Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+1441
View File
File diff suppressed because it is too large Load Diff
+697
View File
@@ -0,0 +1,697 @@
//
// 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_DECODE_VIEW_HPP
#define BOOST_URL_DECODE_VIEW_HPP
#include <boost/url/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/encoding_opts.hpp>
#include <boost/url/pct_string_view.hpp>
#include <type_traits>
#include <iterator>
#include <iosfwd>
namespace boost {
namespace urls {
//------------------------------------------------
#ifndef BOOST_URL_DOCS
class decode_view;
namespace detail {
// unchecked
template<class... Args>
decode_view
make_decode_view(
Args&&... args) noexcept;
} // detail
#endif
//------------------------------------------------
/** A reference to a valid, percent-encoded string
These views reference strings in parts of URLs
or other components that are percent-encoded.
The special characters (those not in the
allowed character set) are stored as three
character escapes that consist of a percent
sign ('%%') followed by a two-digit hexadecimal
number of the corresponding unescaped character
code, which may be part of a UTF-8 code point
depending on the context.
The view refers to the original character
buffer and only decodes escaped sequences when
needed. In particular these operations perform
percent-decoding automatically without the
need to allocate memory:
@li Iteration of the string
@li Accessing the encoded character buffer
@li Comparison to encoded or plain strings
These objects can only be constructed from
strings that have a valid percent-encoding,
otherwise construction fails. The caller is
responsible for ensuring that the lifetime
of the character buffer from which the view
is constructed extends unmodified until the
view is no longer accessed.
@par Operators
The following operators are supported between
@ref decode_view and any object that is convertible
to `core::string_view`
@code
bool operator==( decode_view, decode_view ) noexcept;
bool operator!=( decode_view, decode_view ) noexcept;
bool operator<=( decode_view, decode_view ) noexcept;
bool operator< ( decode_view, decode_view ) noexcept;
bool operator> ( decode_view, decode_view ) noexcept;
bool operator>=( decode_view, decode_view ) noexcept;
@endcode
*/
class decode_view
{
char const* p_ = nullptr;
std::size_t n_ = 0;
std::size_t dn_ = 0;
bool space_as_plus_ = true;
#ifndef BOOST_URL_DOCS
template<class... Args>
friend
decode_view
detail::make_decode_view(
Args&&... args) noexcept;
#endif
// unchecked
BOOST_URL_DECL
explicit
decode_view(
core::string_view s,
std::size_t n,
encoding_opts opt) noexcept;
public:
/** The value type
*/
using value_type = char;
/** The reference type
*/
using reference = char;
/// @copydoc reference
using const_reference = char;
/** The unsigned integer type
*/
using size_type = std::size_t;
/** The signed integer type
*/
using difference_type = std::ptrdiff_t;
/** An iterator of constant, decoded characters.
This iterator is used to access the encoded
string as a bidirectional range of characters
with percent-decoding applied. Escape sequences
are not decoded until the iterator is
dereferenced.
*/
#ifdef BOOST_URL_DOCS
using iterator = __see_below__;
#else
class iterator;
#endif
/// @copydoc iterator
using const_iterator = iterator;
//--------------------------------------------
//
// Special Members
//
//--------------------------------------------
/** Constructor
Default-constructed views represent
empty strings.
@par Example
@code
decode_view ds;
@endcode
@par Postconditions
@code
this->empty() == true
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
decode_view() noexcept = default;
/** Constructor
This constructs a view from the character
buffer `s`, which must remain valid and
unmodified until the view is no longer
accessed.
@par Example
@code
decode_view ds( "Program%20Files" );
@endcode
@par Postconditions
@code
this->encoded() == s
@endcode
@par Complexity
Linear in `s.size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
The string contains an invalid percent encoding.
@param s A percent-encoded string that has
already been validated.
@param opt The options for decoding. If
this parameter is omitted, the default
options are used.
*/
explicit
decode_view(
pct_string_view s,
encoding_opts opt = {}) noexcept
: decode_view(
detail::to_sv(s),
s.decoded_size(),
opt)
{
}
//--------------------------------------------
//
// Observers
//
//--------------------------------------------
/** Return true if the string is empty
@par Example
@code
assert( decode_view( "" ).empty() );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
bool
empty() const noexcept
{
return n_ == 0;
}
/** Return the number of decoded characters
@par Example
@code
assert( decode_view( "Program%20Files" ).size() == 13 );
@endcode
@par Effects
@code
return std::distance( this->begin(), this->end() );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
size_type
size() const noexcept
{
return dn_;
}
/** Return an iterator to the beginning
@par Example
@code
auto it = this->begin();
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
iterator
begin() const noexcept;
/** Return an iterator to the end
@par Example
@code
auto it = this->end();
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
iterator
end() const noexcept;
/** Return the first character
@par Example
@code
assert( decode_view( "Program%20Files" ).front() == 'P' );
@endcode
@par Preconditions
@code
not this->empty()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
reference
front() const noexcept;
/** Return the last character
@par Example
@code
assert( decode_view( "Program%20Files" ).back() == 's' );
@endcode
@par Preconditions
@code
not this->empty()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
reference
back() const noexcept;
/** Checks if the string begins with the given prefix
@par Example
@code
assert( decode_view( "Program%20Files" ).starts_with("Program") );
@endcode
@par Complexity
Linear.
@par Exception Safety
Throws nothing.
*/
BOOST_URL_DECL
bool
starts_with( core::string_view s ) const noexcept;
/** Checks if the string ends with the given prefix
@par Example
@code
assert( decode_view( "Program%20Files" ).ends_with("Files") );
@endcode
@par Complexity
Linear.
@par Exception Safety
Throws nothing.
*/
BOOST_URL_DECL
bool
ends_with( core::string_view s ) const noexcept;
/** Checks if the string begins with the given prefix
@par Example
@code
assert( decode_view( "Program%20Files" ).starts_with('P') );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
BOOST_URL_DECL
bool
starts_with( char ch ) const noexcept;
/** Checks if the string ends with the given prefix
@par Example
@code
assert( decode_view( "Program%20Files" ).ends_with('s') );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
BOOST_URL_DECL
bool
ends_with( char ch ) const noexcept;
/** Finds the first occurrence of character in this view
@par Complexity
Linear.
@par Exception Safety
Throws nothing.
*/
BOOST_URL_DECL
const_iterator
find( char ch ) const noexcept;
/** Finds the first occurrence of character in this view
@par Complexity
Linear.
@par Exception Safety
Throws nothing.
*/
BOOST_URL_DECL
const_iterator
rfind( char ch ) const noexcept;
/** Remove the first characters
@par Example
@code
decode_view d( "Program%20Files" );
d.remove_prefix( 8 );
assert( d == "Files" );
@endcode
@par Preconditions
@code
not this->empty()
@endcode
@par Complexity
Linear.
*/
BOOST_URL_DECL
void
remove_prefix( size_type n );
/** Remove the last characters
@par Example
@code
decode_view d( "Program%20Files" );
d.remove_prefix( 6 );
assert( d == "Program" );
@endcode
@par Preconditions
@code
not this->empty()
@endcode
@par Complexity
Linear.
*/
BOOST_URL_DECL
void
remove_suffix( size_type n );
/** Return the decoding options
*/
encoding_opts
options() const noexcept
{
encoding_opts opt;
opt.space_as_plus = space_as_plus_;
return opt;
}
//--------------------------------------------
//
// Comparison
//
//--------------------------------------------
/** Return the result of comparing to another string
The length of the sequences to compare is the smaller of
`size()` and `other.size()`.
The function compares the two strings as if by calling
`char_traits<char>::compare(to_string().data(), v.data(), rlen)`.
This means the comparison is performed with
percent-decoding applied to the current string.
@param other string to compare
@return Negative value if this string is less than the other
character sequence, zero if the both character sequences are
equal, positive value if this string is greater than the other
character sequence
*/
BOOST_URL_DECL
int
compare(core::string_view other) const noexcept;
/** Return the result of comparing to another string
The length of the sequences to compare is the smaller of
`size()` and `other.size()`.
The function compares the two strings as if by calling
`char_traits<char>::compare(to_string().data(), v.to_string().data(), rlen)`.
This means the comparison is performed with
percent-decoding applied to the current string.
@param other string to compare
@return Negative value if this string is less than the other
character sequence, zero if the both character sequences are
equal, positive value if this string is greater than the other
character sequence
*/
BOOST_URL_DECL
int
compare(decode_view other) const noexcept;
//--------------------------------------------
// relational operators
#ifndef BOOST_URL_DOCS
private:
template<class S0, class S1>
using is_match = std::integral_constant<bool,
// both decode_view or convertible to core::string_view
(
std::is_same<typename std::decay<S0>::type, decode_view>::value ||
std::is_convertible<S0, core::string_view>::value) &&
(
std::is_same<typename std::decay<S1>::type, decode_view>::value ||
std::is_convertible<S1, core::string_view>::value) &&
// not both are convertible to string view
(
!std::is_convertible<S0, core::string_view>::value ||
!std::is_convertible<S1, core::string_view>::value)>;
static
int
decode_compare(decode_view s0, decode_view s1) noexcept
{
return s0.compare(s1);
}
template <class S>
static
int
decode_compare(decode_view s0, S const& s1) noexcept
{
return s0.compare(s1);
}
template <class S>
static
int
decode_compare(S const& s0, decode_view s1) noexcept
{
return -s1.compare(s0);
}
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 decode_compare(s0, s1) == 0;
}
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 decode_compare(s0, s1) != 0;
}
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 decode_compare(s0, s1) < 0;
}
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 decode_compare(s0, s1) <= 0;
}
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 decode_compare(s0, s1) > 0;
}
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 decode_compare(s0, s1) >= 0;
}
#endif
// hidden friend
friend
std::ostream&
operator<<(
std::ostream& os,
decode_view const& s)
{
// hidden friend
s.write(os);
return os;
}
private:
BOOST_URL_DECL
void
write(std::ostream& os) const;
};
/** Format the string with percent-decoding applied to the output stream
This function serializes the decoded view
to the output stream.
@return A reference to the output stream, for chaining
@param os The output stream to write to
@param s The decoded view to write
*/
inline
std::ostream&
operator<<(
std::ostream& os,
decode_view const& s);
//------------------------------------------------
inline
decode_view
pct_string_view::operator*() const noexcept
{
return decode_view(*this);
}
#ifndef BOOST_URL_DOCS
namespace detail {
template<class... Args>
decode_view
make_decode_view(
Args&&... args) noexcept
{
return decode_view(
std::forward<Args>(args)...);
}
} // detail
#endif
//------------------------------------------------
} // urls
} // boost
#include <boost/url/impl/decode_view.hpp>
#endif
+426
View File
@@ -0,0 +1,426 @@
//
// 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_DETAIL_ANY_PARAMS_ITER_HPP
#define BOOST_URL_DETAIL_ANY_PARAMS_ITER_HPP
#include <boost/url/param.hpp>
#include <boost/url/pct_string_view.hpp>
#include <boost/static_assert.hpp>
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace boost {
namespace urls {
namespace detail {
//------------------------------------------------
//
// any_params_iter
//
//------------------------------------------------
/* An iterator to a type-erased,
possibly encoded sequence of
query params_ref.
*/
struct BOOST_SYMBOL_VISIBLE
any_params_iter
{
protected:
any_params_iter(
bool empty_,
core::string_view s0_ = {},
core::string_view s1_ = {}) noexcept
: s0(s0_)
, s1(s1_)
, empty(empty_)
{
}
public:
// these are adjusted
// when self-intersecting
core::string_view s0;
core::string_view s1;
// True if the sequence is empty
bool empty = false;
BOOST_URL_DECL
virtual
~any_params_iter() noexcept = 0;
// Rewind the iterator to the beginning
virtual
void
rewind() noexcept = 0;
// Measure and increment current element
// element.
// Returns false on end of range.
// n is increased by encoded size.
// Can throw on bad percent-escape
virtual
bool
measure(std::size_t& n) = 0;
// Copy and increment the current
// element. encoding is performed
// if needed.
virtual
void
copy(
char*& dest,
char const* end) noexcept = 0;
};
//------------------------------------------------
//
// query_iter
//
//------------------------------------------------
// A string of plain query params
struct BOOST_SYMBOL_VISIBLE
query_iter
: any_params_iter
{
// ne = never empty
BOOST_URL_DECL
explicit
query_iter(
core::string_view s,
bool ne = false) noexcept;
private:
core::string_view s_;
std::size_t n_;
char const* p_;
bool at_end_;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
void increment() noexcept;
};
//------------------------------------------------
//
// param_iter
//
//------------------------------------------------
// A 1-param range allowing
// self-intersection
struct BOOST_SYMBOL_VISIBLE
param_iter
: any_params_iter
{
explicit
param_iter(
param_view const&) noexcept;
private:
bool has_value_;
bool at_end_ = false;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
//
// params_iter_base
//
//------------------------------------------------
struct params_iter_base
{
protected:
// return encoded size
BOOST_URL_DECL
static
void
measure_impl(
std::size_t& n,
param_view const& p) noexcept;
// encode to dest
BOOST_URL_DECL
static
void
copy_impl(
char*& dest,
char const* end,
param_view const& v) noexcept;
};
//------------------------------------------------
// A range of plain query params_ref
template<class FwdIt>
struct params_iter
: any_params_iter
, private params_iter_base
{
BOOST_STATIC_ASSERT(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value);
params_iter(
FwdIt first,
FwdIt last) noexcept
: any_params_iter(
first == last)
, it0_(first)
, it_(first)
, end_(last)
{
}
private:
FwdIt it0_;
FwdIt it_;
FwdIt end_;
void
rewind() noexcept override
{
it_ = it0_;
}
bool
measure(
std::size_t& n) noexcept override
{
if(it_ == end_)
return false;
measure_impl(n,
param_view(*it_++));
return true;
}
void
copy(
char*& dest,
char const* end) noexcept override
{
copy_impl(dest, end,
param_view(*it_++));
}
};
//------------------------------------------------
//
// param_encoded_iter
//
//------------------------------------------------
// A 1-param encoded range
// allowing self-intersection
struct BOOST_SYMBOL_VISIBLE
param_encoded_iter
: any_params_iter
{
explicit
param_encoded_iter(
param_pct_view const&) noexcept;
private:
bool has_value_;
bool at_end_ = false;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
//
// params_encoded_iter
//
//------------------------------------------------
// Validating and copying from
// a string of encoded params
struct params_encoded_iter_base
{
protected:
BOOST_URL_DECL
static
void
measure_impl(
std::size_t& n,
param_view const& v) noexcept;
BOOST_URL_DECL
static
void
copy_impl(
char*& dest,
char const* end,
param_view const& v) noexcept;
};
//------------------------------------------------
// A range of encoded query params_ref
template<class FwdIt>
struct params_encoded_iter
: any_params_iter
, private params_encoded_iter_base
{
BOOST_STATIC_ASSERT(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value);
params_encoded_iter(
FwdIt first,
FwdIt last) noexcept
: any_params_iter(
first == last)
, it0_(first)
, it_(first)
, end_(last)
{
}
private:
FwdIt it0_;
FwdIt it_;
FwdIt end_;
void
rewind() noexcept override
{
it_ = it0_;
}
bool
measure(
std::size_t& n) override
{
if(it_ == end_)
return false;
// throw on invalid input
measure_impl(n,
param_pct_view(
param_view(*it_++)));
return true;
}
void
copy(
char*& dest,
char const* end
) noexcept override
{
copy_impl(dest, end,
param_view(*it_++));
}
};
//------------------------------------------------
//
// param_value_iter
//
//------------------------------------------------
// An iterator which outputs
// one value on an existing key
struct param_value_iter
: any_params_iter
{
param_value_iter(
std::size_t nk,
core::string_view const& value,
bool has_value) noexcept
: any_params_iter(
false,
value)
, nk_(nk)
, has_value_(has_value)
{
}
private:
std::size_t nk_ = 0;
bool has_value_ = false;
bool at_end_ = false;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
//
// param_encoded_value_iter
//
//------------------------------------------------
// An iterator which outputs one
// encoded value on an existing key
struct param_encoded_value_iter
: any_params_iter
{
param_encoded_value_iter(
std::size_t nk,
pct_string_view const& value,
bool has_value) noexcept
: any_params_iter(
false,
value)
, nk_(nk)
, has_value_(has_value)
{
}
private:
std::size_t nk_ = 0;
bool has_value_ = false;
bool at_end_ = false;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
template<class FwdIt>
params_iter<FwdIt>
make_params_iter(
FwdIt first, FwdIt last)
{
return params_iter<
FwdIt>(first, last);
}
template<class FwdIt>
params_encoded_iter<FwdIt>
make_params_encoded_iter(
FwdIt first, FwdIt last)
{
return params_encoded_iter<
FwdIt>(first, last);
}
} // detail
} // urls
} // boost
#endif
+327
View File
@@ -0,0 +1,327 @@
//
// 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_DETAIL_ANY_SEGMENTS_ITER_HPP
#define BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP
#include <boost/url/pct_string_view.hpp>
#include <boost/static_assert.hpp>
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace boost {
namespace urls {
namespace detail {
struct BOOST_SYMBOL_VISIBLE
any_segments_iter
{
protected:
explicit
any_segments_iter(
core::string_view s_ = {}) noexcept
: s(s_)
{
}
virtual ~any_segments_iter() = default;
public:
// this is adjusted
// when self-intersecting
core::string_view s;
// the first segment,
// to handle special cases
core::string_view front;
// quick number of segments
// 0 = zero
// 1 = one
// 2 = two, or more
int fast_nseg = 0;
// whether the segments should encode colons
// when we measure and copy. the calling
// function uses this for the first
// segment in some cases, such as:
// "x:y:z" -> remove_scheme -> "y%3Az"
// as "y:z" would no longer represent a path
bool encode_colons = false;
// Rewind the iterator to the beginning
virtual void rewind() noexcept = 0;
// Measure and increment the current
// element. n is increased by the
// encoded size. Returns false on
// end of range.
virtual bool measure(std::size_t& n) = 0;
// Copy and increment the current
// element, encoding as needed.
virtual void copy(char*& dest,
char const* end) noexcept = 0;
};
//------------------------------------------------
//
// segment_iter
//
//------------------------------------------------
// A 1-segment range
// allowing self-intersection
struct BOOST_SYMBOL_VISIBLE
segment_iter
: any_segments_iter
{
virtual ~segment_iter() = default;
explicit
segment_iter(
core::string_view s) noexcept;
private:
bool at_end_ = false;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
//
// segments_iter
//
//------------------------------------------------
struct segments_iter_base
{
protected:
BOOST_URL_DECL static void
measure_impl(std::size_t&,
core::string_view, bool) noexcept;
BOOST_URL_DECL static void
copy_impl(char*&, char const*,
core::string_view, bool) noexcept;
};
// iterates segments in a
// plain segment range
template<class FwdIt>
struct segments_iter
: any_segments_iter
, segments_iter_base
{
BOOST_STATIC_ASSERT(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value);
segments_iter(
FwdIt first,
FwdIt last) noexcept
: it_(first)
, it0_(first)
, end_(last)
{
if(first != last)
{
front = *first;
auto it = first;
if(++it == last)
fast_nseg = 1;
else
fast_nseg = 2;
}
else
{
fast_nseg = 0;
}
}
private:
FwdIt it_;
FwdIt it0_;
FwdIt end_;
void
rewind() noexcept override
{
it_ = it0_;
}
bool
measure(
std::size_t& n) noexcept override
{
if(it_ == end_)
return false;
measure_impl(n,
detail::to_sv(*it_),
encode_colons);
++it_;
return true;
}
void
copy(
char*& dest,
char const* end) noexcept override
{
copy_impl(dest, end,
detail::to_sv(*it_++),
encode_colons);
}
};
//------------------------------------------------
//
// segment_encoded_iter
//
//------------------------------------------------
// A 1-segment range
// allowing self-intersection
struct BOOST_SYMBOL_VISIBLE
segment_encoded_iter
: any_segments_iter
{
virtual ~segment_encoded_iter() = default;
explicit
segment_encoded_iter(
pct_string_view const& s) noexcept;
private:
bool at_end_ = false;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
//
// segments_encoded_iter
//
//------------------------------------------------
// Validating and copying from
// a string of encoded segments
struct segments_encoded_iter_base
{
protected:
BOOST_URL_DECL static void
measure_impl(std::size_t&,
core::string_view, bool) noexcept;
BOOST_URL_DECL static void
copy_impl(char*&, char const*,
core::string_view, bool) noexcept;
};
// iterates segments in an
// encoded segment range
template<class FwdIt>
struct segments_encoded_iter
: public any_segments_iter
, public segments_encoded_iter_base
{
BOOST_STATIC_ASSERT(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value);
segments_encoded_iter(
FwdIt first,
FwdIt last)
: it_(first)
, it0_(first)
, end_(last)
{
if(it_ != end_)
{
// throw on invalid input
front = pct_string_view(
detail::to_sv(*first));
auto it = first;
if(++it == last)
fast_nseg = 1;
else
fast_nseg = 2;
}
else
{
fast_nseg = 0;
}
}
private:
FwdIt it_;
FwdIt it0_;
FwdIt end_;
void
rewind() noexcept override
{
it_ = it0_;
}
bool
measure(
std::size_t& n) override
{
if(it_ == end_)
return false;
// throw on invalid input
measure_impl(n,
pct_string_view(
detail::to_sv(*it_++)),
encode_colons);
return true;
}
void
copy(
char*& dest,
char const* end) noexcept override
{
copy_impl(dest, end,
detail::to_sv(*it_++),
encode_colons);
}
};
//------------------------------------------------
template<class FwdIt>
segments_iter<FwdIt>
make_segments_iter(
FwdIt first, FwdIt last)
{
return segments_iter<
FwdIt>(first, last);
}
template<class FwdIt>
segments_encoded_iter<FwdIt>
make_segments_encoded_iter(
FwdIt first, FwdIt last)
{
return segments_encoded_iter<
FwdIt>(first, last);
}
} // detail
} // urls
} // boost
#endif
+144
View File
@@ -0,0 +1,144 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_DETAIL_CONFIG_HPP
#define BOOST_URL_DETAIL_CONFIG_HPP
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT != 8
# error unsupported platform
#endif
// Determine if compiling as a dynamic library
#if (defined(BOOST_URL_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_URL_STATIC_LINK)
# define BOOST_URL_BUILD_DLL
#endif
// Set visibility flags
#if !defined(BOOST_URL_BUILD_DLL)
# define BOOST_URL_DECL /* static library */
#elif defined(BOOST_URL_SOURCE)
# define BOOST_URL_DECL BOOST_SYMBOL_EXPORT /* source: dllexport/visibility */
#else
# define BOOST_URL_DECL BOOST_SYMBOL_IMPORT /* header: dllimport */
#endif
// Set up auto-linker
# if !defined(BOOST_URL_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_URL_NO_LIB)
# define BOOST_LIB_NAME boost_url
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_URL_DYN_LINK)
# define BOOST_DYN_LINK
# endif
# include <boost/config/auto_link.hpp>
# endif
// Set up SSE2
#if ! defined(BOOST_URL_NO_SSE2) && \
! defined(BOOST_URL_USE_SSE2)
# if (defined(_M_IX86) && _M_IX86_FP == 2) || \
defined(_M_X64) || defined(__SSE2__)
# define BOOST_URL_USE_SSE2
# endif
#endif
// constexpr
#if BOOST_WORKAROUND( BOOST_GCC_VERSION, <= 72000 ) || \
BOOST_WORKAROUND( BOOST_CLANG_VERSION, <= 35000 )
# define BOOST_URL_CONSTEXPR
#else
# define BOOST_URL_CONSTEXPR constexpr
#endif
// Add source location to error codes
#ifdef BOOST_URL_NO_SOURCE_LOCATION
# define BOOST_URL_ERR(ev) (::boost::system::error_code(ev))
# define BOOST_URL_RETURN_EC(ev) return (ev)
# define BOOST_URL_POS ::boost::source_location()
#else
# define BOOST_URL_ERR(ev) (::boost::system::error_code( (ev), [] { \
static constexpr auto loc((BOOST_CURRENT_LOCATION)); \
return &loc; }()))
# define BOOST_URL_RETURN_EC(ev) \
static constexpr auto loc ## __LINE__((BOOST_CURRENT_LOCATION)); \
return ::boost::system::error_code((ev), &loc ## __LINE__)
# define BOOST_URL_POS (BOOST_CURRENT_LOCATION)
#endif
// String token parameters
#ifndef BOOST_URL_STRTOK_TPARAM
#define BOOST_URL_STRTOK_TPARAM class StringToken = string_token::return_string
#endif
#ifndef BOOST_URL_STRTOK_RETURN
#define BOOST_URL_STRTOK_RETURN typename StringToken::result_type
#endif
#ifndef BOOST_URL_STRTOK_ARG
#define BOOST_URL_STRTOK_ARG(name) StringToken&& token = {}
#endif
// Move
#if BOOST_WORKAROUND( BOOST_GCC_VERSION, < 80000 ) || \
BOOST_WORKAROUND( BOOST_CLANG_VERSION, < 30900 )
#define BOOST_URL_RETURN(x) return std::move((x))
#else
#define BOOST_URL_RETURN(x) return (x)
#endif
// Limit tests
#ifndef BOOST_URL_MAX_SIZE
// we leave room for a null,
// and still fit in size_t
#define BOOST_URL_MAX_SIZE ((std::size_t(-1))-1)
#endif
// noinline attribute
#ifdef BOOST_GCC
#define BOOST_URL_NO_INLINE [[gnu::noinline]]
#else
#define BOOST_URL_NO_INLINE
#endif
// libstdcxx copy-on-write strings
#ifndef BOOST_URL_COW_STRINGS
#if defined(BOOST_LIBSTDCXX_VERSION) && (BOOST_LIBSTDCXX_VERSION < 60000 || (defined(_GLIBCXX_USE_CXX11_ABI) && _GLIBCXX_USE_CXX11_ABI == 0))
#define BOOST_URL_COW_STRINGS
#endif
#endif
// detect 32/64 bit
#if UINTPTR_MAX == UINT64_MAX
# define BOOST_URL_ARCH 64
#elif UINTPTR_MAX == UINT32_MAX
# define BOOST_URL_ARCH 32
#else
# error Unknown or unsupported architecture, please open an issue
#endif
// deprecated attribute
#if defined(BOOST_MSVC) || defined(BOOST_URL_DOCS)
#define BOOST_URL_DEPRECATED(msg)
#else
#define BOOST_URL_DEPRECATED(msg) BOOST_DEPRECATED(msg)
#endif
// avoid Boost.TypeTraits for these traits
namespace boost {
namespace urls {
template<class...> struct make_void { typedef void type; };
template<class... Ts> using void_t = typename make_void<Ts...>::type;
} // urls
} // boost
#endif
+44
View File
@@ -0,0 +1,44 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_DETAIL_DECODE_HPP
#define BOOST_URL_DETAIL_DECODE_HPP
#include <boost/url/encoding_opts.hpp>
#include <boost/core/detail/string_view.hpp>
#include <cstdlib>
namespace boost {
namespace urls {
namespace detail {
BOOST_URL_DECL
char
decode_one(
char const* it) noexcept;
BOOST_URL_DECL
std::size_t
decode_bytes_unsafe(
core::string_view s) noexcept;
BOOST_URL_DECL
std::size_t
decode_unsafe(
char* dest,
char const* end,
core::string_view s,
encoding_opts opt = {}) noexcept;
} // detail
} // urls
} // boost
#endif
+205
View File
@@ -0,0 +1,205 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_DETAIL_ENCODE_HPP
#define BOOST_URL_DETAIL_ENCODE_HPP
#include <boost/url/encoding_opts.hpp>
#include <boost/url/pct_string_view.hpp>
#include <boost/url/grammar/hexdig_chars.hpp>
#include <boost/core/ignore_unused.hpp>
#include <cstdlib>
namespace boost {
namespace urls {
namespace detail {
constexpr
char const* const hexdigs[] = {
"0123456789ABCDEF",
"0123456789abcdef" };
//------------------------------------------------
// re-encode is to percent-encode a
// string that can already contain
// escapes. Characters not in the
// unreserved set are escaped, and
// escapes are passed through unchanged.
//
template<class CharSet>
std::size_t
re_encoded_size_unsafe(
core::string_view s,
CharSet const& unreserved,
encoding_opts opt) noexcept
{
std::size_t n = 0;
auto const end = s.end();
auto it = s.begin();
if(opt.space_as_plus)
{
while(it != end)
{
if(*it != '%')
{
if( unreserved(*it)
|| *it == ' ')
n += 1;
else
n += 3;
++it;
}
else
{
BOOST_ASSERT(end - it >= 3);
BOOST_ASSERT(
grammar::hexdig_value(
it[1]) >= 0);
BOOST_ASSERT(
grammar::hexdig_value(
it[2]) >= 0);
n += 3;
it += 3;
}
}
}
else
{
while(it != end)
{
if(*it != '%')
{
if(unreserved(*it))
n += 1;
else
n += 3;
++it;
}
else
{
BOOST_ASSERT(end - it >= 3);
BOOST_ASSERT(
grammar::hexdig_value(
it[1]) >= 0);
BOOST_ASSERT(
grammar::hexdig_value(
it[2]) >= 0);
n += 3;
it += 3;
}
}
}
return n;
}
// unchecked
// returns decoded size
template<class CharSet>
std::size_t
re_encode_unsafe(
char*& dest_,
char const* const end,
core::string_view s,
CharSet const& unreserved,
encoding_opts opt) noexcept
{
char const* const hex =
detail::hexdigs[opt.lower_case];
auto const encode = [end, hex](
char*& dest,
unsigned char c) noexcept
{
ignore_unused(end);
*dest++ = '%';
BOOST_ASSERT(dest != end);
*dest++ = hex[c>>4];
BOOST_ASSERT(dest != end);
*dest++ = hex[c&0xf];
};
ignore_unused(end);
auto dest = dest_;
auto const dest0 = dest;
auto const last = s.end();
std::size_t dn = 0;
auto it = s.begin();
if(opt.space_as_plus)
{
while(it != last)
{
BOOST_ASSERT(dest != end);
if(*it != '%')
{
if(*it == ' ')
{
*dest++ = '+';
}
else if(unreserved(*it))
{
*dest++ = *it;
}
else
{
encode(dest, *it);
dn += 2;
}
++it;
}
else
{
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
dn += 2;
}
}
}
else
{
while(it != last)
{
BOOST_ASSERT(dest != end);
if(*it != '%')
{
if(unreserved(*it))
{
*dest++ = *it;
}
else
{
encode(dest, *it);
dn += 2;
}
++it;
}
else
{
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
BOOST_ASSERT(dest != end);
*dest++ = *it++;
dn += 2;
}
}
}
dest_ = dest;
return dest - dest0 - dn;
}
} // detail
} // urls
} // boost
#endif
+48
View File
@@ -0,0 +1,48 @@
//
// 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_DETAIL_EXCEPT_HPP
#define BOOST_URL_DETAIL_EXCEPT_HPP
#include <boost/url/error_types.hpp>
#include <boost/assert/source_location.hpp>
namespace boost {
namespace urls {
namespace detail {
BOOST_URL_DECL void BOOST_NORETURN
throw_system_error(
system::error_code const& ec,
source_location const& loc =
BOOST_URL_POS);
BOOST_URL_DECL void BOOST_NORETURN
throw_errc(
boost::system::errc::errc_t ev,
source_location const& loc =
BOOST_URL_POS);
//-----
BOOST_URL_DECL void BOOST_NORETURN
throw_invalid_argument(
source_location const& loc =
BOOST_URL_POS);
BOOST_URL_DECL void BOOST_NORETURN
throw_length_error(
source_location const& loc =
BOOST_URL_POS);
} // detail
} // urls
} // boost
#endif
+340
View File
@@ -0,0 +1,340 @@
//
// 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_DETAIL_FORMAT_ARGS_HPP
#define BOOST_URL_DETAIL_FORMAT_ARGS_HPP
#include <boost/url/detail/encode.hpp>
#include <boost/url/grammar/lut_chars.hpp>
#include <boost/core/ignore_unused.hpp>
#include <array>
// This file implements functions and classes to
// type-erase format arguments.
namespace boost {
namespace urls {
namespace detail {
// state of the format string. It basically keeps
// track of where we are in the format string.
class format_parse_context
{
char const* begin_;
char const* end_;
std::size_t arg_id_ = 0;
public:
constexpr
format_parse_context(
char const* first,
char const* last,
std::size_t arg_id = 0)
: begin_( first )
, end_( last )
, arg_id_( arg_id )
{}
constexpr
format_parse_context(
core::string_view fmt,
std::size_t arg_id = 0)
: format_parse_context(
fmt.data(),
fmt.data() + fmt.size(),
arg_id )
{}
constexpr
char const*
begin() const noexcept
{
return begin_;
}
constexpr
char const*
end() const noexcept
{
return end_;
}
BOOST_CXX14_CONSTEXPR
void
advance_to( char const* it )
{
begin_ = it;
}
std::size_t
next_arg_id()
{
return arg_id_++;
}
};
// State of the destination string
class format_context;
class measure_context;
struct ignore_format {};
template <class T>
struct named_arg
{
core::string_view name;
T const& value;
named_arg(core::string_view n, T const& v)
: name(n)
, value(v)
{}
};
// A type erased format argument
class format_arg
{
void const* arg_;
void (*measure_)(
format_parse_context&,
measure_context&,
grammar::lut_chars const&,
void const* );
void (*fmt_)(
format_parse_context&,
format_context&,
grammar::lut_chars const&,
void const* );
core::string_view name_;
std::size_t value_ = 0;
bool ignore_ = false;
template <class A>
static
void
measure_impl(
format_parse_context& pctx,
measure_context& mctx,
grammar::lut_chars const& cs,
void const* a );
template <class A>
static
void
format_impl(
format_parse_context& pctx,
format_context& fctx,
grammar::lut_chars const& cs,
void const* a );
public:
template<class A>
format_arg( A&& a );
template<class A>
format_arg( named_arg<A>&& a );
template<class A>
format_arg( core::string_view name, A&& a );
format_arg()
: format_arg(ignore_format{})
{}
explicit
operator bool() const noexcept
{
return !ignore_;
}
void
measure(
format_parse_context& pctx,
measure_context& mctx,
grammar::lut_chars const& cs)
{
measure_( pctx, mctx, cs, arg_ );
}
void
format(
format_parse_context& pctx,
format_context& fctx,
grammar::lut_chars const& cs )
{
fmt_( pctx, fctx, cs, arg_ );
}
core::string_view
name() const
{
return name_;
}
std::size_t
value() const
{
return value_;
}
};
// create temp stack storage for type erased args
template< class... Args >
std::array<format_arg, sizeof...(Args)>
make_format_args( Args&&... args )
{
return {{ std::forward<Args>(args)... }};
}
// reference to an array of format_args
class format_args
{
format_arg const* p_{nullptr};
std::size_t n_{0};
public:
format_args(
detail::format_arg const* first,
detail::format_arg const* last ) noexcept
: p_(first)
, n_(static_cast<std::size_t>(last - first))
{}
template < std::size_t N >
format_args( std::array<format_arg, N> const& store ) noexcept
: p_(store.data())
, n_(store.size())
{}
format_arg
get( std::size_t i ) const noexcept
{
if (i < n_)
return p_[i];
return {};
}
format_arg
get( core::string_view name ) const noexcept
{
for (std::size_t i = 0; i < n_; ++i)
{
if (p_[i].name() == name)
return p_[i];
}
return {};
}
};
// define the format_context after format_args
class format_context
{
format_args args_;
char* out_;
public:
format_context(
char* out,
format_args args )
: args_( args )
, out_( out )
{}
format_args
args() const noexcept
{
return args_;
}
format_arg
arg( std::size_t id ) const noexcept
{
return args_.get( id );
}
format_arg
arg( core::string_view name ) const noexcept
{
return args_.get( name );
}
char*
out()
{
return out_;
}
void
advance_to( char* it )
{
out_ = it;
}
};
// define the measure_context after format_args
class measure_context
{
format_args args_;
std::size_t out_;
public:
measure_context(
format_args args )
: measure_context(0, args)
{}
measure_context(
std::size_t out,
format_args args )
: args_( args )
, out_( out )
{}
format_args
args() const noexcept
{
return args_;
}
format_arg
arg( std::size_t id ) const noexcept
{
return args_.get( id );
}
format_arg
arg( core::string_view name ) const noexcept
{
return args_.get( name );
}
std::size_t
out()
{
return out_;
}
void
advance_to( std::size_t n )
{
out_ = n;
}
};
// fwd declare the formatter
template <class T, class = void>
struct formatter;
} // detail
} // url
} // boost
#include <boost/url/detail/impl/format_args.hpp>
#endif
+416
View File
@@ -0,0 +1,416 @@
//
// 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_DETAIL_IMPL_FORMAT_ARGS_HPP
#define BOOST_URL_DETAIL_IMPL_FORMAT_ARGS_HPP
namespace boost {
namespace urls {
namespace detail {
template<
class A,
typename std::enable_if<
!std::is_integral<
typename std::decay<A>::type>::value,
int>::type = 0>
std::size_t
get_uvalue( A&& )
{
return 0;
}
template<
class A,
typename std::enable_if<
std::is_integral<
typename std::decay<A>::type>::value &&
std::is_signed<
typename std::decay<A>::type>::value,
int>::type = 0>
std::size_t
get_uvalue( A&& a )
{
if (a > 0)
return static_cast<std::size_t>(a);
return 0;
}
template<
class A,
typename std::enable_if<
std::is_integral<
typename std::decay<A>::type>::value &&
std::is_unsigned<
typename std::decay<A>::type>::value,
int>::type = 0>
std::size_t
get_uvalue( A&& a )
{
return static_cast<std::size_t>(a);
}
BOOST_URL_DECL
std::size_t
get_uvalue( core::string_view a );
BOOST_URL_DECL
std::size_t
get_uvalue( char a );
template<class A>
format_arg::
format_arg( A&& a )
: arg_( &a )
, measure_( &measure_impl<A> )
, fmt_( &format_impl<A> )
, value_( get_uvalue(std::forward<A>(a) ))
, ignore_( std::is_same<A, ignore_format>::value )
{}
template<class A>
format_arg::
format_arg( named_arg<A>&& a )
: arg_( &a.value )
, measure_( &measure_impl<A> )
, fmt_( &format_impl<A> )
, name_( a.name )
, value_( get_uvalue(a.value))
{}
template<class A>
format_arg::
format_arg( core::string_view name, A&& a )
: arg_( &a )
, measure_( &measure_impl<A> )
, fmt_( &format_impl<A> )
, name_( name )
, value_( get_uvalue(a) )
{}
// define the type-erased implementations that
// depends on everything: the context types,
// formatters, and type erased args
template <class A>
void
format_arg::
measure_impl(
format_parse_context& pctx,
measure_context& mctx,
grammar::lut_chars const& cs,
void const* a )
{
using ref_t = typename std::remove_reference<A>::type;
A const& ref = *static_cast<ref_t*>(
const_cast<void*>( a ) );
formatter<ref_t> f;
pctx.advance_to( f.parse(pctx) );
mctx.advance_to( f.measure( ref, mctx, cs ) );
}
template <class A>
void
format_arg::
format_impl(
format_parse_context& pctx,
format_context& fctx,
grammar::lut_chars const& cs,
void const* a )
{
using ref_t = typename std::remove_reference<A>::type;
A const& ref = *static_cast<ref_t*>(
const_cast<void*>( a ) );
formatter<ref_t> f;
pctx.advance_to( f.parse(pctx) );
fctx.advance_to( f.format( ref, fctx, cs ) );
}
// We point to formatter<ignore_format> where
// the format_arg variant would store monostate
template <>
struct formatter<ignore_format>
{
public:
char const*
parse(format_parse_context& ctx) const
{
return parse_empty_spec(
ctx.begin(), ctx.end());
}
std::size_t
measure(
ignore_format,
measure_context& ctx,
grammar::lut_chars const&) const
{
return ctx.out();
}
char*
format(
ignore_format,
format_context& ctx,
grammar::lut_chars const&) const
{
return ctx.out();
}
// We ignore the modifiers in all replacements
// for now
static
char const*
parse_empty_spec(
char const* it,
char const* end)
{
// [it, end] -> "} suffix"
BOOST_ASSERT(it != end);
ignore_unused(end);
// Should be always empty/valid as an
// implementation detail
BOOST_ASSERT(*it == '}');
/*
if (*it != '}')
urls::detail::throw_invalid_argument();
*/
return it;
}
};
inline
std::size_t
measure_one(
char c,
grammar::lut_chars const& unreserved)
{
// '%' must be reserved
BOOST_ASSERT(! unreserved('%'));
return 1 + !unreserved(c) * 2;
}
inline
void
encode_one(
char*& out,
char c,
grammar::lut_chars const& unreserved)
{
// '%' must be reserved
BOOST_ASSERT(! unreserved('%'));
if(unreserved(c))
{
*out++ = c;
return;
}
*out++ = '%';
*out++ = urls::detail::hexdigs[0][c>>4];
*out++ = urls::detail::hexdigs[0][c&0xf];
}
// get an unsigned value from format_args
BOOST_URL_DECL
void
get_width_from_args(
std::size_t arg_idx,
core::string_view arg_name,
format_args args,
std::size_t& w);
// formatter for string view
template <>
struct formatter<core::string_view>
{
private:
char fill = ' ';
char align = '\0';
std::size_t width = 0;
std::size_t width_idx = std::size_t(-1);
core::string_view width_name;
public:
BOOST_URL_DECL
char const*
parse(format_parse_context& ctx);
BOOST_URL_DECL
std::size_t
measure(
core::string_view str,
measure_context& ctx,
grammar::lut_chars const& cs) const;
BOOST_URL_DECL
char*
format(
core::string_view str,
format_context& ctx,
grammar::lut_chars const& cs) const;
};
// formatter for anything convertible to a
// string view
template <class T>
struct formatter<
T, typename std::enable_if<
std::is_convertible<
T, core::string_view>::value>::type>
{
formatter<core::string_view> impl_;
public:
char const*
parse(format_parse_context& ctx)
{
return impl_.parse(ctx);
}
std::size_t
measure(
core::string_view str,
measure_context& ctx,
grammar::lut_chars const& cs) const
{
return impl_.measure(str, ctx, cs);
}
char*
format(core::string_view str, format_context& ctx, grammar::lut_chars const& cs) const
{
return impl_.format(str, ctx, cs);
}
};
template <>
struct formatter<char>
{
formatter<core::string_view> impl_;
public:
char const*
parse(format_parse_context& ctx)
{
return impl_.parse(ctx);
}
std::size_t
measure(
char c,
measure_context& ctx,
grammar::lut_chars const& cs) const
{
return impl_.measure({&c, 1}, ctx, cs);
}
char*
format(
char c,
format_context& ctx,
grammar::lut_chars const& cs) const
{
return impl_.format({&c, 1}, ctx, cs);
}
};
// formatters for a single integer
class integer_formatter_impl
{
char fill = ' ';
char align = '\0';
char sign = '-';
bool zeros = false;
std::size_t width = 0;
std::size_t width_idx = std::size_t(-1);
core::string_view width_name;
public:
BOOST_URL_DECL
char const*
parse(format_parse_context& ctx);
BOOST_URL_DECL
std::size_t
measure(
unsigned long long int v,
measure_context& ctx,
grammar::lut_chars const& cs) const;
BOOST_URL_DECL
std::size_t
measure(
long long int v,
measure_context& ctx,
grammar::lut_chars const& cs) const;
BOOST_URL_DECL
char*
format(
unsigned long long int v,
format_context& ctx,
grammar::lut_chars const& cs) const;
BOOST_URL_DECL
char*
format(
long long int v,
format_context& ctx,
grammar::lut_chars const& cs) const;
};
template <class T>
struct formatter<
T, typename std::enable_if<
mp11::mp_contains<mp11::mp_list<
short int,
int,
long int,
long long int,
unsigned short int,
unsigned int,
unsigned long int,
unsigned long long int>, T>::value>::type>
{
private:
integer_formatter_impl impl_;
using base_value_type = typename std::conditional<
std::is_unsigned<T>::value,
unsigned long long int,
long long int
>::type;
public:
char const*
parse(format_parse_context& ctx)
{
return impl_.parse(ctx);
}
std::size_t
measure(
T v,
measure_context& ctx,
grammar::lut_chars const& cs) const
{
return impl_.measure(
static_cast<base_value_type>(v), ctx, cs);
}
char*
format(T v, format_context& ctx, grammar::lut_chars const& cs) const
{
return impl_.format(
static_cast<base_value_type>(v), ctx, cs);
}
};
} // detail
} // url
} // boost
#endif
+90
View File
@@ -0,0 +1,90 @@
//
// 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_DETAIL_MOVE_CHARS_HPP
#define BOOST_URL_DETAIL_MOVE_CHARS_HPP
#include <boost/core/detail/string_view.hpp>
#include <boost/assert.hpp>
#include <cstring>
#include <functional>
namespace boost {
namespace urls {
namespace detail {
// Moves characters, and adjusts any passed
// views if they point to any moved characters.
// true if s completely overlapped by buf
inline
bool
is_overlapping(
core::string_view buf,
core::string_view s) noexcept
{
auto const b0 = buf.data();
auto const e0 = b0 + buf.size();
auto const b1 = s.data();
auto const e1 = b1 + s.size();
auto const less_equal =
std::less_equal<char const*>();
if(less_equal(e0, b1))
return false;
if(less_equal(e1, b0))
return false;
// partial overlap is undefined
BOOST_ASSERT(less_equal(e1, e0));
BOOST_ASSERT(less_equal(b0, b1));
return true;
}
inline
void
move_chars_impl(
std::ptrdiff_t,
core::string_view const&) noexcept
{
}
template<class... Sn>
void
move_chars_impl(
std::ptrdiff_t d,
core::string_view const& buf,
core::string_view& s,
Sn&... sn) noexcept
{
if(is_overlapping(buf, s))
s = {s.data() + d, s.size()};
move_chars_impl(d, buf, sn...);
}
template<class... Args>
void
move_chars(
char* dest,
char const* src,
std::size_t n,
Args&... args) noexcept
{
core::string_view buf(src, n);
move_chars_impl(
dest - src,
core::string_view(src, n),
args...);
std::memmove(
dest, src, n);
}
} // detail
} // urls
} // boost
#endif
+179
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_DETAIL_NORMALIZED_HPP
#define BOOST_URL_DETAIL_NORMALIZED_HPP
#include <boost/core/detail/string_view.hpp>
#include <boost/url/segments_encoded_view.hpp>
#include <boost/url/detail/normalize.hpp>
namespace boost {
namespace urls {
namespace detail {
class fnv_1a
{
public:
using digest_type = std::size_t;
#if BOOST_URL_ARCH == 64
static constexpr std::size_t const prime =
static_cast<std::size_t>(0x100000001B3ULL);
static constexpr std::size_t init_hash =
static_cast<std::size_t>(0xcbf29ce484222325ULL);
#else
static constexpr std::size_t const prime =
static_cast<std::size_t>(0x01000193UL);
static constexpr std::size_t init_hash =
static_cast<std::size_t>(0x811C9DC5UL);
#endif
explicit
fnv_1a(std::size_t salt) noexcept
: h_(init_hash + salt)
{
}
void
put(char c) noexcept
{
h_ ^= c;
h_ *= prime;
}
void
put(core::string_view s) noexcept
{
for (char c: s)
{
put(c);
}
}
digest_type
digest() const noexcept
{
return h_;
}
private:
std::size_t h_;
};
void
pop_encoded_front(
core::string_view& s,
char& c,
std::size_t& n) noexcept;
// compare two core::string_views as if they are both
// percent-decoded
int
compare_encoded(
core::string_view lhs,
core::string_view rhs) noexcept;
// digest a core::string_view as if it were
// percent-decoded
void
digest_encoded(
core::string_view s,
fnv_1a& hasher) noexcept;
void
digest(
core::string_view s,
fnv_1a& hasher) noexcept;
// check if core::string_view lhs starts with core::string_view
// rhs as if they are both percent-decoded. If
// lhs starts with rhs, return number of chars
// matched in the encoded core::string_view
std::size_t
path_starts_with(
core::string_view lhs,
core::string_view rhs) noexcept;
// check if core::string_view lhs ends with core::string_view
// rhs as if they are both percent-decoded. If
// lhs ends with rhs, return number of chars
// matched in the encoded core::string_view
std::size_t
path_ends_with(
core::string_view lhs,
core::string_view rhs) noexcept;
// compare two core::string_views as if they are both
// percent-decoded and lowercase
int
ci_compare_encoded(
core::string_view lhs,
core::string_view rhs) noexcept;
// digest a core::string_view as if it were decoded
// and lowercase
void
ci_digest_encoded(
core::string_view s,
fnv_1a& hasher) noexcept;
// compare two ascii core::string_views
int
compare(
core::string_view lhs,
core::string_view rhs) noexcept;
// compare two core::string_views as if they are both
// lowercase
int
ci_compare(
core::string_view lhs,
core::string_view rhs) noexcept;
// digest a core::string_view as if it were lowercase
void
ci_digest(
core::string_view s,
fnv_1a& hasher) noexcept;
BOOST_URL_DECL
std::size_t
remove_dot_segments(
char* dest,
char const* end,
core::string_view s) noexcept;
void
pop_last_segment(
core::string_view& s,
core::string_view& c,
std::size_t& level,
bool r) noexcept;
char
path_pop_back( core::string_view& s );
void
normalized_path_digest(
core::string_view s,
bool remove_unmatched,
fnv_1a& hasher) noexcept;
int
segments_compare(
segments_encoded_view seg0,
segments_encoded_view seg1) noexcept;
} // detail
} // urls
} // boost
#endif
+99
View File
@@ -0,0 +1,99 @@
//
// 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_DETAIL_OPTIONAL_STRING_HPP
#define BOOST_URL_DETAIL_OPTIONAL_STRING_HPP
#include <boost/url/detail/string_view.hpp>
#include <boost/core/detail/string_view.hpp>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
struct no_value_t;
#endif
namespace detail {
struct optional_string
{
core::string_view s;
bool b = false;
};
template <class String>
typename std::enable_if<
std::is_convertible<String, core::string_view>::value,
optional_string>::type
get_optional_string(
String const& s)
{
optional_string r;
r.s = s;
r.b = true;
return r;
}
template <class T, class = void>
struct is_dereferenceable : std::false_type
{};
template <class T>
struct is_dereferenceable<
T,
void_t<
decltype(*std::declval<T>())
>> : std::true_type
{};
template <class OptionalString>
typename std::enable_if<
!std::is_convertible<OptionalString, core::string_view>::value,
optional_string>::type
get_optional_string(
OptionalString const& opt)
{
// If this goes off, it means the rule
// passed in did not meet the requirements.
// Please check the documentation of functions
// that call get_optional_string.
static_assert(
is_dereferenceable<OptionalString>::value &&
std::is_constructible<bool, OptionalString>::value &&
!std::is_convertible<OptionalString, core::string_view>::value &&
std::is_convertible<typename std::decay<decltype(*std::declval<OptionalString>())>::type, core::string_view>::value,
"OptionalString requirements not met");
optional_string r;
r.s = opt ? detail::to_sv(*opt) : core::string_view{};
r.b = static_cast<bool>(opt);
return r;
}
inline
optional_string
get_optional_string(
std::nullptr_t)
{
return {};
}
inline
optional_string
get_optional_string(
no_value_t const&)
{
return {};
}
} // detail
} // urls
} // boost
#endif
+165
View File
@@ -0,0 +1,165 @@
//
// 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_DETAIL_OVER_ALLOCATOR_HPP
#define BOOST_URL_DETAIL_OVER_ALLOCATOR_HPP
#include <boost/config.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/assert.hpp>
#include <boost/type_traits/is_final.hpp>
#include <boost/type_traits/type_with_alignment.hpp>
#ifdef BOOST_NO_CXX11_ALLOCATOR
# include <boost/core/allocator_traits.hpp>
#endif
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
namespace boost {
namespace urls {
namespace detail {
// This is a workaround for allocator_traits
// implementations which falsely claim C++11
// compatibility.
#ifdef BOOST_NO_CXX11_ALLOCATOR
template<class Alloc>
using allocator_traits =
boost::allocator_traits<Alloc>;
#else
template<class Alloc>
using allocator_traits = std::allocator_traits<Alloc>;
#endif
template<class T, class Allocator>
class over_allocator
: private empty_value<Allocator>
{
template<class U, class OtherAlloc>
friend class over_allocator;
std::size_t extra_;
public:
using is_always_equal = std::false_type;
using value_type = typename
allocator_traits<typename allocator_traits<
Allocator>::template rebind_alloc<T>>::value_type;
using pointer = typename
allocator_traits<typename allocator_traits<
Allocator>::template rebind_alloc<T>>::pointer;
using const_pointer = typename
allocator_traits<typename allocator_traits<
Allocator>::template rebind_alloc<T>>::const_pointer;
using size_type = typename
allocator_traits<typename allocator_traits<
Allocator>::template rebind_alloc<T>>::size_type;
using difference_type = typename
allocator_traits<typename allocator_traits<
Allocator>::template rebind_alloc<T>>::difference_type;
template<class U>
struct rebind
{
using other = over_allocator<U, Allocator>;
};
over_allocator(
std::size_t extra,
Allocator const& alloc)
: empty_value<Allocator>(
empty_init, alloc)
, extra_(extra)
{
}
template<class U>
over_allocator(over_allocator<U, Allocator> const& other) noexcept
: empty_value<Allocator>(
empty_init, other.get())
, extra_(other.extra_)
{
}
pointer
allocate(size_type n)
{
BOOST_ASSERT(n == 1);
using U = typename boost::type_with_alignment<
alignof(value_type)>::type;
auto constexpr S = sizeof(U);
using A = typename allocator_traits<
Allocator>::template rebind_alloc<U>;
A a(this->get());
return reinterpret_cast<pointer>(
std::allocator_traits<A>::allocate(a,
(n * sizeof(value_type) + extra_ + S - 1) / S));
}
void
deallocate(pointer p, size_type n)
{
BOOST_ASSERT(n == 1);
using U = typename boost::type_with_alignment<
alignof(value_type)>::type;
auto constexpr S = sizeof(U);
using A = typename allocator_traits<
Allocator>::template rebind_alloc<U>;
A a{this->get()};
std::allocator_traits<A>::deallocate(a,
reinterpret_cast<U*>(p),
(n * sizeof(value_type) + extra_ + S - 1) / S);
}
#if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
template<class U, class... Args>
void
construct(U* ptr, Args&&... args)
{
::new((void*)ptr) U(std::forward<Args>(args)...);
}
template<class U>
void
destroy(U* ptr)
{
ptr->~U();
}
#endif
template<class U>
friend
bool
operator==(
over_allocator const& lhs,
over_allocator<U, Allocator> const& rhs)
{
return
lhs.get() == rhs.get() &&
lhs.extra_ == rhs.extra_;
}
template<class U>
friend
bool
operator!=(
over_allocator const& lhs,
over_allocator<U, Allocator> const& rhs)
{
return ! (lhs == rhs);
}
};
} // detail
} // urls
} // boost
#endif
+84
View File
@@ -0,0 +1,84 @@
//
// 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_DETAIL_PARAMS_ITER_IMPL_HPP
#define BOOST_URL_DETAIL_PARAMS_ITER_IMPL_HPP
#include <boost/url/param.hpp>
#include <boost/url/detail/parts_base.hpp>
#include <boost/url/detail/url_impl.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace urls {
namespace detail {
struct BOOST_URL_DECL params_iter_impl
: parts_base
{
query_ref ref;
std::size_t index = 0;
std::size_t pos;
std::size_t nk;
std::size_t nv;
std::size_t dk;
std::size_t dv;
params_iter_impl() = default;
params_iter_impl(
params_iter_impl const&) = default;
params_iter_impl& operator=(
params_iter_impl const&) = default;
// begin
params_iter_impl(
query_ref const&) noexcept;
// end
params_iter_impl(
query_ref const&,
int) noexcept;
// at index
params_iter_impl(
query_ref const&,
std::size_t,
std::size_t) noexcept;
void setup() noexcept;
void increment() noexcept;
void decrement() noexcept;
param_pct_view
dereference() const noexcept;
pct_string_view key() const noexcept;
auto
next() const noexcept ->
params_iter_impl
{
auto next = *this;
next.increment();
return next;
}
bool
equal(
params_iter_impl const&
other) const noexcept
{
// different containers
BOOST_ASSERT(ref.alias_of(other.ref));
return index == other.index;
}
};
} // detail
} // urls
} // boost
#endif
+53
View File
@@ -0,0 +1,53 @@
//
// 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_DETAIL_PARTS_BASE_HPP
#define BOOST_URL_DETAIL_PARTS_BASE_HPP
#include <boost/url/error.hpp>
namespace boost {
namespace urls {
namespace detail {
// mix-in to provide part
// constants and variables
struct parts_base
{
enum
{
id_scheme = -1, // trailing ':'
id_user, // leading "//"
id_pass, // leading ':', trailing '@'
id_host,
id_port, // leading ':'
id_path,
id_query, // leading '?'
id_frag, // leading '#'
id_end // one past the end
};
enum class from : char {
// this belongs to a string
string = 0,
// this belongs to url_base
// segments/params containers point to
// another url
url = 1,
// this belongs to authority_view
// id_user does not have the leading "//"
authority = 2,
};
};
} // detail
} // urls
} // boost
#endif
+140
View File
@@ -0,0 +1,140 @@
//
// 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_DETAIL_PATH_HPP
#define BOOST_URL_DETAIL_PATH_HPP
#include <boost/core/detail/string_view.hpp>
namespace boost {
namespace urls {
namespace detail {
// Return the number of characters at
// the front of the path that are reserved
inline
std::size_t
path_prefix(
char const* p,
std::size_t n) noexcept
{
switch(n)
{
case 0:
return 0;
case 1:
if(p[0] == '/')
return 1;
return 0;
case 2:
if(p[0] == '/')
return 1;
if( p[0] == '.' &&
p[1] == '/')
return 2;
return 0;
default:
if(p[0] == '/')
{
if( p[1] == '.' &&
p[2] == '/')
return 3;
return 1;
}
if( p[0] == '.' &&
p[1] == '/')
return 2;
break;
}
return 0;
}
// VFALCO DEPRECATED
inline
std::size_t
path_prefix(
core::string_view s) noexcept
{
return path_prefix(
s.data(), s.size());
}
// returns the number of adjusted
// segments based on the malleable prefix.
inline
std::size_t
path_segments(
core::string_view s,
std::size_t nseg) noexcept
{
switch(s.size())
{
case 0:
BOOST_ASSERT(nseg == 0);
return 0;
case 1:
BOOST_ASSERT(nseg == 1);
if(s[0] == '/')
return 0;
return 1;
case 2:
if(s[0] == '/')
return nseg;
if( s[0] == '.' &&
s[1] == '/')
{
BOOST_ASSERT(nseg > 1);
return nseg - 1;
}
return nseg;
default:
if(s[0] == '/')
{
if( s[1] == '.' &&
s[2] == '/')
{
BOOST_ASSERT(nseg > 1);
return nseg - 1;
}
return nseg;
}
if( s[0] == '.' &&
s[1] == '/')
{
BOOST_ASSERT(nseg > 1);
return nseg - 1;
}
break;
}
return nseg;
}
// Trim reserved characters from
// the front of the path.
inline
core::string_view
clean_path(
core::string_view s) noexcept
{
s.remove_prefix(
path_prefix(s));
return s;
}
} // detail
} // urls
} // boost
#endif
+60
View File
@@ -0,0 +1,60 @@
//
// 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_DETAIL_PATTERN_HPP
#define BOOST_URL_DETAIL_PATTERN_HPP
#include <boost/url/error_types.hpp>
#include <boost/url/url_base.hpp>
#include <boost/core/detail/string_view.hpp>
// This file includes functions and classes
// to parse uri templates or format strings
namespace boost {
namespace urls {
namespace detail {
class format_args;
struct pattern
{
core::string_view scheme;
core::string_view user;
core::string_view pass;
core::string_view host;
core::string_view port;
core::string_view path;
core::string_view query;
core::string_view frag;
bool has_authority = false;
bool has_user = false;
bool has_pass = false;
bool has_port = false;
bool has_query = false;
bool has_frag = false;
BOOST_URL_DECL
void
apply(
url_base& u,
format_args const& args) const;
};
BOOST_URL_DECL
system::result<pattern>
parse_pattern(
core::string_view s);
} // detail
} // url
} // boost
#endif
+42
View File
@@ -0,0 +1,42 @@
//
// 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_DETAIL_PCT_FORMAT_HPP
#define BOOST_URL_DETAIL_PCT_FORMAT_HPP
#include <boost/core/detail/string_view.hpp>
#include <boost/url/url.hpp>
#include <boost/url/grammar/lut_chars.hpp>
#include <boost/url/detail/format_args.hpp>
namespace boost {
namespace urls {
namespace detail {
// measure a single string
BOOST_URL_DECL
std::size_t
pct_vmeasure(
grammar::lut_chars const& cs,
format_parse_context& pctx,
measure_context& mctx);
// format a single string
BOOST_URL_DECL
char*
pct_vformat(
grammar::lut_chars const& cs,
format_parse_context& pctx,
format_context& fctx);
} // detail
} // url
} // boost
#endif
+79
View File
@@ -0,0 +1,79 @@
//
// 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_DETAIL_PRINT_HPP
#define BOOST_URL_DETAIL_PRINT_HPP
#include <cstdint>
#include <type_traits>
namespace boost {
namespace urls {
namespace detail {
// std::uint64_t
// 18446744073709551615
// 1 2
template<class T>
struct printed
: std::false_type
{
};
// 16-bit unsigned
template<>
class printed<std::uint16_t>
: std::false_type
{
char n_;
char buf_[5];
public:
printed(std::uint16_t n)
{
char* it =
buf_ + sizeof(buf_);
if(n == 0)
{
*--it = '0';
n_ = 1;
}
else
{
while(n > 0)
{
*--it = '0' + (n % 10);
n /= 10;
}
n_ = static_cast<char>(
sizeof(buf_) - (
it - buf_));
}
}
core::string_view
string() const noexcept
{
return core::string_view(buf_ +
sizeof(buf_) - n_, n_);
}
};
template<class T>
printed<T>
make_printed(T t)
{
return printed<T>(t);
}
} // detail
} // urls
} // boost
#endif
+76
View File
@@ -0,0 +1,76 @@
//
// 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_DETAIL_REPLACEMENT_FIELD_RULE_HPP
#define BOOST_URL_DETAIL_REPLACEMENT_FIELD_RULE_HPP
#include <boost/url/error.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/variant_rule.hpp>
#include <boost/url/grammar/unsigned_rule.hpp>
namespace boost {
namespace urls {
namespace detail {
// replacement_field ::= "{" [arg_id] [":" format_spec "}"
struct replacement_field_rule_t
{
using value_type = core::string_view;
BOOST_URL_DECL
system::result<value_type>
parse(
char const*& it,
char const* end) const noexcept;
};
constexpr replacement_field_rule_t replacement_field_rule{};
// identifier ::= id_start id_continue*
// id_start ::= "a"..."z" | "A"..."Z" | "_"
// id_continue ::= id_start | digit
struct identifier_rule_t
{
using value_type = core::string_view;
BOOST_URL_DECL
system::result<value_type>
parse(
char const*& it,
char const* end) const noexcept;
};
constexpr identifier_rule_t identifier_rule{};
// arg_id ::= integer | identifier
// integer ::= digit+
// digit ::= "0"..."9"
static constexpr auto arg_id_rule =
grammar::variant_rule(
identifier_rule,
grammar::unsigned_rule<std::size_t>{});
struct format_spec_rule_t
{
using value_type = core::string_view;
system::result<value_type>
parse(
char const*& it,
char const* end) const noexcept;
};
constexpr format_spec_rule_t format_spec_rule{};
} // detail
} // urls
} // boost
#endif
+85
View File
@@ -0,0 +1,85 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_DETAIL_SEGMENTS_ITER_IMPL_HPP
#define BOOST_URL_DETAIL_SEGMENTS_ITER_IMPL_HPP
#include <boost/url/detail/parts_base.hpp>
#include <boost/url/detail/url_impl.hpp>
#include <boost/core/detail/string_view.hpp>
#include <string>
namespace boost {
namespace urls {
namespace detail {
struct segments_iter_impl
: private parts_base
{
path_ref ref;
std::size_t pos = 0;
std::size_t next = 0;
std::size_t index = 0;
std::size_t dn = 0;
private:
pct_string_view s_;
public:
segments_iter_impl() = default;
segments_iter_impl(
segments_iter_impl const&) noexcept = default;
segments_iter_impl& operator=(
segments_iter_impl const&) noexcept = default;
// begin
segments_iter_impl(
detail::path_ref const&) noexcept;
// end
segments_iter_impl(
detail::path_ref const&,
int) noexcept;
// at index
segments_iter_impl(
url_impl const& u_,
std::size_t pos_,
std::size_t i_) noexcept;
void update() noexcept;
BOOST_URL_DECL
void
increment() noexcept;
BOOST_URL_DECL
void
decrement() noexcept;
pct_string_view
dereference() const noexcept
{
return s_;
}
bool
equal(
segments_iter_impl const& other) const noexcept
{
BOOST_ASSERT(ref.alias_of(other.ref));
return index == other.index;
}
};
} // detail
} // urls
} // boost
#endif
+34
View File
@@ -0,0 +1,34 @@
//
// 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_DETAIL_STRING_VIEW_HPP
#define BOOST_URL_DETAIL_STRING_VIEW_HPP
#include <boost/core/detail/string_view.hpp>
namespace boost {
namespace urls {
namespace detail {
// We use detail::to_sv(s) instead of core::string_view(s) whenever
// we should convert to core::string_view.
// This is a workaround for GCC >=8.0 <8.4
// See: https://github.com/boostorg/url/issues/672
template<class T>
core::string_view
to_sv(T const& t) noexcept
{
return core::string_view(t);
}
} // detail
} // urls
} // boost
#endif
+193
View File
@@ -0,0 +1,193 @@
//
// 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_DETAIL_URL_IMPL_HPP
#define BOOST_URL_DETAIL_URL_IMPL_HPP
#include <boost/url/host_type.hpp>
#include <boost/url/pct_string_view.hpp>
#include <boost/url/scheme.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/detail/parts_base.hpp>
#include <boost/assert.hpp>
#include <cstdint>
namespace boost {
namespace urls {
class url_view;
class authority_view;
namespace detail {
constexpr char const* const empty_c_str_ = "";
// This is the private 'guts' of a
// url_view, exposed so different parts
// of the implementation can work on it.
struct BOOST_URL_DECL url_impl : parts_base
{
static
constexpr
std::size_t const zero_ = 0;
// never nullptr
char const* cs_ = empty_c_str_;
std::size_t offset_[id_end + 1] = {};
std::size_t decoded_[id_end] = {};
std::size_t nseg_ = 0;
std::size_t nparam_ = 0;
unsigned char ip_addr_[16] = {};
// VFALCO don't we need a bool?
std::uint16_t port_number_ = 0;
host_type host_type_ =
urls::host_type::none;
scheme scheme_ =
urls::scheme::none;
from from_ = from::string;
url_impl(
from b) noexcept
: from_(b)
{
}
// in url_view.ipp
url_view construct() const noexcept;
// in authority_view.ipp
authority_view
construct_authority() const noexcept;
std::size_t len(int, int) const noexcept;
std::size_t len(int) const noexcept;
std::size_t offset(int) const noexcept;
core::string_view get(int) const noexcept;
core::string_view get(int, int) const noexcept;
pct_string_view pct_get(int) const noexcept;
pct_string_view pct_get(int, int) const noexcept;
void set_size(int, std::size_t) noexcept;
void split(int, std::size_t) noexcept;
void adjust(int, int, std::size_t) noexcept;
void collapse(int, int, std::size_t) noexcept;
void apply_scheme(core::string_view) noexcept;
void apply_userinfo(pct_string_view const&,
pct_string_view const*) noexcept;
void apply_host(host_type, pct_string_view,
unsigned char const*) noexcept;
void apply_port(core::string_view, unsigned short) noexcept;
void apply_authority(authority_view const&) noexcept;
void apply_path(pct_string_view, std::size_t) noexcept;
void apply_query(pct_string_view, std::size_t) noexcept;
void apply_frag(pct_string_view) noexcept;
};
//------------------------------------------------
// this allows a path to come from a
// url_impl or a separate core::string_view
class path_ref
: private parts_base
{
url_impl const* impl_ = nullptr;
char const* data_ = nullptr;
std::size_t size_ = 0;
std::size_t nseg_ = 0;
std::size_t dn_ = 0;
public:
path_ref() = default;
path_ref(url_impl const& impl) noexcept;
path_ref(core::string_view,
std::size_t, std::size_t) noexcept;
pct_string_view buffer() const noexcept;
std::size_t size() const noexcept;
char const* data() const noexcept;
char const* end() const noexcept;
std::size_t nseg() const noexcept;
bool
alias_of(
url_impl const& impl) const noexcept
{
return impl_ == &impl;
}
bool
alias_of(
path_ref const& ref) const noexcept
{
if(impl_)
return impl_ == ref.impl_;
BOOST_ASSERT(data_ != ref.data_ || (
size_ == ref.size_ &&
nseg_ == ref.nseg_ &&
dn_ == ref.dn_));
return data_ == ref.data_;
}
};
//------------------------------------------------
// this allows a params to come from a
// url_impl or a separate core::string_view
class BOOST_URL_DECL query_ref
: private parts_base
{
url_impl const* impl_ = nullptr;
char const* data_ = nullptr;
std::size_t size_ = 0;
std::size_t nparam_ = 0;
std::size_t dn_ = 0;
bool question_mark_ = false;
public:
query_ref(
core::string_view s, // buffer, no '?'
std::size_t dn, // decoded size
std::size_t nparam
) noexcept;
query_ref() = default;
query_ref(url_impl const& impl) noexcept;
pct_string_view buffer() const noexcept;
std::size_t size() const noexcept; // with '?'
char const* begin() const noexcept; // no '?'
char const* end() const noexcept;
std::size_t nparam() const noexcept;
bool
alias_of(
url_impl const& impl) const noexcept
{
return impl_ == &impl;
}
bool
alias_of(
query_ref const& ref) const noexcept
{
if(impl_)
return impl_ == ref.impl_;
BOOST_ASSERT(data_ != ref.data_ || (
size_ == ref.size_ &&
nparam_ == ref.nparam_ &&
dn_ == ref.dn_));
return data_ == ref.data_;
}
};
} // detail
} // urls
} // boost
#endif
+48
View File
@@ -0,0 +1,48 @@
//
// 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_DETAIL_FORMAT_HPP
#define BOOST_URL_DETAIL_FORMAT_HPP
#include <boost/url/detail/format_args.hpp>
#include <boost/url/detail/pattern.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/url.hpp>
namespace boost {
namespace urls {
namespace detail {
inline
void
vformat_to(
url_base& u,
core::string_view fmt,
detail::format_args args)
{
parse_pattern(fmt)
.value().apply(u, args);
}
inline
url
vformat(
core::string_view fmt,
detail::format_args args)
{
url u;
vformat_to(u, fmt, args);
return u;
}
} // detail
} // url
} // boost
#endif
+196
View File
@@ -0,0 +1,196 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_ENCODE_HPP
#define BOOST_URL_ENCODE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/encoding_opts.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/all_chars.hpp>
#include <boost/url/grammar/string_token.hpp>
namespace boost {
namespace urls {
/** Return the buffer size needed for percent-encoding
This function returns the exact number
of bytes necessary to store the result
of applying percent-encoding to the
string using the given options and
character set.
No encoding is actually performed.
@par Example
@code
assert( encoded_size( "My Stuff", pchars ) == 10 );
@endcode
@par Exception Safety
Throws nothing.
@return The number of bytes needed,
excluding any null terminator.
@param s The string to measure.
@param unreserved The set of characters
that is not percent-encoded.
@param opt The options for encoding. If
this parameter is omitted, the default
options are be used.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-2.1"
>2.1. Percent-Encoding (rfc3986)</a>
@see
@ref encode,
@ref encoding_opts,
@ref make_pct_string_view.
*/
template<class CharSet>
std::size_t
encoded_size(
core::string_view s,
CharSet const& unreserved,
encoding_opts opt = {}) noexcept;
//------------------------------------------------
/** Apply percent-encoding to a string
This function applies percent-encoding
to the string using the given options and
character set. The destination buffer
provided by the caller is used to store
the result, which may be truncated if
there is insufficient space.
@par Example
@code
char buf[100];
assert( encode( buf, sizeof(buf), "Program Files", pchars ) == 15 );
@endcode
@par Exception Safety
Throws nothing.
@return The number of characters written
to the destination buffer.
@param dest The destination buffer
to write to.
@param size The number of writable
characters pointed to by `dest`.
If this is less than `encoded_size(s)`,
the result is truncated.
@param s The string to encode.
@param unreserved The set of characters
that is not percent-encoded.
@param opt The options for encoding. If
this parameter is omitted, the default
options are used.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-2.1"
>2.1. Percent-Encoding (rfc3986)</a>
@see
@ref encode,
@ref encoded_size,
@ref make_pct_string_view.
*/
template<class CharSet>
std::size_t
encode(
char* dest,
std::size_t size,
core::string_view s,
CharSet const& unreserved,
encoding_opts opt = {});
#ifndef BOOST_URL_DOCS
// VFALCO semi-private for now
template<class CharSet>
std::size_t
encode_unsafe(
char* dest,
std::size_t size,
core::string_view s,
CharSet const& unreserved,
encoding_opts opt);
#endif
//------------------------------------------------
/** Return a percent-encoded string
This function applies percent-encoding
to the string using the given options and
character set, and returns the result as
a string when called with default arguments.
@par Example
@code
encoding_opts opt;
opt.space_as_plus = true;
std::string s = encode( "My Stuff", opt, pchars );
assert( s == "My+Stuff" );
@endcode
@par Exception Safety
Calls to allocate may throw.
@return The string
@param s The string to encode.
@param unreserved The set of characters
that is not percent-encoded.
@param opt The options for encoding. If
this parameter is omitted, the default
options are used.
@param token A string token.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-2.1"
>2.1. Percent-Encoding (rfc3986)</a>
@see
@ref encode,
@ref encoded_size,
@ref encoding_opts,
*/
template<
BOOST_URL_STRTOK_TPARAM,
class CharSet>
BOOST_URL_STRTOK_RETURN
encode(
core::string_view s,
CharSet const& unreserved,
encoding_opts opt = {},
BOOST_URL_STRTOK_ARG(token)) noexcept;
} // urls
} // boost
#include <boost/url/impl/encode.hpp>
#endif
+81
View File
@@ -0,0 +1,81 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_ENCODING_OPTS_HPP
#define BOOST_URL_ENCODING_OPTS_HPP
#include <boost/url/detail/config.hpp>
namespace boost {
namespace urls {
/** Percent-encoding options
These options are used to customize
the behavior of algorithms which use
percent escapes, such as encoding
or decoding.
@see
@ref encode,
@ref encoded_size,
@ref pct_string_view.
*/
struct BOOST_URL_DECL encoding_opts
{
/** True if spaces encode to and from plus signs
This option controls whether or not
the PLUS character ("+") is used to
represent the SP character (" ") when
encoding or decoding.
Although not prescribed by the RFC, plus
signs are commonly treated as spaces upon
decoding when used in the query of URLs
using well known schemes such as HTTP.
@par Specification
@li <a href="https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1">
application/x-www-form-urlencoded (w3.org)</a>
*/
bool space_as_plus = false;
/** True if hexadecimal digits are emitted as lower case
By default, percent-encoding algorithms
emit hexadecimal digits A through F as
uppercase letters. When this option is
`true`, lowercase letters are used.
*/
bool lower_case = false;
/** True if nulls are not allowed
Normally all possible character values
(from 0 to 255) are allowed, with reserved
characters being replaced with escapes
upon encoding. When this option is true,
attempting to decode a null will result
in an error.
*/
bool disallow_null = false;
#ifndef BOOST_URL_DOCS
encoding_opts(
bool space_as_plus_ = false,
bool lower_case_ = false,
bool disallow_null_ = false) noexcept;
#endif
};
} // urls
} // boost
#endif
+90
View File
@@ -0,0 +1,90 @@
//
// 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_ERROR_HPP
#define BOOST_URL_ERROR_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <stdexcept>
namespace boost {
namespace urls {
/** Error codes returned the library
*/
enum class error
{
// VFALCO 3 space indent or
// else Doxygen malfunctions
/**
* The operation completed successfully.
*/
success = 0,
/**
* Null encountered in pct-encoded.
*/
illegal_null,
/**
* Illegal reserved character in encoded string.
*/
illegal_reserved_char,
/**
* A grammar element was not in canonical form.
*/
non_canonical,
//--------------------------------------------
/**
* Bad hexadecimal digit.
This error condition is fatal.
*/
bad_pct_hexdig,
/**
* The percent-encoded sequence is incomplete.
This error condition is fatal.
*/
incomplete_encoding,
/**
* Missing hexadecimal digit.
This error condition is fatal.
*/
missing_pct_hexdig,
/**
* No space in output buffer
This error is returned when a provided
output buffer was too small to hold
the complete result of an algorithm.
*/
no_space,
/**
* The URL is not a base URL
*/
not_a_base
};
} // urls
} // boost
#include <boost/url/impl/error.hpp>
#endif
+293
View File
@@ -0,0 +1,293 @@
//
// 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_ERROR_TYPES_HPP
#define BOOST_URL_ERROR_TYPES_HPP
#include <boost/url/detail/config.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <boost/system/result.hpp>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
namespace error_types {
#endif
/** The type of error category used by the library
@note This alias is no longer supported and
should not be used in new code. Please use
`system::error_category` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
using error_category
BOOST_URL_DEPRECATED("Use system::error_category instead") =
boost::system::error_category;
/** The type of error code used by the library
@note This alias is no longer supported and
should not be used in new code. Please use
`system::error_code` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
using error_code
BOOST_URL_DEPRECATED("Use system::error_code instead") =
boost::system::error_code;
/** The type of error condition used by the library
@note This alias is no longer supported and
should not be used in new code. Please use
`system::error_condition` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
using error_condition
BOOST_URL_DEPRECATED("Use system::error_condition instead") =
boost::system::error_condition;
/** The type of system error thrown by the library
@note This alias is no longer supported and
should not be used in new code. Please use
`system::system_error` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
using system_error
BOOST_URL_DEPRECATED("Use system::system_error instead") =
boost::system::system_error;
/** A function to return the generic error category used by the library
@note This alias is no longer supported and
should not be used in new code. Please use
`core::string_view` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
#ifdef BOOST_URL_DOCS
error_category const& generic_category();
#else
using boost::system::generic_category;
#endif
/** A function to return the system error category used by the library
@note This alias is no longer supported and
should not be used in new code. Please use
`core::string_view` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
#ifdef BOOST_URL_DOCS
error_category const& system_category();
#else
using boost::system::system_category;
#endif
/** The set of constants used for cross-platform error codes
@note This alias is no longer supported and
should not be used in new code. Please use
`core::string_view` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
#ifdef BOOST_URL_DOCS
enum errc
{
__see_below__
};
#else
namespace errc = boost::system::errc;
#endif
/** The type of result returned by library functions
@note This alias is no longer supported and
should not be used in new code. Please use
`system::result` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
@details This is an alias template used as the return type
for functions that can either return a container,
or fail with an error code. This is a brief
synopsis of the type:
@par Declaration
@code
template< class T >
class result
{
public:
//
// Return true if the result contains an error
//
constexpr bool has_error() const noexcept;
//
// Return the error
//
constexpr system::error_code error() const noexcept;
//
// Return true if the result contains a value
//
constexpr bool has_value() const noexcept;
constexpr explicit operator bool() const noexcept;
//
// Return the value, or throw an exception
//
constexpr T& value();
constexpr T const& value() const;
// Return the value.
// Precondition: has_value()==true
//
constexpr T& operator*() noexcept;
constexpr T* operator->() noexcept;
constexpr T const& operator*() const noexcept;
constexpr T const* operator->() const noexcept;
...more
@endcode
@par Usage
Given the function @ref parse_uri with this signature:
@code
system::result< url_view > parse_uri( core::string_view s ) noexcept;
@endcode
The following statement captures the value in a
variable upon success, otherwise throws:
@code
url_view u = parse_uri( "http://example.com/path/to/file.txt" ).value();
@endcode
This statement captures the result in a local
variable and inspects the error condition:
@code
system::result< url_view > rv = parse_uri( "http://example.com/path/to/file.txt" );
if(! rv )
std::cout << rv.error();
else
std::cout << *rv;
@endcode
@tparam T The type of value held by the result.
@see
@li <a href="https://boost.org/libs/system/doc/html/system.html#ref_resultt_e"
>`boost::system::result`</a>
*/
template<class T>
using result
BOOST_URL_DEPRECATED("Use system::result<T> instead") =
boost::system::result<T, system::error_code>;
#ifndef BOOST_URL_DOCS
} // error_types
using namespace error_types;
#endif
} // urls
} // boost
#endif
+416
View File
@@ -0,0 +1,416 @@
//
// 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_FORMAT_HPP
#define BOOST_URL_FORMAT_HPP
#include <boost/url/detail/config.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/url.hpp>
#include <boost/url/detail/vformat.hpp>
#include <initializer_list>
namespace boost {
namespace urls {
/** Format arguments into a URL
Format arguments according to the format
URL string into a @ref url.
The rules for a format URL string are the same
as for a `std::format_string`, where replacement
fields are delimited by curly braces.
The URL components to which replacement fields
belong are identified before replacement is
applied and any invalid characters for that
formatted argument are percent-escaped.
Hence, the delimiters between URL components,
such as `:`, `//`, `?`, and `#`, should be
included in the URL format string. Likewise,
a format string with a single `"{}"` is
interpreted as a path and any replacement
characters invalid in this component will be
encoded to form a valid URL.
@par Example
@code
assert(format("{}", "Hello world!").buffer() == "Hello%20world%21");
@endcode
@par Preconditions
All replacement fields must be valid and the
resulting URL should be valid after arguments
are formatted into the URL.
Because any invalid characters for a URL
component are encoded by this function, only
replacements in the scheme and port components
might be invalid, as these components do not
allow percent-encoding of arbitrary
characters.
@return A URL holding the formatted result.
@param fmt The format URL string.
@param args Arguments to be formatted.
@throws system_error
`fmt` contains an invalid format string and
the result contains an invalid URL after
replacements are applied.
@par BNF
@code
replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
arg_id ::= integer | identifier
integer ::= digit+
digit ::= "0"..."9"
identifier ::= id_start id_continue*
id_start ::= "a"..."z" | "A"..."Z" | "_"
id_continue ::= id_start | digit
@endcode
@par Specification
@li <a href="https://fmt.dev/latest/syntax.html"
>Format String Syntax</a>
@see
@ref format_to.
*/
template <class... Args>
url
format(
core::string_view fmt,
Args&&... args)
{
return detail::vformat(
fmt, detail::make_format_args(
std::forward<Args>(args)...));
}
/** Format arguments into a URL
Format arguments according to the format
URL string into a @ref url_base.
The rules for a format URL string are the same
as for a `std::format_string`, where replacement
fields are delimited by curly braces.
The URL components to which replacement fields
belong are identified before replacement is
applied and any invalid characters for that
formatted argument are percent-escaped.
Hence, the delimiters between URL components,
such as `:`, `//`, `?`, and `#`, should be
included in the URL format string. Likewise,
a format string with a single `"{}"` is
interpreted as a path and any replacement
characters invalid in this component will be
encoded to form a valid URL.
@par Example
@code
static_url<30> u;
format(u, "{}", "Hello world!");
assert(u.buffer() == "Hello%20world%21");
@endcode
@par Preconditions
All replacement fields must be valid and the
resulting URL should be valid after arguments
are formatted into the URL.
Because any invalid characters for a URL
component are encoded by this function, only
replacements in the scheme and port components
might be invalid, as these components do not
allow percent-encoding of arbitrary
characters.
@par Exception Safety
Strong guarantee.
@param u An object that derives from @ref url_base.
@param fmt The format URL string.
@param args Arguments to be formatted.
@throws system_error
`fmt` contains an invalid format string and
`u` contains an invalid URL after replacements
are applied.
@par BNF
@code
replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
arg_id ::= integer | identifier
integer ::= digit+
digit ::= "0"..."9"
identifier ::= id_start id_continue*
id_start ::= "a"..."z" | "A"..."Z" | "_"
id_continue ::= id_start | digit
@endcode
@par Specification
@li <a href="https://fmt.dev/latest/syntax.html"
>Format String Syntax</a>
@see
@ref format.
*/
template <class... Args>
void
format_to(
url_base& u,
core::string_view fmt,
Args&&... args)
{
detail::vformat_to(
u, fmt, detail::make_format_args(
std::forward<Args>(args)...));
}
/** Format arguments into a URL
Format arguments according to the format
URL string into a @ref url.
This overload allows type-erased arguments
to be passed as an initializer_list, which
is mostly convenient for named parameters.
All arguments must be convertible to a
implementation defined type able to store a
type-erased reference to any valid format
argument.
The rules for a format URL string are the same
as for a `std::format_string`, where replacement
fields are delimited by curly braces.
The URL components to which replacement fields
belong are identified before replacement is
applied and any invalid characters for that
formatted argument are percent-escaped.
Hence, the delimiters between URL components,
such as `:`, `//`, `?`, and `#`, should be
included in the URL format string. Likewise,
a format string with a single `"{}"` is
interpreted as a path and any replacement
characters invalid in this component will be
encoded to form a valid URL.
@par Example
@code
assert(format("user/{id}", {{"id", 1}}).buffer() == "user/1");
@endcode
@par Preconditions
All replacement fields must be valid and the
resulting URL should be valid after arguments
are formatted into the URL.
Because any invalid characters for a URL
component are encoded by this function, only
replacements in the scheme and port components
might be invalid, as these components do not
allow percent-encoding of arbitrary
characters.
@return A URL holding the formatted result.
@param fmt The format URL string.
@param args Arguments to be formatted.
@throws system_error
`fmt` contains an invalid format string and
the result contains an invalid URL after
replacements are applied.
@par BNF
@code
replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
arg_id ::= integer | identifier
integer ::= digit+
digit ::= "0"..."9"
identifier ::= id_start id_continue*
id_start ::= "a"..."z" | "A"..."Z" | "_"
id_continue ::= id_start | digit
@endcode
@par Specification
@li <a href="https://fmt.dev/latest/syntax.html"
>Format String Syntax</a>
@see
@ref format_to.
*/
inline
url
format(
core::string_view fmt,
#ifdef BOOST_URL_DOCS
std::initializer_list<__see_below__> args
#else
std::initializer_list<detail::format_arg> args
#endif
)
{
return detail::vformat(
fmt, detail::format_args(
args.begin(), args.end()));
}
/** Format arguments into a URL
Format arguments according to the format
URL string into a @ref url_base.
This overload allows type-erased arguments
to be passed as an initializer_list, which
is mostly convenient for named parameters.
All arguments must be convertible to a
implementation defined type able to store a
type-erased reference to any valid format
argument.
The rules for a format URL string are the same
as for a `std::format_string`, where replacement
fields are delimited by curly braces.
The URL components to which replacement fields
belong are identified before replacement is
applied and any invalid characters for that
formatted argument are percent-escaped.
Hence, the delimiters between URL components,
such as `:`, `//`, `?`, and `#`, should be
included in the URL format string. Likewise,
a format string with a single `"{}"` is
interpreted as a path and any replacement
characters invalid in this component will be
encoded to form a valid URL.
@par Example
@code
static_url<30> u;
format_to(u, "user/{id}", {{"id", 1}})
assert(u.buffer() == "user/1");
@endcode
@par Preconditions
All replacement fields must be valid and the
resulting URL should be valid after arguments
are formatted into the URL.
Because any invalid characters for a URL
component are encoded by this function, only
replacements in the scheme and port components
might be invalid, as these components do not
allow percent-encoding of arbitrary
characters.
@par Exception Safety
Strong guarantee.
@param u An object that derives from @ref url_base.
@param fmt The format URL string.
@param args Arguments to be formatted.
@throws system_error
`fmt` contains an invalid format string and
`u` contains an invalid URL after replacements
are applied.
@par BNF
@code
replacement_field ::= "{" [arg_id] [":" (format_spec | chrono_format_spec)] "}"
arg_id ::= integer | identifier
integer ::= digit+
digit ::= "0"..."9"
identifier ::= id_start id_continue*
id_start ::= "a"..."z" | "A"..."Z" | "_"
id_continue ::= id_start | digit
@endcode
@par Specification
@li <a href="https://fmt.dev/latest/syntax.html"
>Format String Syntax</a>
@see
@ref format.
*/
inline
void
format_to(
url_base& u,
core::string_view fmt,
#ifdef BOOST_URL_DOCS
std::initializer_list<__see_below__> args
#else
std::initializer_list<detail::format_arg> args
#endif
)
{
detail::vformat_to(
u, fmt, detail::format_args(
args.begin(), args.end()));
}
/** Designate a named argument for a replacement field
Construct a named argument for a format URL
string that contains named replacement fields.
The function parameters should be convertible
to an implementation defined type able to
store the name and a reference to any type
potentially used as a format argument.
@par Example
@code
assert(format("user/{id}", arg("id", 1)).buffer() == "user/1");
@endcode
@return An temporary object with reference
semantics for a named argument
@param name The argument name
@param arg The argument value
@see
@ref format,
@ref format_to.
*/
template <class T>
#ifdef BOOST_URL_DOCS
__implementation_defined__
#else
detail::named_arg<T>
#endif
arg(core::string_view name, T const& arg)
{
return {name, arg};
}
} // url
} // boost
#endif
+40
View File
@@ -0,0 +1,40 @@
//
// 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_HPP
#define BOOST_URL_GRAMMAR_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/grammar/alnum_chars.hpp>
#include <boost/url/grammar/alpha_chars.hpp>
#include <boost/url/grammar/charset.hpp>
#include <boost/url/grammar/ci_string.hpp>
#include <boost/url/grammar/dec_octet_rule.hpp>
#include <boost/url/grammar/delim_rule.hpp>
#include <boost/url/grammar/digit_chars.hpp>
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/hexdig_chars.hpp>
#include <boost/url/grammar/literal_rule.hpp>
#include <boost/url/grammar/lut_chars.hpp>
#include <boost/url/grammar/not_empty_rule.hpp>
#include <boost/url/grammar/optional_rule.hpp>
#include <boost/url/grammar/parse.hpp>
#include <boost/url/grammar/range_rule.hpp>
#include <boost/url/grammar/recycled.hpp>
#include <boost/url/grammar/string_token.hpp>
#include <boost/url/grammar/string_view_base.hpp>
#include <boost/url/grammar/token_rule.hpp>
#include <boost/url/grammar/tuple_rule.hpp>
#include <boost/url/grammar/type_traits.hpp>
#include <boost/url/grammar/unsigned_rule.hpp>
#include <boost/url/grammar/variant_rule.hpp>
#include <boost/url/grammar/vchars.hpp>
#endif
+88
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
+93
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
+95
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
+217
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
+356
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
+76
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
+188
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
+189
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
+179
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
+102
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
+212
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
+85
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
+130
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
+158
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
+123
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
+55
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
+42
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
+67
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
+742
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
+221
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
+45
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
+285
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
+109
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
+116
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
+88
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
+402
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
+108
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
+112
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
+144
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
+602
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
+510
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
+347
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
+877
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
+108
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
+248
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
+68
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
+82
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
+131
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
+85
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
+58
View File
@@ -0,0 +1,58 @@
//
// 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_HOST_TYPE_HPP
#define BOOST_URL_HOST_TYPE_HPP
#include <boost/url/detail/config.hpp>
namespace boost {
namespace urls {
/** Identifies the type of host in a URL.
Values of this type are returned by URL views
and containers to indicate the type of host
present in a URL.
*/
enum class host_type
{
// VFALCO 3 space indent or
// else Doxygen malfunctions
/**
* No host is specified.
*/
none,
/**
* A host is specified by reg-name.
*/
name,
/**
* A host is specified by @ref ipv4_address.
*/
ipv4,
/**
* A host is specified by @ref ipv6_address.
*/
ipv6,
/**
* A host is specified by IPvFuture.
*/
ipvfuture
};
} // urls
} // boost
#endif
+118
View File
@@ -0,0 +1,118 @@
//
// 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_IGNORE_CASE_HPP
#define BOOST_URL_IGNORE_CASE_HPP
#include <boost/url/detail/config.hpp>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
struct ignore_case_t
{
};
#endif
/** Ignore case when comparing
This value may be optionally passed to
functions accepting a parameter of type
@ref ignore_case_param to indicate that
comparisons should be case-insensitive.
*/
constexpr
#ifdef BOOST_URL_DOCS
__implementation_defined__
#else
ignore_case_t
#endif
ignore_case{};
/** An optional parameter to determine case-sensitivity
Functions may use parameters of this type
to allow the user to optionally indicate
that comparisons should be case-insensitive
when the value @ref ignore_case is passed.
*/
class ignore_case_param
{
/** True if an algorithm should ignore case
Functions accepting a parameter of type
`ignore_case_param` can check `value`
to determine if the caller has indicated
that comparisons should ignore case.
*/
bool value_ = false;
public:
/** Constructor
By default, comparisons are
case-sensitive.
@par Example
This function performs case-sensitive
comparisons when called with no
arguments:
@code
void f( ignore_case_param = {} );
@endcode
*/
constexpr
ignore_case_param() noexcept = default;
/** Constructor
Construction from @ref ignore_case
indicates that comparisons should
be case-insensitive.
@par Example
When @ref ignore_case is passed as
an argument, this function ignores
case when performing comparisons:
@code
void f( ignore_case_param = {} );
@endcode
*/
constexpr
ignore_case_param(
#ifdef BOOST_URL_DOCS
__implementation_defined__
#else
ignore_case_t
#endif
) noexcept
: value_(true)
{
}
/** True if an algorithm should ignore case
Values of type `ignore_case_param`
evaluate to true when constructed
with the constant @ref ignore_case.
Otherwise, they are default-constructed
and evaluate to `false`.
*/
operator
bool() const noexcept
{
return value_;
}
};
} // urls
} // boost
#endif
+172
View File
@@ -0,0 +1,172 @@
//
// 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_IMPL_PCT_ENCODED_VIEW_HPP
#define BOOST_URL_IMPL_PCT_ENCODED_VIEW_HPP
#include <boost/url/grammar/type_traits.hpp>
#include <boost/static_assert.hpp>
namespace boost {
namespace urls {
class decode_view::iterator
{
char const* begin_ = nullptr;
char const* pos_ = nullptr;
bool space_as_plus_ = true;
friend decode_view;
iterator(
char const* str,
bool space_as_plus) noexcept
: begin_(str)
, pos_(str)
, space_as_plus_(
space_as_plus)
{
}
// end ctor
iterator(
char const* str,
size_type n,
bool space_as_plus) noexcept
: begin_(str)
, pos_(str + n)
, space_as_plus_(space_as_plus)
{
}
public:
using value_type = char;
using reference = char;
using pointer = void const*;
using const_reference = char;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
iterator() = default;
iterator(iterator const&) = default;
iterator&
operator=(iterator const&) = default;
BOOST_URL_DECL
reference
operator*() const noexcept;
iterator&
operator++() noexcept
{
BOOST_ASSERT(pos_ != nullptr);
if (*pos_ != '%')
++pos_;
else
pos_ += 3;
return *this;
}
iterator&
operator--() noexcept
{
BOOST_ASSERT(pos_ != begin_);
if (pos_ - begin_ < 3 ||
pos_[-3] != '%')
--pos_;
else
pos_ -= 3;
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
char const*
base()
{
return pos_;
}
bool
operator==(
iterator const& other) const noexcept
{
return pos_ == other.pos_;
}
bool
operator!=(
iterator const& other) const noexcept
{
return !(*this == other);
}
};
//------------------------------------------------
inline
auto
decode_view::
begin() const noexcept ->
const_iterator
{
return {p_, space_as_plus_};
}
inline
auto
decode_view::
end() const noexcept ->
const_iterator
{
return {p_, n_, space_as_plus_};
}
inline
auto
decode_view::
front() const noexcept ->
const_reference
{
BOOST_ASSERT( !empty() );
return *begin();
}
inline
auto
decode_view::
back() const noexcept ->
const_reference
{
BOOST_ASSERT( !empty() );
return *--end();
}
} // urls
} // boost
#endif
+278
View File
@@ -0,0 +1,278 @@
//
// 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_IMPL_ENCODE_HPP
#define BOOST_URL_IMPL_ENCODE_HPP
#include <boost/url/detail/encode.hpp>
#include <boost/url/detail/except.hpp>
#include <boost/url/encoding_opts.hpp>
#include <boost/url/grammar/charset.hpp>
#include <boost/url/grammar/hexdig_chars.hpp>
#include <boost/url/grammar/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
namespace boost {
namespace urls {
//------------------------------------------------
template<class CharSet>
std::size_t
encoded_size(
core::string_view s,
CharSet const& unreserved,
encoding_opts opt) noexcept
{
/* If you get a compile error here, it
means that the value you passed does
not meet the requirements stated in
the documentation.
*/
static_assert(
grammar::is_charset<CharSet>::value,
"Type requirements not met");
std::size_t n = 0;
auto it = s.data();
auto const last = it + s.size();
if(! opt.space_as_plus ||
unreserved(' '))
{
while(it != last)
{
if(unreserved(*it))
n += 1;
else
n += 3;
++it;
}
}
else
{
while(it != last)
{
auto c = *it;
if(unreserved(c))
++n;
else if(c == ' ')
++n;
else
n += 3;
++it;
}
}
return n;
}
//------------------------------------------------
template<class CharSet>
std::size_t
encode(
char* dest,
std::size_t size,
core::string_view s,
CharSet const& unreserved,
encoding_opts opt)
{
/* If you get a compile error here, it
means that the value you passed does
not meet the requirements stated in
the documentation.
*/
static_assert(
grammar::is_charset<CharSet>::value,
"Type requirements not met");
// '%' must be reserved
BOOST_ASSERT(! unreserved('%'));
char const* const hex =
detail::hexdigs[opt.lower_case];
auto const encode = [hex](
char*& dest,
unsigned char c) noexcept
{
*dest++ = '%';
*dest++ = hex[c>>4];
*dest++ = hex[c&0xf];
};
auto it = s.data();
auto const end = dest + size;
auto const last = it + s.size();
auto const dest0 = dest;
auto const end3 = end - 3;
if(! opt.space_as_plus)
{
while(it != last)
{
if(unreserved(*it))
{
if(dest == end)
return dest - dest0;
*dest++ = *it++;
continue;
}
if(dest > end3)
return dest - dest0;
encode(dest, *it++);
}
return dest - dest0;
}
else if(! unreserved(' '))
{
// VFALCO space is usually reserved,
// and we depend on this for an
// optimization. if this assert
// goes off we can split the loop
// below into two versions.
BOOST_ASSERT(! unreserved(' '));
while(it != last)
{
if(unreserved(*it))
{
if(dest == end)
return dest - dest0;
*dest++ = *it++;
continue;
}
if(*it == ' ')
{
if(dest == end)
return dest - dest0;
*dest++ = '+';
++it;
continue;
}
if(dest > end3)
return dest - dest0;
encode(dest, *it++);
}
}
return dest - dest0;
}
//------------------------------------------------
// unsafe encode just
// asserts on the output buffer
//
template<class CharSet>
std::size_t
encode_unsafe(
char* dest,
std::size_t size,
core::string_view s,
CharSet const& unreserved,
encoding_opts opt)
{
// '%' must be reserved
BOOST_ASSERT(! unreserved('%'));
auto it = s.data();
auto const last = it + s.size();
auto const end = dest + size;
ignore_unused(end);
char const* const hex =
detail::hexdigs[opt.lower_case];
auto const encode = [end, hex](
char*& dest,
unsigned char c) noexcept
{
ignore_unused(end);
*dest++ = '%';
BOOST_ASSERT(dest != end);
*dest++ = hex[c>>4];
BOOST_ASSERT(dest != end);
*dest++ = hex[c&0xf];
};
auto const dest0 = dest;
if(! opt.space_as_plus)
{
while(it != last)
{
BOOST_ASSERT(dest != end);
if(unreserved(*it))
*dest++ = *it++;
else
encode(dest, *it++);
}
}
else
{
// VFALCO space is usually reserved,
// and we depend on this for an
// optimization. if this assert
// goes off we can split the loop
// below into two versions.
BOOST_ASSERT(! unreserved(' '));
while(it != last)
{
BOOST_ASSERT(dest != end);
if(unreserved(*it))
{
*dest++ = *it++;
}
else if(*it == ' ')
{
*dest++ = '+';
++it;
}
else
{
encode(dest, *it++);
}
}
}
return dest - dest0;
}
//------------------------------------------------
template<
class StringToken,
class CharSet>
BOOST_URL_STRTOK_RETURN
encode(
core::string_view s,
CharSet const& unreserved,
encoding_opts opt,
StringToken&& token) noexcept
{
/* If you get a compile error here, it
means that the value you passed does
not meet the requirements stated in
the documentation.
*/
static_assert(
grammar::is_charset<CharSet>::value,
"Type requirements not met");
auto const n = encoded_size(
s, unreserved, opt);
auto p = token.prepare(n);
if(n > 0)
encode_unsafe(
p, n, s, unreserved, opt);
return token.result();
}
} // urls
} // boost
#endif
+79
View File
@@ -0,0 +1,79 @@
//
// 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_IMPL_ERROR_HPP
#define BOOST_URL_IMPL_ERROR_HPP
#include <type_traits>
namespace boost {
//-----------------------------------------------
namespace system {
template<>
struct is_error_code_enum<::boost::urls::error>
{
static bool const value = true;
};
} // system
//-----------------------------------------------
namespace urls {
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(0xbc15399d7a4ce829)
{
}
};
BOOST_URL_DECL extern
error_cat_type error_cat;
} // detail
inline
BOOST_SYSTEM_CONSTEXPR
system::error_code
make_error_code(
error ev) noexcept
{
return system::error_code{
static_cast<std::underlying_type<
error>::type>(ev),
detail::error_cat};
}
} // urls
} // boost
#endif
+116
View File
@@ -0,0 +1,116 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_PARAMS_BASE_HPP
#define BOOST_URL_IMPL_PARAMS_BASE_HPP
#include <boost/url/detail/params_iter_impl.hpp>
#include <iterator>
namespace boost {
namespace urls {
//------------------------------------------------
class BOOST_URL_DECL params_base::iterator
{
detail::params_iter_impl it_;
bool space_as_plus_ = true;
friend class params_base;
friend class params_ref;
iterator(
detail::query_ref const& ref,
encoding_opts opt) noexcept;
iterator(
detail::query_ref const& impl,
encoding_opts opt,
int) noexcept;
iterator(
detail::params_iter_impl const& it,
encoding_opts opt) noexcept
: it_(it)
, space_as_plus_(opt.space_as_plus)
{
}
public:
using value_type = params_base::value_type;
using reference = params_base::reference;
using pointer = reference;
using difference_type =
params_base::difference_type;
using iterator_category =
std::bidirectional_iterator_tag;
iterator() = default;
iterator(iterator const&) = default;
iterator& operator=(
iterator const&) noexcept = default;
iterator&
operator++() noexcept
{
it_.increment();
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
iterator&
operator--() noexcept
{
it_.decrement();
return *this;
}
iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
reference
operator*() const;
// the return value is too expensive
pointer operator->() const = delete;
bool
operator==(
iterator const& other) const noexcept
{
return it_.equal(other.it_);
}
bool
operator!=(
iterator const& other) const noexcept
{
return ! it_.equal(other.it_);
}
};
} // urls
} // boost
#endif
+186
View File
@@ -0,0 +1,186 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_PARAMS_ENCODED_BASE_HPP
#define BOOST_URL_IMPL_PARAMS_ENCODED_BASE_HPP
#include <boost/url/detail/params_iter_impl.hpp>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
class params_ref;
#endif
//------------------------------------------------
class params_encoded_base::iterator
{
detail::params_iter_impl it_;
friend class params_encoded_base;
friend class params_encoded_ref;
iterator(detail::query_ref const& ref) noexcept;
iterator(detail::query_ref const& ref, int) noexcept;
iterator(
detail::params_iter_impl const& it)
: it_(it)
{
}
public:
using value_type =
params_encoded_base::value_type;
using reference =
params_encoded_base::reference;
using pointer = reference;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
iterator() = default;
iterator(iterator const&) = default;
iterator& operator=(
iterator const&) = default;
iterator&
operator++() noexcept
{
it_.increment();
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
iterator&
operator--() noexcept
{
it_.decrement();
return *this;
}
iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
reference
operator*() const
{
return it_.dereference();
}
pointer
operator->() const
{
return it_.dereference();
}
friend
bool
operator==(
iterator const& it0,
iterator const& it1) noexcept
{
return it0.it_.equal(it1.it_);
}
friend
bool
operator!=(
iterator const& it0,
iterator const& it1) noexcept
{
return ! it0.it_.equal(it1.it_);
}
};
//------------------------------------------------
//
// Observers
//
//------------------------------------------------
inline
bool
params_encoded_base::
contains(
pct_string_view key,
ignore_case_param ic) const noexcept
{
return find_impl(
begin().it_, key, ic) != end();
}
inline
auto
params_encoded_base::
find(
pct_string_view key,
ignore_case_param ic) const noexcept ->
iterator
{
return find_impl(
begin().it_, key, ic);
}
inline
auto
params_encoded_base::
find(
iterator it,
pct_string_view key,
ignore_case_param ic) const noexcept ->
iterator
{
return find_impl(
it.it_, key, ic);
}
inline
auto
params_encoded_base::
find_last(
pct_string_view key,
ignore_case_param ic) const noexcept ->
iterator
{
return find_last_impl(
end().it_, key, ic);
}
inline
auto
params_encoded_base::
find_last(
iterator it,
pct_string_view key,
ignore_case_param ic) const noexcept ->
iterator
{
return find_last_impl(
it.it_, key, ic);
}
} // urls
} // boost
#endif
+196
View File
@@ -0,0 +1,196 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_PARAMS_ENCODED_REF_HPP
#define BOOST_URL_IMPL_PARAMS_ENCODED_REF_HPP
#include <boost/url/detail/except.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace urls {
//------------------------------------------------
//
// Modifiers
//
//------------------------------------------------
inline
void
params_encoded_ref::
clear() noexcept
{
u_->remove_query();
}
template<class FwdIt>
void
params_encoded_ref::
assign(FwdIt first, FwdIt last)
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
assign(first, last,
typename std::iterator_traits<
FwdIt>::iterator_category{});
}
inline
auto
params_encoded_ref::
append(
param_pct_view const& p) ->
iterator
{
return insert(end(), p);
}
inline
auto
params_encoded_ref::
append(
std::initializer_list<
param_pct_view> init) ->
iterator
{
return insert(end(), init);
}
template<class FwdIt>
auto
params_encoded_ref::
append(
FwdIt first, FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
return insert(
end(), first, last);
}
template<class FwdIt>
auto
params_encoded_ref::
insert(
iterator before,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
return insert(
before,
first,
last,
typename std::iterator_traits<
FwdIt>::iterator_category{});
}
template<class FwdIt>
auto
params_encoded_ref::
replace(
iterator from,
iterator to,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
return u_->edit_params(
from.it_, to.it_,
detail::make_params_encoded_iter(
first, last));
}
//------------------------------------------------
//
// implementation
//
//------------------------------------------------
template<class FwdIt>
void
params_encoded_ref::
assign(FwdIt first, FwdIt last,
std::forward_iterator_tag)
{
u_->edit_params(
begin().it_,
end().it_,
detail::make_params_encoded_iter(
first, last));
}
template<class FwdIt>
auto
params_encoded_ref::
insert(
iterator before,
FwdIt first,
FwdIt last,
std::forward_iterator_tag) ->
iterator
{
return u_->edit_params(
before.it_,
before.it_,
detail::make_params_encoded_iter(
first, last));
}
} // urls
} // boost
#endif
+240
View File
@@ -0,0 +1,240 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_PARAMS_REF_HPP
#define BOOST_URL_IMPL_PARAMS_REF_HPP
#include <boost/url/params_view.hpp>
#include <boost/url/detail/any_params_iter.hpp>
#include <boost/url/detail/except.hpp>
#include <boost/url/grammar/recycled.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace urls {
inline
params_ref::
params_ref(
url_base& u,
encoding_opts opt) noexcept
: params_base(u.impl_, opt)
, u_(&u)
{
}
//------------------------------------------------
//
// Special Members
//
//------------------------------------------------
inline
params_ref::
params_ref(
params_ref const& other,
encoding_opts opt) noexcept
: params_ref(*other.u_, opt)
{
}
inline
auto
params_ref::
operator=(std::initializer_list<
param_view> init) ->
params_ref&
{
assign(init);
return *this;
}
//------------------------------------------------
//
// Modifiers
//
//------------------------------------------------
inline
void
params_ref::
clear() noexcept
{
u_->remove_query();
}
//------------------------------------------------
template<class FwdIt>
void
params_ref::
assign(FwdIt first, FwdIt last)
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
assign(first, last,
typename std::iterator_traits<
FwdIt>::iterator_category{});
}
inline
auto
params_ref::
append(
param_view const& p) ->
iterator
{
return insert(end(), p);
}
inline
auto
params_ref::
append(
std::initializer_list<
param_view> init) ->
iterator
{
return insert(end(), init);
}
template<class FwdIt>
auto
params_ref::
append(FwdIt first, FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
return insert(
end(), first, last);
}
template<class FwdIt>
auto
params_ref::
insert(
iterator before,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
return insert(
before,
first,
last,
typename std::iterator_traits<
FwdIt>::iterator_category{});
}
template<class FwdIt>
auto
params_ref::
replace(
iterator from,
iterator to,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
param_view>::value,
"Type requirements not met");
return iterator(
u_->edit_params(
from.it_, to.it_,
detail::make_params_iter(
first, last)),
opt_);
}
//------------------------------------------------
//
// implementation
//
//------------------------------------------------
template<class FwdIt>
void
params_ref::
assign(FwdIt first, FwdIt last,
std::forward_iterator_tag)
{
u_->edit_params(
begin().it_,
end().it_,
detail::make_params_iter(
first, last));
}
template<class FwdIt>
auto
params_ref::
insert(
iterator before,
FwdIt first,
FwdIt last,
std::forward_iterator_tag) ->
iterator
{
return iterator(
u_->edit_params(
before.it_,
before.it_,
detail::make_params_iter(
first, last)),
opt_);
}
} // urls
} // boost
#endif
+126
View File
@@ -0,0 +1,126 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_SEGMENTS_BASE_HPP
#define BOOST_URL_IMPL_SEGMENTS_BASE_HPP
#include <boost/url/detail/segments_iter_impl.hpp>
#include <boost/assert.hpp>
#include <iterator>
namespace boost {
namespace urls {
class segments_base::iterator
{
detail::segments_iter_impl it_;
friend class segments_base;
friend class segments_ref;
iterator(detail::path_ref const&) noexcept;
iterator(detail::path_ref const&, int) noexcept;
iterator(
detail::segments_iter_impl const& it) noexcept
: it_(it)
{
}
public:
using value_type = segments_base::value_type;
using reference = segments_base::reference;
using pointer = reference;
using difference_type =
segments_base::difference_type;
using iterator_category =
std::bidirectional_iterator_tag;
iterator() = default;
iterator(iterator const&) = default;
iterator& operator=(
iterator const&) noexcept = default;
BOOST_URL_DECL
reference
operator*() const;
// the return value is too expensive
pointer operator->() const = delete;
iterator&
operator++() noexcept
{
it_.increment();
return *this;
}
iterator&
operator--() noexcept
{
it_.decrement();
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
bool
operator==(
iterator const& other) const noexcept
{
return it_.equal(other.it_);
}
bool
operator!=(
iterator const& other) const noexcept
{
return ! it_.equal(other.it_);
}
};
//------------------------------------------------
inline
std::string
segments_base::
front() const noexcept
{
BOOST_ASSERT(! empty());
return *begin();
}
inline
std::string
segments_base::
back() const noexcept
{
BOOST_ASSERT(! empty());
return *--end();
}
} // urls
} // boost
#endif
+132
View File
@@ -0,0 +1,132 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_SEGMENTS_ENCODED_BASE_HPP
#define BOOST_URL_IMPL_SEGMENTS_ENCODED_BASE_HPP
#include <boost/url/detail/segments_iter_impl.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace urls {
class segments_encoded_base::iterator
{
detail::segments_iter_impl it_;
friend class url_base;
friend class segments_encoded_base;
friend class segments_encoded_ref;
iterator(detail::path_ref const&) noexcept;
iterator(detail::path_ref const&, int) noexcept;
iterator(
detail::segments_iter_impl const& it) noexcept
: it_(it)
{
}
public:
using value_type =
segments_encoded_base::value_type;
using reference =
segments_encoded_base::reference;
using pointer = reference;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
iterator() = default;
iterator(iterator const&) = default;
iterator& operator=(
iterator const&) = default;
reference
operator*() const noexcept
{
return it_.dereference();
}
pointer
operator->() const noexcept
{
return it_.dereference();
}
iterator&
operator++() noexcept
{
it_.increment();
return *this;
}
iterator&
operator--() noexcept
{
it_.decrement();
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
bool
operator==(
iterator const& other) const noexcept
{
return it_.equal(other.it_);
}
bool
operator!=(
iterator const& other) const noexcept
{
return ! it_.equal(other.it_);
}
};
//------------------------------------------------
inline
pct_string_view
segments_encoded_base::
front() const noexcept
{
BOOST_ASSERT(! empty());
return *begin();
}
inline
pct_string_view
segments_encoded_base::
back() const noexcept
{
BOOST_ASSERT(! empty());
return *--end();
}
} // urls
} // boost
#endif
+170
View File
@@ -0,0 +1,170 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_SEGMENTS_ENCODED_REF_HPP
#define BOOST_URL_IMPL_SEGMENTS_ENCODED_REF_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/detail/segments_iter_impl.hpp>
#include <boost/url/detail/any_segments_iter.hpp>
#include <type_traits>
namespace boost {
namespace urls {
//------------------------------------------------
//
// Modifiers
//
//------------------------------------------------
inline
void
segments_encoded_ref::
clear() noexcept
{
erase(begin(), end());
}
template<class FwdIt>
void
segments_encoded_ref::
assign(
FwdIt first, FwdIt last)
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value,
"Type requirements not met");
u_->edit_segments(
begin().it_,
end().it_,
detail::make_segments_encoded_iter(
first, last));
}
template<class FwdIt>
auto
segments_encoded_ref::
insert(
iterator before,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value,
"Type requirements not met");
return insert(
before,
first,
last,
typename std::iterator_traits<
FwdIt>::iterator_category{});
}
inline
auto
segments_encoded_ref::
erase(
iterator pos) noexcept ->
iterator
{
return erase(pos, std::next(pos));
}
template<class FwdIt>
auto
segments_encoded_ref::
replace(
iterator from,
iterator to,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value,
"Type requirements not met");
return u_->edit_segments(
from.it_,
to.it_,
detail::make_segments_encoded_iter(
first, last));
}
//------------------------------------------------
inline
void
segments_encoded_ref::
push_back(
pct_string_view s)
{
insert(end(), s);
}
inline
void
segments_encoded_ref::
pop_back() noexcept
{
erase(std::prev(end()));
}
//------------------------------------------------
template<class FwdIt>
auto
segments_encoded_ref::
insert(
iterator before,
FwdIt first,
FwdIt last,
std::forward_iterator_tag) ->
iterator
{
return u_->edit_segments(
before.it_,
before.it_,
detail::make_segments_encoded_iter(
first, last));
}
} // urls
} // boost
#endif
+169
View File
@@ -0,0 +1,169 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IMPL_SEGMENTS_REF_HPP
#define BOOST_URL_IMPL_SEGMENTS_REF_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/detail/any_segments_iter.hpp>
#include <boost/url/detail/segments_iter_impl.hpp>
#include <type_traits>
namespace boost {
namespace urls {
//------------------------------------------------
//
// Modifiers
//
//------------------------------------------------
inline
void
segments_ref::
clear() noexcept
{
erase(begin(), end());
}
template<class FwdIt>
void
segments_ref::
assign(FwdIt first, FwdIt last)
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value,
"Type requirements not met");
u_->edit_segments(
begin().it_,
end().it_,
detail::make_segments_iter(
first, last));
}
template<class FwdIt>
auto
segments_ref::
insert(
iterator before,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value,
"Type requirements not met");
return insert(
before,
first,
last,
typename std::iterator_traits<
FwdIt>::iterator_category{});
}
inline
auto
segments_ref::
erase(
iterator pos) noexcept ->
iterator
{
return erase(pos, std::next(pos));
}
template<class FwdIt>
auto
segments_ref::
replace(
iterator from,
iterator to,
FwdIt first,
FwdIt last) ->
iterator
{
/* If you get a compile error here, it
means that the iterators you passed
do not meet the requirements stated
in the documentation.
*/
static_assert(
std::is_convertible<
typename std::iterator_traits<
FwdIt>::reference,
core::string_view>::value,
"Type requirements not met");
return u_->edit_segments(
from.it_,
to.it_,
detail::make_segments_iter(
first, last));
}
//------------------------------------------------
inline
void
segments_ref::
push_back(
core::string_view s)
{
insert(end(), s);
}
inline
void
segments_ref::
pop_back() noexcept
{
erase(std::prev(end()));
}
//------------------------------------------------
template<class FwdIt>
auto
segments_ref::
insert(
iterator before,
FwdIt first,
FwdIt last,
std::forward_iterator_tag) ->
iterator
{
return u_->edit_segments(
before.it_,
before.it_,
detail::make_segments_iter(
first, last));
}
} // urls
} // boost
#endif
+344
View File
@@ -0,0 +1,344 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IPV4_ADDRESS_HPP
#define BOOST_URL_IPV4_ADDRESS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/string_token.hpp>
#include <string>
#include <array>
#include <cstdint>
#include <iosfwd>
namespace boost {
namespace urls {
/** An IP version 4 style address.
Objects of this type are used to construct,
parse, and manipulate IP version 6 addresses.
@par BNF
@code
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
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://en.wikipedia.org/wiki/IPv4"
>IPv4 (Wikipedia)</a>
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
>3.2.2. Host (rfc3986)</a>
@see
@ref parse_ipv4_address,
@ref ipv6_address.
*/
class ipv4_address
{
public:
/** The number of characters in the longest possible IPv4 string.
The longest ipv4 address string is "255.255.255.255".
*/
static
constexpr
std::size_t max_str_len = 15;
/** The type used to represent an address as an unsigned integer
*/
using uint_type =
std::uint_least32_t;
/** The type used to represent an address as an array of bytes
*/
using bytes_type =
std::array<unsigned char, 4>;
/** Constructor.
*/
ipv4_address() = default;
/** Constructor.
*/
ipv4_address(
ipv4_address const&) = default;
/** Copy Assignment.
*/
ipv4_address&
operator=(
ipv4_address const&) = default;
//
//---
//
/** Construct from an unsigned integer.
This function constructs an address from
the unsigned integer `u`, where the most
significant byte forms the first octet
of the resulting address.
@param u The integer to construct from.
*/
BOOST_URL_DECL
explicit
ipv4_address(
uint_type u) noexcept;
/** Construct from an array of bytes.
This function constructs an address
from the array in `bytes`, which is
interpreted in big-endian.
@param bytes The value to construct from.
*/
BOOST_URL_DECL
explicit
ipv4_address(
bytes_type const& bytes) noexcept;
/** Construct from a string.
This function constructs an address from
the string `s`, which must contain a valid
IPv4 address string or else an exception
is thrown.
@note For a non-throwing parse function,
use @ref parse_ipv4_address.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
The input failed to parse correctly.
@param s The string to parse.
@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_ipv4_address.
*/
BOOST_URL_DECL
explicit
ipv4_address(
core::string_view s);
/** Return the address as bytes, in network byte order.
*/
BOOST_URL_DECL
bytes_type
to_bytes() const noexcept;
/** Return the address as an unsigned integer.
*/
BOOST_URL_DECL
uint_type
to_uint() const noexcept;
/** Return the address as a string in dotted decimal format
When called with no arguments, the
return type is `std::string`.
Otherwise, the return type and style
of output is determined by which string
token is passed.
@par Example
@code
assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
@endcode
@par Complexity
Constant.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
String tokens may throw exceptions.
@return The return type of the string token.
If the token parameter is omitted, then
a new `std::string` is returned.
Otherwise, the function return type
is the result type of the token.
@param token An optional string token.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
2.2. Text Representation of Addresses (rfc4291)</a>
*/
template<BOOST_URL_STRTOK_TPARAM>
BOOST_URL_STRTOK_RETURN
to_string(
BOOST_URL_STRTOK_ARG(token)) const
{
to_string_impl(token);
return token.result();
}
/** Write a dotted decimal string representing the address to a buffer
The resulting buffer is not null-terminated.
@throw std::length_error `dest_size < ipv4_address::max_str_len`
@return The formatted string
@param dest The buffer in which to write,
which must have at least `dest_size` space.
@param dest_size The size of the output buffer.
*/
BOOST_URL_DECL
core::string_view
to_buffer(
char* dest,
std::size_t dest_size) const;
/** Return true if the address is a loopback address
*/
BOOST_URL_DECL
bool
is_loopback() const noexcept;
/** Return true if the address is unspecified
*/
BOOST_URL_DECL
bool
is_unspecified() const noexcept;
/** Return true if the address is a multicast address
*/
BOOST_URL_DECL
bool
is_multicast() const noexcept;
/** Return true if two addresses are equal
*/
friend
bool
operator==(
ipv4_address const& a1,
ipv4_address const& a2) noexcept
{
return a1.addr_ == a2.addr_;
}
/** Return true if two addresses are not equal
*/
friend
bool
operator!=(
ipv4_address const& a1,
ipv4_address const& a2) noexcept
{
return a1.addr_ != a2.addr_;
}
/** Return an address object that represents any address
*/
static
ipv4_address
any() noexcept
{
return ipv4_address();
}
/** Return an address object that represents the loopback address
*/
static
ipv4_address
loopback() noexcept
{
return ipv4_address(0x7F000001);
}
/** Return an address object that represents the broadcast address
*/
static
ipv4_address
broadcast() noexcept
{
return ipv4_address(0xFFFFFFFF);
}
// hidden friend
friend
std::ostream&
operator<<(
std::ostream& os,
ipv4_address const& addr)
{
char buf[ipv4_address::max_str_len];
os << addr.to_buffer(buf, sizeof(buf));
return os;
}
private:
friend class ipv6_address;
BOOST_URL_DECL
std::size_t
print_impl(
char* dest) const noexcept;
BOOST_URL_DECL
void
to_string_impl(
string_token::arg& t) const;
uint_type addr_ = 0;
};
/** Format the address to an output stream.
IPv4 addresses written to output streams
are written in their dotted decimal format.
@param os The output stream.
@param addr The address to format.
*/
std::ostream&
operator<<(
std::ostream& os,
ipv4_address const& addr);
//------------------------------------------------
/** Return an IPv4 address from an IP address string in dotted decimal form
*/
BOOST_URL_DECL
system::result<ipv4_address>
parse_ipv4_address(
core::string_view s) noexcept;
} // urls
} // boost
#endif
+398
View File
@@ -0,0 +1,398 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_IPV6_ADDRESS_HPP
#define BOOST_URL_IPV6_ADDRESS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/string_token.hpp>
#include <array>
#include <cstdint>
#include <iosfwd>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
class ipv4_address;
#endif
/** An IP version 6 style address.
Objects of this type are used to construct,
parse, and manipulate IP version 6 addresses.
@par BNF
@code
IPv6address = 6( h16 ":" ) ls32
/ "::" 5( h16 ":" ) ls32
/ [ h16 ] "::" 4( h16 ":" ) ls32
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
/ [ *4( h16 ":" ) h16 ] "::" ls32
/ [ *5( h16 ":" ) h16 ] "::" h16
/ [ *6( h16 ":" ) h16 ] "::"
ls32 = ( h16 ":" h16 ) / IPv4address
; least-significant 32 bits of address
h16 = 1*4HEXDIG
; 16 bits of address represented in hexadecimal
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291"
>IP Version 6 Addressing Architecture (rfc4291)</a>
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
>3.2.2. Host (rfc3986)</a>
@see
@ref ipv4_address,
@ref parse_ipv6_address.
*/
class ipv6_address
{
public:
/** The number of characters in the longest possible IPv6 string.
The longest IPv6 address is:
@code
ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
@endcode
@see
@ref to_buffer.
*/
// ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
// ::ffff:255.255.255.255
// 12345678901234567890123456789012345678901234567890
// 1 2 3 4
static
constexpr
std::size_t max_str_len = 49;
/** The type used to represent an address as an array of bytes.
Octets are stored in network byte order.
*/
using bytes_type = std::array<
unsigned char, 16>;
/** Constructor.
Default constructed objects represent
the unspecified address.
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"
>2.5.2. The Unspecified Address</a>
@see
@ref is_unspecified
*/
ipv6_address() = default;
/** Constructor.
*/
ipv6_address(
ipv6_address const&) = default;
/** Copy Assignment
*/
ipv6_address&
operator=(
ipv6_address const&) = default;
/** Construct from an array of bytes.
This function constructs an address
from the array in `bytes`, which is
interpreted in big-endian.
@param bytes The value to construct from.
*/
BOOST_URL_DECL
ipv6_address(
bytes_type const& bytes) noexcept;
/** Construct from an IPv4 address.
This function constructs an IPv6 address
from the IPv4 address `addr`. The resulting
address is an IPv4-Mapped IPv6 Address.
@param addr The address to construct from.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"
>2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
*/
BOOST_URL_DECL
ipv6_address(
ipv4_address const& addr) noexcept;
/** Construct from a string.
This function constructs an address from
the string `s`, which must contain a valid
IPv6 address string or else an exception
is thrown.
@note For a non-throwing parse function,
use @ref parse_ipv6_address.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
The input failed to parse correctly.
@param s The string to parse.
@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_ipv6_address.
*/
BOOST_URL_DECL
ipv6_address(
core::string_view s);
/** Return the address as bytes, in network byte order
*/
bytes_type
to_bytes() const noexcept
{
return addr_;
}
/** Return the address as a string.
The returned string does not
contain surrounding square brackets.
When called with no arguments, the
return type is `std::string`.
Otherwise, the return type and style
of output is determined by which string
token is passed.
@par Example
@code
ipv6_address::bytes_type b = {{
0, 1, 0, 2, 0, 3, 0, 4,
0, 5, 0, 6, 0, 7, 0, 8 }};
ipv6_address a(b);
assert(a.to_string() == "1:2:3:4:5:6:7:8");
assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
@endcode
@par Complexity
Constant.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
String tokens may throw exceptions.
@return The return type of the string token.
If the token parameter is omitted, then
a new `std::string` is returned.
Otherwise, the function return type
is the result type of the token.
@param token An optional string token.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
2.2. Text Representation of Addresses (rfc4291)</a>
*/
template<BOOST_URL_STRTOK_TPARAM>
BOOST_URL_STRTOK_RETURN
to_string(
BOOST_URL_STRTOK_ARG(token)) const
{
to_string_impl(token);
return token.result();
}
/** Write a dotted decimal string representing the address to a buffer
The resulting buffer is not null-terminated.
@throw std::length_error `dest_size < ipv6_address::max_str_len`
@return The formatted string
@param dest The buffer in which to write,
which must have at least `dest_size` space.
@param dest_size The size of the output buffer.
*/
BOOST_URL_DECL
core::string_view
to_buffer(
char* dest,
std::size_t dest_size) const;
/** Return true if the address is unspecified
The address 0:0:0:0:0:0:0:0 is called the
unspecified address. It indicates the
absence of an address.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2">
2.5.2. The Unspecified Address (rfc4291)</a>
*/
BOOST_URL_DECL
bool
is_unspecified() const noexcept;
/** Return true if the address is a loopback address
The unicast address 0:0:0:0:0:0:0:1 is called
the loopback address. It may be used by a node
to send an IPv6 packet to itself.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
2.5.3. The Loopback Address (rfc4291)</a>
*/
BOOST_URL_DECL
bool
is_loopback() const noexcept;
/** Return true if the address is a mapped IPv4 address
This address type is used to represent the
addresses of IPv4 nodes as IPv6 addresses.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
*/
BOOST_URL_DECL
bool
is_v4_mapped() const noexcept;
/** Return true if two addresses are equal
*/
friend
bool
operator==(
ipv6_address const& a1,
ipv6_address const& a2) noexcept
{
return a1.addr_ == a2.addr_;
}
/** Return true if two addresses are not equal
*/
friend
bool
operator!=(
ipv6_address const& a1,
ipv6_address const& a2) noexcept
{
return !( a1 == a2 );
}
/** Return an address object that represents the loopback address
The unicast address 0:0:0:0:0:0:0:1 is called
the loopback address. It may be used by a node
to send an IPv6 packet to itself.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
2.5.3. The Loopback Address (rfc4291)</a>
*/
BOOST_URL_DECL
static
ipv6_address
loopback() noexcept;
// hidden friend
friend
std::ostream&
operator<<(
std::ostream& os,
ipv6_address const& addr)
{
char buf[ipv6_address::max_str_len];
auto const s = addr.to_buffer(
buf, sizeof(buf));
os << s;
return os;
}
private:
BOOST_URL_DECL
std::size_t
print_impl(
char* dest) const noexcept;
BOOST_URL_DECL
void
to_string_impl(
string_token::arg& t) const;
bytes_type addr_{{}};
};
/** Format the address to an output stream
This function writes the address to an
output stream using standard notation.
@return The output stream, for chaining.
@param os The output stream to write to.
@param addr The address to write.
*/
std::ostream&
operator<<(
std::ostream& os,
ipv6_address const& addr);
//------------------------------------------------
/** Parse a string containing an IPv6 address.
This function attempts to parse the string
as an IPv6 address and returns a result
containing the address upon success, or
an error code if the string does not contain
a valid IPv6 address.
@par Exception Safety
Throws nothing.
@return A result containing the address.
@param s The string to parse.
*/
BOOST_URL_DECL
system::result<ipv6_address>
parse_ipv6_address(
core::string_view s) noexcept;
} // urls
} // boost
#endif
+50
View File
@@ -0,0 +1,50 @@
//
// 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_OPTIONAL_HPP
#define BOOST_URL_OPTIONAL_HPP
#include <boost/url/detail/config.hpp>
#include <boost/optional.hpp>
namespace boost {
namespace urls {
/** The type of optional used by the library
@note This alias is no longer supported and
should not be used in new code. Please use
`boost::optional` instead.
This alias is included for backwards
compatibility with earlier versions of the
library.
However, it will be removed in future releases,
and using it in new code is not recommended.
Please use the updated version instead to
ensure compatibility with future versions of
the library.
*/
#ifndef BOOST_URL_DOCS
template<class T>
using optional
BOOST_URL_DEPRECATED("Use boost::optional<T> instead") =
boost::optional<T>;
#else
template<class T>
using optional = boost::optional<T>;
#endif
} // urls
} // boost
#endif
+934
View File
@@ -0,0 +1,934 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARAM_HPP
#define BOOST_URL_PARAM_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/detail/optional_string.hpp>
#include <boost/url/pct_string_view.hpp>
#include <cstddef>
#include <string>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
struct param_pct_view;
struct param_view;
#endif
/** The type of no_value
*/
struct no_value_t
{
};
/** Constant indicating no value in a param
*/
constexpr no_value_t no_value{};
//------------------------------------------------
/** A query parameter
Objects of this type represent a single key
and value pair in a query string where a key
is always present and may be empty, while the
presence of a value is indicated by
@ref has_value equal to true.
An empty value is distinct from no value.
Depending on where the object was obtained,
the strings may or may not contain percent
escapes.
For most usages, key comparisons are
case-sensitive and duplicate keys in
a query are possible. However, it is
the authority that has final control
over how the query is interpreted.
@par BNF
@code
query-params = query-param *( "&" query-param )
query-param = key [ "=" value ]
key = *qpchar
value = *( qpchar / "=" )
@endcode
@par Specification
@li <a href="https://en.wikipedia.org/wiki/Query_string"
>Query string (Wikipedia)</a>
@see
@ref param_view,
@ref param_pct_view.
*/
struct param
{
/** The key
For most usages, key comparisons are
case-sensitive and duplicate keys in
a query are possible. However, it is
the authority that has final control
over how the query is interpreted.
*/
std::string key;
/** The value
The presence of a value is indicated by
@ref has_value equal to true.
An empty value is distinct from no value.
*/
std::string value;
/** True if a value is present
The presence of a value is indicated by
`has_value == true`.
An empty value is distinct from no value.
*/
bool has_value = false;
/** Constructor
Default constructed query parameters
have an empty key and no value.
@par Example
@code
param qp;
@endcode
@par Postconditions
@code
this->key == "" && this->value == "" && this->has_value == false
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
param() = default;
/** Constructor
Upon construction, this acquires
ownership of the members of other
via move construction. The moved
from object is as if default
constructed.
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@par other The object to construct from.
*/
param(param&& other) noexcept
: key(std::move(other.key))
, value(std::move(other.value))
, has_value(other.has_value)
{
#ifdef BOOST_URL_COW_STRINGS
// for copy-on-write std::string
other.key.clear();
other.value.clear();
#endif
other.has_value = false;
}
/** Constructor
Upon construction, this becomes a copy
of `other`.
@par Postconditions
@code
this->key == other.key && this->value == other.value && this->has_value == other.has_value
@endcode
@par Complexity
Linear in `other.key.size() + other.value.size()`.
@par Exception Safety
Calls to allocate may throw.
@par other The object to construct from.
*/
param(param const& other) = default;
/** Assignment
Upon assignment, this acquires
ownership of the members of other
via move assignment. The moved
from object is as if default
constructed.
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@par other The object to assign from.
*/
param&
operator=(param&& other) noexcept
{
key = std::move(other.key);
value = std::move(other.value);
has_value = other.has_value;
#ifdef BOOST_URL_COW_STRINGS
// for copy-on-write std::string
other.key.clear();
other.value.clear();
#endif
other.has_value = false;
return *this;
}
/** Assignment
Upon assignment, this becomes a copy
of `other`.
@par Postconditions
@code
this->key == other.key && this->value == other.value && this->has_value == other.has_value
@endcode
@par Complexity
Linear in `other.key.size() + other.value.size()`.
@par Exception Safety
Calls to allocate may throw.
@par other The object to assign from.
*/
param& operator=(
param const&) = default;
//--------------------------------------------
/** Constructor
This constructs a parameter with a key
and value.
No validation is performed on the strings.
Ownership of the key and value is acquired
by making copies.
@par Example
@code
param qp( "key", "value" );
@endcode
@code
param qp( "key", optional<core::string_view>("value") );
@endcode
@code
param qp( "key", boost::none );
@endcode
@code
param qp( "key", nullptr );
@endcode
@code
param qp( "key", no_value );
@endcode
@par Postconditions
@code
this->key == key && this->value == value && this->has_value == true
@endcode
@par Complexity
Linear in `key.size() + value.size()`.
@par Exception Safety
Calls to allocate may throw.
@tparam OptionalString An optional string
type, such as `core::string_view`,
`std::nullptr`, @ref no_value_t, or
`optional<core::string_view>`.
@param key, value The key and value to set.
*/
template <class OptionalString>
param(
core::string_view key,
OptionalString const& value)
: param(key, detail::get_optional_string(value))
{
}
/** Assignment
The members of `other` are copied,
re-using already existing string capacity.
@par Postconditions
@code
this->key == other.key && this->value == other.value && this->has_value == other.has_value
@endcode
@par Complexity
Linear in `other.key.size() + other.value.size()`.
@par Exception Safety
Calls to allocate may throw.
@param other The parameter to copy.
*/
param&
operator=(param_view const& other);
/** Assignment
The members of `other` are copied,
re-using already existing string capacity.
@par Postconditions
@code
this->key == other.key && this->value == other.value && this->has_value == other.has_value
@endcode
@par Complexity
Linear in `other.key.size() + other.value.size()`.
@par Exception Safety
Calls to allocate may throw.
@param other The parameter to copy.
*/
param&
operator=(param_pct_view const& other);
#ifndef BOOST_URL_DOCS
// arrow support
param const*
operator->() const noexcept
{
return this;
}
// aggregate construction
param(
core::string_view key,
core::string_view value,
bool has_value) noexcept
: key(key)
, value(has_value
? value
: core::string_view())
, has_value(has_value)
{
}
#endif
private:
param(
core::string_view key,
detail::optional_string const& value)
: param(key, value.s, value.b)
{
}
};
//------------------------------------------------
/** A query parameter
Objects of this type represent a single key
and value pair in a query string where a key
is always present and may be empty, while the
presence of a value is indicated by
@ref has_value equal to true.
An empty value is distinct from no value.
Depending on where the object was obtained,
the strings may or may not contain percent
escapes.
For most usages, key comparisons are
case-sensitive and duplicate keys in
a query are possible. However, it is
the authority that has final control
over how the query is interpreted.
<br>
Keys and values in this object reference
external character buffers.
Ownership of the buffers is not transferred;
the caller is responsible for ensuring that
the assigned buffers remain valid until
they are no longer referenced.
@par BNF
@code
query-params = query-param *( "&" query-param )
query-param = key [ "=" value ]
key = *qpchar
value = *( qpchar / "=" )
@endcode
@par Specification
@li <a href="https://en.wikipedia.org/wiki/Query_string"
>Query string (Wikipedia)</a>
@see
@ref param,
@ref param_pct_view.
*/
struct param_view
{
/** The key
For most usages, key comparisons are
case-sensitive and duplicate keys in
a query are possible. However, it is
the authority that has final control
over how the query is interpreted.
*/
core::string_view key;
/** The value
The presence of a value is indicated by
@ref has_value equal to true.
An empty value is distinct from no value.
*/
core::string_view value;
/** True if a value is present
The presence of a value is indicated by
`has_value == true`.
An empty value is distinct from no value.
*/
bool has_value = false;
//--------------------------------------------
/** Constructor
Default constructed query parameters
have an empty key and no value.
@par Example
@code
param_view qp;
@endcode
@par Postconditions
@code
this->key == "" && this->value == "" && this->has_value == false
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
param_view() = default;
/** Constructor
This constructs a parameter with a key
and value.
No validation is performed on the strings.
The new key and value reference
the same corresponding underlying
character buffers.
Ownership of the buffers is not transferred;
the caller is responsible for ensuring that
the assigned buffers remain valid until
they are no longer referenced.
@par Example
@code
param_view qp( "key", "value" );
@endcode
@par Postconditions
@code
this->key.data() == key.data() && this->value.data() == value.data() && this->has_value == true
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@tparam OptionalString An optional string
type, such as `core::string_view`,
`std::nullptr`, @ref no_value_t, or
`optional<core::string_view>`.
@param key, value The key and value to set.
*/
template <class OptionalString>
param_view(
core::string_view key,
OptionalString const& value) noexcept
: param_view(key, detail::get_optional_string(value))
{
}
/** Constructor
This function constructs a param
which references the character buffers
representing the key and value in another
container.
Ownership of the buffers is not transferred;
the caller is responsible for ensuring that
the assigned buffers remain valid until
they are no longer referenced.
@par Example
@code
param qp( "key", "value" );
param_view qpv( qp );
@endcode
@par Postconditions
@code
this->key == key && this->value == value && this->has_value == other.has_value
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@param other The param to reference
*/
param_view(
param const& other) noexcept
: param_view(
other.key,
other.value,
other.has_value)
{
}
/** Conversion
This function performs a conversion from
a reference-like query parameter to one
retaining ownership of the strings by
making a copy.
No validation is performed on the strings.
@par Complexity
Linear in `this->key.size() + this->value.size()`.
@par Exception Safety
Calls to allocate may throw.
*/
explicit
operator
param()
{
return { key, value, has_value };
}
#ifndef BOOST_URL_DOCS
// arrow support
param_view const*
operator->() const noexcept
{
return this;
}
// aggregate construction
param_view(
core::string_view key_,
core::string_view value_,
bool has_value_) noexcept
: key(key_)
, value(has_value_
? value_
: core::string_view())
, has_value(has_value_)
{
}
#endif
private:
param_view(
core::string_view key,
detail::optional_string const& value)
: param_view(key, value.s, value.b)
{
}
};
//------------------------------------------------
/** A query parameter
Objects of this type represent a single key
and value pair in a query string where a key
is always present and may be empty, while the
presence of a value is indicated by
@ref has_value equal to true.
An empty value is distinct from no value.
The strings may have percent escapes, and
offer an additional invariant: they never
contain an invalid percent-encoding.
For most usages, key comparisons are
case-sensitive and duplicate keys in
a query are possible. However, it is
the authority that has final control
over how the query is interpreted.
<br>
Keys and values in this object reference
external character buffers.
Ownership of the buffers is not transferred;
the caller is responsible for ensuring that
the assigned buffers remain valid until
they are no longer referenced.
@par BNF
@code
query-params = query-param *( "&" query-param )
query-param = key [ "=" value ]
key = *qpchar
value = *( qpchar / "=" )
@endcode
@par Specification
@li <a href="https://en.wikipedia.org/wiki/Query_string"
>Query string (Wikipedia)</a>
@see
@ref param,
@ref param_view.
*/
struct param_pct_view
{
/** The key
For most usages, key comparisons are
case-sensitive and duplicate keys in
a query are possible. However, it is
the authority that has final control
over how the query is interpreted.
*/
pct_string_view key;
/** The value
The presence of a value is indicated by
@ref has_value equal to true.
An empty value is distinct from no value.
*/
pct_string_view value;
/** True if a value is present
The presence of a value is indicated by
`has_value == true`.
An empty value is distinct from no value.
*/
bool has_value = false;
//--------------------------------------------
/** Constructor
Default constructed query parameters
have an empty key and no value.
@par Example
@code
param_pct_view qp;
@endcode
@par Postconditions
@code
this->key == "" && this->value == "" && this->has_value == false
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
param_pct_view() = default;
/** Constructor
This constructs a parameter with a key
and value, which may both contain percent
escapes.
The new key and value reference
the same corresponding underlying
character buffers.
Ownership of the buffers is not transferred;
the caller is responsible for ensuring that
the assigned buffers remain valid until
they are no longer referenced.
@par Example
@code
param_pct_view qp( "key", "value" );
@endcode
@par Postconditions
@code
this->key.data() == key.data() && this->value.data() == value.data() && this->has_value == true
@endcode
@par Complexity
Linear in `key.size() + value.size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` or `value` contains an invalid percent-encoding.
@param key, value The key and value to set.
*/
param_pct_view(
pct_string_view key,
pct_string_view value) noexcept
: key(key)
, value(value)
, has_value(true)
{
}
/** Constructor
This constructs a parameter with a key
and optional value, which may both
contain percent escapes.
The new key and value reference
the same corresponding underlying
character buffers.
Ownership of the buffers is not transferred;
the caller is responsible for ensuring that
the assigned buffers remain valid until
they are no longer referenced.
@par Example
@code
param_pct_view qp( "key", optional<core::string_view>("value") );
@endcode
@par Postconditions
@code
this->key.data() == key.data() && this->value->data() == value->data() && this->has_value == true
@endcode
@par Complexity
Linear in `key.size() + value->size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` or `value` contains an invalid percent-encoding.
@tparam OptionalString An optional
`core::string_view` type, such as
`boost::optional<core::string_view>` or
`std::optional<core::string_view>`.
@param key, value The key and value to set.
*/
template <class OptionalString>
param_pct_view(
pct_string_view key,
OptionalString const& value)
: param_pct_view(key, detail::get_optional_string(value))
{
}
/** Construction
This converts a param which may
contain unvalidated percent-escapes into
a param whose key and value are
guaranteed to contain strings with no
invalid percent-escapes, otherwise
an exception is thrown.
The new key and value reference
the same corresponding underlying
character buffers.
Ownership of the buffers is not transferred;
the caller is responsible for ensuring that
the assigned buffers remain valid until
they are no longer referenced.
@par Example
@code
param_pct_view qp( param_view( "key", "value" ) );
@endcode
@par Complexity
Linear in `key.size() + value.size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` or `value` contains an invalid percent escape.
@param p The param to construct from.
*/
explicit
param_pct_view(
param_view const& p)
: key(p.key)
, value(p.has_value
? pct_string_view(p.value)
: pct_string_view())
, has_value(p.has_value)
{
}
/** Conversion
This function performs a conversion from
a reference-like query parameter to one
retaining ownership of the strings by
making a copy.
@par Complexity
Linear in `this->key.size() + this->value.size()`.
@par Exception Safety
Calls to allocate may throw.
*/
explicit
operator
param() const
{
return param(
static_cast<std::string>(key),
static_cast<std::string>(value),
has_value);
}
operator
param_view() const noexcept
{
return param_view(
key, value, has_value);
}
#ifndef BOOST_URL_DOCS
// arrow support
param_pct_view const*
operator->() const noexcept
{
return this;
}
// aggregate construction
param_pct_view(
pct_string_view key,
pct_string_view value,
bool has_value) noexcept
: key(key)
, value(has_value
? value
: pct_string_view())
, has_value(has_value)
{
}
#endif
private:
param_pct_view(
pct_string_view key,
detail::optional_string const& value)
: param_pct_view(key, value.s, value.b)
{
}
};
//------------------------------------------------
inline
param&
param::
operator=(
param_view const& other)
{
// VFALCO operator= assignment
// causes a loss of original capacity:
// https://godbolt.org/z/nYef8445K
//
// key = other.key;
// value = other.value;
// preserve capacity
key.assign(
other.key.data(),
other.key.size());
value.assign(
other.value.data(),
other.value.size());
has_value = other.has_value;
return *this;
}
inline
param&
param::
operator=(
param_pct_view const& other)
{
// preserve capacity
key.assign(
other.key.data(),
other.key.size());
value.assign(
other.value.data(),
other.value.size());
has_value = other.has_value;
return *this;
}
} // urls
} // boost
#endif
+519
View File
@@ -0,0 +1,519 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARAMS_BASE_HPP
#define BOOST_URL_PARAMS_BASE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/encoding_opts.hpp>
#include <boost/url/ignore_case.hpp>
#include <boost/url/param.hpp>
#include <boost/url/detail/params_iter_impl.hpp>
#include <boost/url/detail/url_impl.hpp>
#include <iosfwd>
namespace boost {
namespace urls {
/** Common functionality for containers
This base class is used by the library
to provide common member functions for
containers. This cannot be instantiated
directly; Instead, use one of the
containers or functions:
@par Containers
@li @ref params_ref
@li @ref params_view
@li @ref params_encoded_ref
@li @ref params_encoded_view
*/
class BOOST_URL_DECL params_base
{
friend class url_view_base;
friend class params_ref;
friend class params_view;
detail::query_ref ref_;
encoding_opts opt_;
params_base() noexcept;
params_base(
detail::query_ref const& ref,
encoding_opts opt) noexcept;
params_base(
params_base const&) = default;
params_base& operator=(
params_base const&) = default;
public:
/** A Bidirectional iterator to a query parameter
Objects of this type allow iteration
through the parameters in the query.
Any percent-escapes in returned strings
are decoded first.
The values returned are read-only;
changes to parameters must be made
through the container instead, if the
container supports modification.
<br>
The strings produced when iterators are
dereferenced belong to the iterator and
become invalidated when that particular
iterator is incremented, decremented,
or destroyed.
@note
The implementation may use temporary,
recycled storage to store decoded
strings. These iterators are meant
to be used ephemerally. That is, for
short durations such as within a
function scope. Do not store
iterators with static storage
duration or as long-lived objects.
*/
#ifdef BOOST_URL_DOCS
using iterator = __see_below__;
#else
class iterator;
#endif
/// @copydoc iterator
using const_iterator = iterator;
/** The value type
Values of this type represent parameters
whose strings retain unique ownership by
making a copy.
@par Example
@code
params_view::value_type qp( *url_view( "?first=John&last=Doe" ).params().find( "first" ) );
@endcode
@see
@ref param.
*/
using value_type = param;
/** The reference type
This is the type of value returned when
iterators of the view are dereferenced.
@see
@ref param_view.
*/
using reference = param;
/// @copydoc reference
using const_reference = param;
/** An unsigned integer type to represent sizes.
*/
using size_type = std::size_t;
/** A signed integer type used to represent differences.
*/
using difference_type = std::ptrdiff_t;
//--------------------------------------------
//
// Observers
//
//--------------------------------------------
/** Return the maximum number of characters possible
This represents the largest number of
characters that are possible in a path,
not including any null terminator.
@par Exception Safety
Throws nothing.
*/
static
constexpr
std::size_t
max_size() noexcept
{
return BOOST_URL_MAX_SIZE;
}
/** Return the referenced character buffer.
This function returns the character
buffer referenced by the view.
The returned string may contain
percent escapes.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).params().buffer() == "?first=John&last=Doe" );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
pct_string_view
buffer() const noexcept;
/** Return true if there are no params
@par Example
@code
assert( ! url_view( "?key=value" ).params().empty() );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
bool
empty() const noexcept;
/** Return the number of params
@par Example
@code
assert( url_view( "?key=value").params().size() == 1 );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
std::size_t
size() const noexcept;
/** Return an iterator to the beginning
@par Complexity
Linear in the size of the first param.
@par Exception Safety
Throws nothing.
*/
iterator
begin() const noexcept;
/** Return an iterator to the end
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
iterator
end() const noexcept;
//--------------------------------------------
/** Return true if a matching key exists
This function examines the parameters
in the container to find a match for
the specified key.
The comparison is performed as if all
escaped characters were decoded first.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).params().contains( "first" ) );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@par Exception Safety
Throws nothing.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
bool
contains(
core::string_view key,
ignore_case_param ic = {}) const noexcept;
/** Return the number of matching keys
This function examines the
parameters in the container to
find the number of matches for
the specified key.
The comparison is performed as if all
escaped characters were decoded first.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).params().count( "first" ) == 1 );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@par Exception Safety
Throws nothing.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
std::size_t
count(
core::string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the parameters
in the container to find a match for
the specified key.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts from the first param
and proceeds forward until either the
key is found or the end of the range is
reached, in which case `end()` is
returned.
@par Example
@code
assert( (*url_view( "?first=John&last=Doe" ).params().find( "First", ignore_case )).value == "John" );
@endcode
@par Effects
@code
return this->find( this->begin(), key, ic );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@return an iterator to the param
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find(
core::string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the
parameters in the container to
find a match for the specified key.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts at `from`
and proceeds forward until either the
key is found or the end of the range is
reached, in which case `end()` is
returned.
@par Example
@code
url_view u( "?First=John&Last=Doe" );
assert( u.params().find( "first" ) != u.params().find( "first", ignore_case ) );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@return an iterator to the param
@param from The position to begin the
search from. This can be `end()`.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find(
iterator from,
core::string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the
parameters in the container to
find a match for the specified key.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts from the last param
and proceeds backwards until either the
key is found or the beginning of the
range is reached, in which case `end()`
is returned.
@par Example
@code
assert( (*url_view( "?first=John&last=Doe" ).params().find_last( "last" )).value == "Doe" );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@return an iterator to the param
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find_last(
core::string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the
parameters in the container to
find a match for the specified key.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts prior to `before`
and proceeds backwards until either the
key is found or the beginning of the
range is reached, in which case `end()`
is returned.
@par Example
@code
url_view u( "?First=John&Last=Doe" );
assert( u.params().find_last( "last" ) != u.params().find_last( "last", ignore_case ) );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@return an iterator to the param
@param before One past the position
to begin the search from. This can
be `end()`.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find_last(
iterator before,
core::string_view key,
ignore_case_param ic = {}) const noexcept;
private:
detail::params_iter_impl
find_impl(
detail::params_iter_impl,
core::string_view,
ignore_case_param) const noexcept;
detail::params_iter_impl
find_last_impl(
detail::params_iter_impl,
core::string_view,
ignore_case_param) const noexcept;
};
//------------------------------------------------
/** Format to an output stream
Any percent-escapes are emitted as-is;
no decoding is performed.
@par Complexity
Linear in `ps.buffer().size()`.
@par Effects
@code
return os << ps.buffer();
@endcode
*/
BOOST_URL_DECL
std::ostream&
operator<<(
std::ostream& os,
params_base const& qp);
} // urls
} // boost
#include <boost/url/impl/params_base.hpp>
#endif
+549
View File
@@ -0,0 +1,549 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARAMS_ENCODED_BASE_HPP
#define BOOST_URL_PARAMS_ENCODED_BASE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/ignore_case.hpp>
#include <boost/url/param.hpp>
#include <boost/url/detail/params_iter_impl.hpp>
#include <boost/url/detail/url_impl.hpp>
#include <iosfwd>
namespace boost {
namespace urls {
/** Common functionality for containers
This base class is used by the library
to provide common member functions for
containers. This cannot be instantiated
directly; Instead, use one of the
containers or functions:
@par Containers
@li @ref params_ref
@li @ref params_view
@li @ref params_encoded_ref
@li @ref params_encoded_view
*/
class BOOST_URL_DECL params_encoded_base
{
friend class url_view_base;
friend class params_encoded_ref;
friend class params_encoded_view;
detail::query_ref ref_;
params_encoded_base() = default;
params_encoded_base(
params_encoded_base const&) = default;
params_encoded_base& operator=(
params_encoded_base const&) = default;
params_encoded_base(
detail::query_ref const& ref) noexcept;
public:
/** A Bidirectional iterator to a query parameter
Objects of this type allow iteration
through the parameters in the query.
Strings returned by iterators may
contain percent escapes.
The values returned are read-only;
changes to parameters must be made
through the container instead, if the
container supports modification.
<br>
The strings produced when iterators
are dereferenced refer to the 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 by any
container or iterator.
*/
#ifdef BOOST_URL_DOCS
using iterator = __see_below__;
#else
class iterator;
#endif
/// @copydoc iterator
using const_iterator = iterator;
/** The value type
Values of this type represent parameters
whose strings retain unique ownership by
making a copy.
@par Example
@code
params_encoded_view::value_type qp( *url_view( "?first=John&last=Doe" ).params().find( "first" ) );
@endcode
@see
@ref param.
*/
using value_type = param;
/** The reference type
This is the type of value returned when
iterators of the view are dereferenced.
@see
@ref param_view.
*/
using reference = param_pct_view;
/// @copydoc reference
using const_reference = param_pct_view;
/** An unsigned integer type to represent sizes.
*/
using size_type = std::size_t;
/** A signed integer type used to represent differences.
*/
using difference_type = std::ptrdiff_t;
//--------------------------------------------
//
// Observers
//
//--------------------------------------------
/** Return the maximum number of characters possible
This represents the largest number of
characters that are possible in a path,
not including any null terminator.
@par Exception Safety
Throws nothing.
*/
static
constexpr
std::size_t
max_size() noexcept
{
return BOOST_URL_MAX_SIZE;
}
/** Return the query corresponding to these params
This function returns the query string
referenced by the container.
The returned string may contain
percent escapes.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).encoded_params().buffer() == "first=John&last=Doe" );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@par BNF
@code
query-params = query-param *( "&" query-param )
query-param = key [ "=" value ]
key = *qpchar
value = *( qpchar / "=" )
@endcode
@par Specification
@li <a href="https://en.wikipedia.org/wiki/Query_string"
>Query string (Wikipedia)</a>
*/
pct_string_view
buffer() const noexcept;
/** Return true if there are no params
@par Example
@code
assert( ! url_view( "?key=value" ).encoded_params().empty() );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
bool
empty() const noexcept;
/** Return the number of params
@par Example
@code
assert( url_view( "?key=value").encoded_params().size() == 1 );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
std::size_t
size() const noexcept;
/** Return an iterator to the beginning
@par Complexity
Linear in the size of the first param.
@par Exception Safety
Throws nothing.
*/
iterator
begin() const noexcept;
/** Return an iterator to the end
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
iterator
end() const noexcept;
//--------------------------------------------
/** Return true if a matching key exists
This function examines the parameters
in the container to find a match for
the specified key,
which may contain percent escapes.
The comparison is performed as if all
escaped characters were decoded first.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).encoded_params().contains( "first" ) );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` contains an invalid percent-encoding.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
bool
contains(
pct_string_view key,
ignore_case_param ic = {}) const noexcept;
/** Return the number of matching keys
This function examines the parameters
in the container to find the number of
matches for the specified key,
which may contain percent escapes.
The comparison is performed as if all
escaped characters were decoded first.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).encoded_params().count( "first" ) == 1 );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` contains an invalid percent-encoding.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
std::size_t
count(
pct_string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the parameters
in the container to find a match for
the specified key,
which may contain percent escapes.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts from the first param
and proceeds forward until either the
key is found or the end of the range is
reached, in which case `end()` is
returned.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).encoded_params().find( "First", ignore_case )->value == "John" );
@endcode
@par Effects
@code
return this->find( this->begin(), key, ic );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` contains an invalid percent-encoding.
@return an iterator to the param
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find(
pct_string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the parameters
in the container to find a match for
the specified key, which may contain
percent escapes.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts at `from`
and proceeds forward until either the
key is found or the end of the range is
reached, in which case `end()` is
returned.
@par Example
@code
url_view u( "?First=John&Last=Doe" );
assert( u.encoded_params().find( "first" ) != u.encoded_params().find( "first", ignore_case ) );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` contains an invalid percent-encoding.
@return an iterator to the param
@param from The position to begin the
search from. This can be `end()`.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find(
iterator from,
pct_string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the parameters
in the container to find a match for
the specified key, which may contain
percent escapes.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts from the last param
and proceeds backwards until either the
key is found or the beginning of the
range is reached, in which case `end()`
is returned.
@par Example
@code
assert( url_view( "?first=John&last=Doe" ).encoded_params().find_last( "last" )->value == "Doe" );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`key` contains an invalid percent-encoding.
@return an iterator to the param
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find_last(
pct_string_view key,
ignore_case_param ic = {}) const noexcept;
/** Find a matching key
This function examines the parameters
in the container to find a match for
the specified key, which may contain
percent escapes.
The comparison is performed as if all
escaped characters were decoded first.
<br>
The search starts prior to `before`
and proceeds backwards until either the
key is found or the beginning of the
range is reached, in which case `end()`
is returned.
@par Example
@code
url_view u( "?First=John&Last=Doe" );
assert( u.encoded_params().find_last( "last" ) != u.encoded_params().find_last( "last", ignore_case ) );
@endcode
@par Complexity
Linear in `this->buffer().size()`.
@return an iterator to the param
@param before One past the position
to begin the search from. This can
be `end()`.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
find_last(
iterator before,
pct_string_view key,
ignore_case_param ic = {}) const noexcept;
private:
detail::params_iter_impl
find_impl(
detail::params_iter_impl,
pct_string_view,
ignore_case_param) const noexcept;
detail::params_iter_impl
find_last_impl(
detail::params_iter_impl,
pct_string_view,
ignore_case_param) const noexcept;
};
//------------------------------------------------
/** Format to an output stream
Any percent-escapes are emitted as-is;
no decoding is performed.
@par Complexity
Linear in `ps.buffer().size()`.
@par Effects
@code
return os << ps.buffer();
@endcode
*/
BOOST_URL_DECL
std::ostream&
operator<<(
std::ostream& os,
params_encoded_base const& qp);
} // urls
} // boost
#include <boost/url/impl/params_encoded_base.hpp>
#endif
File diff suppressed because it is too large Load Diff
+237
View File
@@ -0,0 +1,237 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARAMS_ENCODED_VIEW_HPP
#define BOOST_URL_PARAMS_ENCODED_VIEW_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/params_encoded_base.hpp>
#include <boost/url/params_view.hpp>
#include <boost/core/detail/string_view.hpp>
#include <iosfwd>
#include <utility>
namespace boost {
namespace urls {
/** A view representing query parameters in a URL
Objects of this type are used to interpret
the query parameters as a bidirectional view
of key/value pairs.
The view does not retain ownership of the
elements and instead references the original
character buffer. The caller is responsible
for ensuring that the lifetime of the buffer
extends until it is no longer referenced.
@par Example
@code
url_view u( "?first=John&last=Doe" );
params_encoded_view p = u.encoded_params();
@endcode
Strings produced when elements are returned
have type @ref param_pct_view and represent
encoded strings. Strings passed to member
functions may contain percent escapes, and
throw exceptions on invalid inputs.
@par Iterator Invalidation
Changes to the underlying character buffer
can invalidate iterators which reference it.
*/
class BOOST_URL_DECL params_encoded_view
: public params_encoded_base
{
friend class url_view_base;
friend class params_view;
friend class params_encoded_ref;
friend struct query_rule_t;
params_encoded_view(
detail::query_ref const& ref) noexcept;
public:
/** Constructor
Default-constructed params have
zero elements.
@par Example
@code
params_encoded_view qp;
@endcode
@par Effects
@code
return params_encoded_view( "" );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
params_encoded_view() = default;
/** Constructor
After construction both views
reference the same character buffer.
Ownership is not transferred; the caller
is responsible for ensuring the lifetime
of the buffer extends until it is no
longer referenced.
@par Postconditions
@code
this->buffer().data() == other.buffer().data()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing
*/
params_encoded_view(
params_encoded_view const& other) = default;
/** Constructor
This function constructs params from
a valid query parameter string, which
can contain percent escapes. Unlike
the parameters in URLs, the string
passed here should not start with "?".
Upon construction, the view
references the character buffer pointed
to by `s`. The caller is responsible
for ensuring that the lifetime of the
buffer extends until it is no longer
referenced.
@par Example
@code
params_encoded_view qp( "first=John&last=Doe" );
@endcode
@par Effects
@code
return parse_query( s ).value();
@endcode
@par Postconditions
@code
this->buffer().data() == s.data()
@endcode
@par Complexity
Linear in `s`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`s` contains an invalid query parameter
string.
@param s The string to parse.
@par BNF
@code
query-params = [ query-param ] *( "&" query-param )
query-param = key [ "=" value ]
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.4"
>3.4. Query</a>
*/
params_encoded_view(
core::string_view s);
/** Assignment
After assignment, both views
reference the same underlying character
buffer.
Ownership is not transferred; the caller
is responsible for ensuring the lifetime
of the buffer extends until it is no
longer referenced.
@par Postconditions
@code
this->buffer().data() == other.buffer().data()
@endcode
@par Complexity
Constant
@par Exception Safety
Throws nothing
*/
params_encoded_view&
operator=(
params_encoded_view const&) = default;
/** Conversion
This conversion returns a new view which
references the same underlying character
buffer, and whose iterators and members
return ordinary strings with decoding
applied to any percent escapes.
Ownership is not transferred; the caller
is responsible for ensuring the lifetime
of the buffer extends until it is no
longer referenced.
@par Example
@code
params_view qp = parse_path( "/path/to/file.txt" ).value();
@endcode
@par Postconditions
@code
params_view( *this ).buffer().data() == this->buffer().data()
@endcode
@par Complexity
Constant
@par Exception Safety
Throws nothing
*/
operator
params_view() const noexcept;
//--------------------------------------------
friend
BOOST_URL_DECL
system::result<params_encoded_view>
parse_query(core::string_view s) noexcept;
};
} // urls
} // boost
#endif
+967
View File
@@ -0,0 +1,967 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARAMS_REF_HPP
#define BOOST_URL_PARAMS_REF_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/ignore_case.hpp>
#include <boost/url/params_base.hpp>
#include <initializer_list>
#include <iterator>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
class url_base;
class params_view;
#endif
/** A view representing query parameters in a URL
Objects of this type are used to interpret
the query parameters as a bidirectional view
of key/value pairs.
The view does not retain ownership of the
elements and instead references the original
url. The caller is responsible for ensuring
that the lifetime of the referenced url
extends until it is no longer referenced.
The view is modifiable; calling non-const
members causes changes to the referenced
url.
<br>
Percent escapes in strings returned when
dereferencing iterators are automatically
decoded.
Reserved characters in strings supplied
to modifier functions are automatically
percent-escaped.
@par Example
@code
url u( "?first=John&last=Doe" );
params_ref p = u.params();
@endcode
@par Iterator Invalidation
Changes to the underlying character buffer
can invalidate iterators which reference it.
Modifications made through the container
invalidate some or all iterators:
<br>
@li @ref append : Only `end()`.
@li @ref assign, @ref clear,
`operator=` : All elements.
@li @ref erase : Erased elements and all
elements after (including `end()`).
@li @ref insert : All elements at or after
the insertion point (including `end()`).
@li @ref replace, @ref set : Modified
elements and all elements
after (including `end()`).
*/
class BOOST_URL_DECL params_ref
: public params_base
{
friend class url_base;
url_base* u_ = nullptr;
params_ref(
url_base& u,
encoding_opts opt) noexcept;
public:
//--------------------------------------------
//
// Special Members
//
//--------------------------------------------
/** Constructor
After construction, both views
reference the same url. Ownership is not
transferred; the caller is responsible
for ensuring the lifetime of the url
extends until it is no longer
referenced.
@par Postconditions
@code
&this->url() == &other.url()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@param other The other view.
*/
params_ref(
params_ref const& other) = default;
/** Constructor
After construction, both views will
reference the same url but this
instance will use the specified
@ref encoding_opts when the values
are decoded.
Ownership is not transferred; the
caller is responsible for ensuring
the lifetime of the url extends
until it is no longer referenced.
@par Postconditions
@code
&this->url() == &other.url()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@param other The other view.
@param opt The options for decoding. If
this parameter is omitted, `space_as_plus`
is used.
*/
params_ref(
params_ref const& other,
encoding_opts opt) noexcept;
/** Assignment
The previous contents of this are
replaced by the contents of `other.
<br>
All iterators are invalidated.
@note
The strings referenced by `other`
must not come from the underlying url,
or else the behavior is undefined.
@par Effects
@code
this->assign( other.begin(), other.end() );
@endcode
@par Complexity
Linear in `other.buffer().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param other The params to assign.
*/
params_ref&
operator=(
params_ref const& other);
/** Assignment
After assignment, the previous contents
of the query parameters are replaced by
the contents of the initializer-list.
@par Preconditions
None of character buffers referenced by
`init` may overlap the character buffer of
the underlying url, or else the behavior
is undefined.
@par Effects
@code
this->assign( init );
@endcode
@par Complexity
Linear in `init.size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param init The list of params to assign.
*/
params_ref&
operator=(
std::initializer_list<
param_view> init);
/** Conversion
*/
operator
params_view() const noexcept;
//--------------------------------------------
//
// Observers
//
//--------------------------------------------
/** Return the referenced url
This function returns the url referenced
by the view.
@par Example
@code
url u( "?key=value" );
assert( &u.segments().url() == &u );
@endcode
@par Exception Safety
@code
Throws nothing.
@endcode
*/
url_base&
url() const noexcept
{
return *u_;
}
//--------------------------------------------
//
// Modifiers
//
//--------------------------------------------
/** Clear the contents of the container
<br>
All iterators are invalidated.
@par Effects
@code
this->url().remove_query();
@endcode
@par Postconditions
@code
this->empty() == true && this->url().has_query() == false
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
void
clear() noexcept;
//--------------------------------------------
/** Assign elements
This function replaces the entire
contents of the view with the params
in the <em>initializer-list</em>.
<br>
All iterators are invalidated.
@note
The strings referenced by the inputs
must not come from the underlying url,
or else the behavior is undefined.
@par Example
@code
url u;
u.params().assign( {{ "first", "John" }, { "last", "Doe" }} );
@endcode
@par Complexity
Linear in `init.size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param init The list of params to assign.
*/
void
assign(
std::initializer_list<
param_view> init);
/** Assign elements
This function replaces the entire
contents of the view with the params
in the range.
<br>
All iterators are invalidated.
@note
The strings referenced by the inputs
must not come from the underlying url,
or else the behavior is undefined.
@par Mandates
@code
std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
@endcode
@par Complexity
Linear in the size of the range.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param first, last The range of params
to assign.
*/
template<class FwdIt>
void
assign(FwdIt first, FwdIt last);
//--------------------------------------------
/** Append elements
This function appends a param to the view.
<br>
The `end()` iterator is invalidated.
@par Example
@code
url u;
u.params().append( { "first", "John" } );
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the new element.
@param p The param to append.
*/
iterator
append(
param_view const& p);
/** Append elements
This function appends the params in
an <em>initializer-list</em> to the view.
<br>
The `end()` iterator is invalidated.
@par Example
@code
url u;
u.params().append({ { "first", "John" }, { "last", "Doe" } });
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the first new element.
@param init The list of params to append.
*/
iterator
append(
std::initializer_list<
param_view> init);
/** Append elements
This function appends a range of params
to the view.
<br>
The `end()` iterator is invalidated.
@note
The strings referenced by the inputs
must not come from the underlying url,
or else the behavior is undefined.
@par Mandates
@code
std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the first new element.
@param first, last The range of params
to append.
*/
template<class FwdIt>
iterator
append(
FwdIt first, FwdIt last);
//--------------------------------------------
/** Insert elements
This function inserts a param
before the specified position.
<br>
All iterators that are equal to
`before` or come after are invalidated.
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the inserted
element.
@param before An iterator before which
the param is inserted. This may
be equal to `end()`.
@param p The param to insert.
*/
iterator
insert(
iterator before,
param_view const& p);
/** Insert elements
This function inserts the params in
an <em>initializer-list</em> before
the specified position.
<br>
All iterators that are equal to
`before` or come after are invalidated.
@note
The strings referenced by the inputs
must not come from the underlying url,
or else the behavior is undefined.
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the first
element inserted, or `before` if
`init.size() == 0`.
@param before An iterator before which
the element is inserted. This may
be equal to `end()`.
@param init The list of params to insert.
*/
iterator
insert(
iterator before,
std::initializer_list<
param_view> init);
/** Insert elements
This function inserts a range of
params before the specified position.
<br>
All iterators that are equal to
`before` or come after are invalidated.
@note
The strings referenced by the inputs
must not come from the underlying url,
or else the behavior is undefined.
@par Mandates
@code
std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the first
element inserted, or `before` if
`first == last`.
@param before An iterator before which
the element is inserted. This may
be equal to `end()`.
@param first, last The range of params
to insert.
*/
template<class FwdIt>
iterator
insert(
iterator before,
FwdIt first,
FwdIt last);
//--------------------------------------------
/** Erase elements
This function removes an element from
the container.
<br>
All iterators that are equal to
`pos` or come after are invalidated.
@par Example
@code
url u( "?first=John&last=Doe" );
params_ref::iterator it = u.params().erase( u.params().begin() );
assert( u.encoded_query() == "last=Doe" );
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Throws nothing.
@return An iterator to one past
the removed element.
@param pos An iterator to the element.
*/
iterator
erase(iterator pos) noexcept;
/** Erase elements
This function removes a range of elements
from the container.
<br>
All iterators that are equal to
`first` or come after are invalidated.
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Throws nothing.
@return An iterator to one past
the removed range.
@param first, last The range of
elements to erase.
*/
iterator
erase(
iterator first,
iterator last) noexcept;
/** Erase elements
<br>
All iterators are invalidated.
@par Postconditions
@code
this->count( key, ic ) == 0
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Throws nothing.
@return The number of elements removed
from the container.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
std::size_t
erase(
core::string_view key,
ignore_case_param ic = {}) noexcept;
//--------------------------------------------
/** Replace elements
This function replaces the contents
of the element at `pos` with the
specified param.
<br>
All iterators that are equal to
`pos` or come after are invalidated.
@par Example
@code
url u( "?first=John&last=Doe" );
u.params().replace( u.params().begin(), { "title", "Mr" });
assert( u.encoded_query() == "title=Mr&last=Doe" );
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the element.
@param pos An iterator to the element.
@param p The param to assign.
*/
iterator
replace(
iterator pos,
param_view const& p);
/** Replace elements
This function replaces a range of
elements with the params in an
<em>initializer-list</em>.
<br>
All iterators that are equal to
`from` or come after are invalidated.
@note
The strings referenced by the inputs
must not come from the underlying url,
or else the behavior is undefined.
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the first
element inserted, or one past `to` if
`init.size() == 0`.
@param from,to The range of elements
to replace.
@param init The list of params to assign.
*/
iterator
replace(
iterator from,
iterator to,
std::initializer_list<
param_view> init);
/** Replace elements
This function replaces a range of
elements with a range of params.
<br>
All iterators that are equal to
`from` or come after are invalidated.
@note
The strings referenced by the inputs
must not come from the underlying url,
or else the behavior is undefined.
@par Mandates
@code
std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_view >::value == true
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the first
element inserted, or one past `to` if
`first == last`.
@param from,to The range of elements to
replace.
@param first, last The range of params
to assign.
*/
template<class FwdIt>
iterator
replace(
iterator from,
iterator to,
FwdIt first,
FwdIt last);
//--------------------------------------------
/** Remove the value on an element
This function removes the value of
an element at the specified position.
After the call returns, `has_value`
for the element is false.
<br>
All iterators that are equal to
`pos` or come after are invalidated.
@par Example
@code
url u( "?first=John&last=Doe" );
u.params().unset( u.params().begin() );
assert( u.encoded_query() == "first&last=Doe" );
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Throws nothing.
@return An iterator to the element.
@param pos An iterator to the element.
*/
iterator
unset(
iterator pos) noexcept;
/** Set a value
This function replaces the value of an
element at the specified position.
<br>
All iterators that are equal to
`pos` or come after are invalidated.
@par Example
@code
url u( "?id=42&id=69" );
u.params().set( u.params().begin(), "none" );
assert( u.encoded_query() == "id=none&id=69" );
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the element.
@param pos An iterator to the element.
@param value The value to assign. The
empty string still counts as a value.
That is, `has_value` for the element
is true.
*/
iterator
set(
iterator pos,
core::string_view value);
/** Set a value
This function performs one of two
actions depending on the value of
`this->contains( key, ic )`.
@li If key is contained in the view
then one of the matching elements has
its value changed to the specified value.
The remaining elements with a matching
key are erased. Otherwise,
@li If `key` is not contained in the
view, then the function apppends the
param `{ key, value }`.
<br>
All iterators are invalidated.
@par Example
@code
url u( "?id=42&id=69" );
u.params().set( "id", "none" );
assert( u.params().count( "id" ) == 1 );
@endcode
@par Postconditions
@code
this->count( key, ic ) == 1 && this->find( key, ic )->value == value
@endcode
@par Complexity
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return An iterator to the appended
or modified element.
@param key The key to match.
By default, a case-sensitive
comparison is used.
@param value The value to assign. The
empty string still counts as a value.
That is, `has_value` for the element
is true.
@param ic An optional parameter. If
the value @ref ignore_case is passed
here, the comparison is
case-insensitive.
*/
iterator
set(
core::string_view key,
core::string_view value,
ignore_case_param ic = {});
//--------------------------------------------
private:
detail::params_iter_impl
find_impl(
detail::params_iter_impl,
core::string_view,
ignore_case_param) const noexcept;
detail::params_iter_impl
find_last_impl(
detail::params_iter_impl,
core::string_view,
ignore_case_param) const noexcept;
template<class FwdIt>
void
assign(FwdIt first, FwdIt last,
std::forward_iterator_tag);
// Doxygen cannot render ` = delete`
template<class FwdIt>
void
assign(FwdIt first, FwdIt last,
std::input_iterator_tag) = delete;
template<class FwdIt>
iterator
insert(
iterator before,
FwdIt first,
FwdIt last,
std::forward_iterator_tag);
// Doxygen cannot render ` = delete`
template<class FwdIt>
iterator
insert(
iterator before,
FwdIt first,
FwdIt last,
std::input_iterator_tag) = delete;
};
} // urls
} // boost
// This is in <boost/url/url_base.hpp>
//
// #include <boost/url/impl/params_ref.hpp>
#endif
+286
View File
@@ -0,0 +1,286 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARAMS_VIEW_HPP
#define BOOST_URL_PARAMS_VIEW_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/params_base.hpp>
namespace boost {
namespace urls {
/** A view representing query parameters in a URL
Objects of this type are used to interpret
the query parameters as a bidirectional view
of key/value pairs.
The view does not retain ownership of the
elements and instead references the original
character buffer. The caller is responsible
for ensuring that the lifetime of the buffer
extends until it is no longer referenced.
@par Example
@code
url_view u( "?first=John&last=Doe" );
params_view p = u.params();
@endcode
Percent escapes in strings returned when
dereferencing iterators are automatically
decoded.
@par Iterator Invalidation
Changes to the underlying character buffer
can invalidate iterators which reference it.
*/
class params_view
: public params_base
{
friend class url_view_base;
friend class params_encoded_view;
friend class params_ref;
params_view(
detail::query_ref const& ref,
encoding_opts opt) noexcept;
public:
/** Constructor
Default-constructed params have
zero elements.
@par Example
@code
params_view qp;
@endcode
@par Effects
@code
return params_view( "" );
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
params_view() = default;
/** Constructor
After construction both views reference
the same character buffer.
Ownership is not transferred; the caller
is responsible for ensuring the lifetime
of the buffer extends until it is no
longer referenced.
@par Postconditions
@code
this->buffer().data() == other.buffer().data()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing
*/
params_view(
params_view const& other) = default;
/** Constructor
After construction both views will
reference the same character buffer
but this instance will use the specified
@ref encoding_opts when the values
are decoded.
Ownership is not transferred; the caller
is responsible for ensuring the lifetime
of the buffer extends until it is no
longer referenced.
@par Postconditions
@code
this->buffer().data() == other.buffer().data()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing
*/
params_view(
params_view const& other,
encoding_opts opt) noexcept;
/** Constructor
This function constructs params from
a valid query parameter string, which
can contain percent escapes. Unlike
the parameters in URLs, the string
passed here should not start with "?".
Upon construction, the view references
the character buffer pointed to by `s`.
The caller is responsible for ensuring
that the lifetime of the buffer extends
until it is no longer referenced.
@par Example
@code
params_view qp( "first=John&last=Doe" );
@endcode
@par Effects
@code
return parse_query( s ).value();
@endcode
@par Postconditions
@code
this->buffer().data() == s.data()
@endcode
@par Complexity
Linear in `s`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`s` contains an invalid query parameter
string.
@param s The string to parse.
@par BNF
@code
query-params = [ query-param ] *( "&" query-param )
query-param = key [ "=" value ]
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.4"
>3.4. Query</a>
*/
BOOST_URL_DECL
params_view(
core::string_view s);
/** Constructor
This function constructs params from
a valid query parameter string, which
can contain percent escapes.
This instance will use the specified
@ref encoding_opts when the values
are decoded.
Unlike the parameters in URLs, the string
passed here should not start with "?".
Upon construction, the view will
reference the character buffer pointed
to by `s`. The caller is responsible
for ensuring that the lifetime of the
buffer extends until it is no longer
referenced.
@par Example
@code
encoding_opts opt;
opt.space_as_plus = true;
params_view qp( "name=John+Doe", opt );
@endcode
@par Effects
@code
return params_view(parse_query( s ).value(), opt);
@endcode
@par Postconditions
@code
this->buffer().data() == s.data()
@endcode
@par Complexity
Linear in `s`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
`s` contains an invalid query parameter
string.
@param s The string to parse.
@param opt The options for decoding. If
this parameter is omitted, `space_as_plus`
is used.
@par BNF
@code
query-params = [ query-param ] *( "&" query-param )
query-param = key [ "=" value ]
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.4"
>3.4. Query</a>
*/
BOOST_URL_DECL
params_view(
core::string_view s,
encoding_opts opt);
/** Assignment
After assignment, both views reference
the same underlying character buffer.
Ownership is not transferred; the caller
is responsible for ensuring the lifetime
of the buffer extends until it is no
longer referenced.
@par Postconditions
@code
this->buffer().data() == other.buffer().data()
@endcode
@par Complexity
Constant
@par Exception Safety
Throws nothing
*/
params_view&
operator=(
params_view const&) = default;
};
} // urls
} // boost
#endif
+284
View File
@@ -0,0 +1,284 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARSE_HPP
#define BOOST_URL_PARSE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/url_view.hpp>
namespace boost {
namespace urls {
/** Return a reference to a parsed URL string
This function parses a string according
to the grammar below and returns a view
referencing the passed string upon success,
else returns an error.
Ownership of the string is not transferred;
the caller is responsible for ensuring that
the lifetime of the character buffer extends
until the view is no longer being accessed.
@par Example
@code
system::result< url_view > rv = parse_absolute_uri( "http://example.com/index.htm?id=1" );
@endcode
@par BNF
@code
absolute-URI = scheme ":" hier-part [ "?" query ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
@endcode
@throw std::length_error `s.size() > url_view::max_size`
@return A @ref result containing a value or an error
@param s The string to parse
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.3"
>4.3. Absolute URI (rfc3986)</a>
@see
@ref parse_origin_form,
@ref parse_relative_ref,
@ref parse_uri,
@ref parse_uri_reference,
@ref url_view.
*/
BOOST_URL_DECL
system::result<url_view>
parse_absolute_uri(
core::string_view s);
//------------------------------------------------
/** Return a reference to a parsed URL string
This function parses a string according
to the grammar below and returns a view
referencing the passed string upon success,
else returns an error.
Ownership of the string is not transferred;
the caller is responsible for ensuring that
the lifetime of the character buffer extends
until the view is no longer being accessed.
@par Example
@code
system::result< url_view > = parse_origin_form( "/index.htm?layout=mobile" );
@endcode
@par BNF
@code
origin-form = absolute-path [ "?" query ]
absolute-path = 1*( "/" segment )
@endcode
@throw std::length_error `s.size() > url_view::max_size`
@return A @ref result containing a value or an error
@param s The string to parse
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1"
>5.3.1. origin-form (rfc7230)</a>
@see
@ref parse_absolute_uri,
@ref parse_relative_ref,
@ref parse_uri,
@ref parse_uri_reference,
@ref url_view.
*/
BOOST_URL_DECL
system::result<url_view>
parse_origin_form(
core::string_view s);
//------------------------------------------------
/** Return a reference to a parsed URL string
This function parses a string according
to the grammar below and returns a view
referencing the passed string upon success,
else returns an error.
Ownership of the string is not transferred;
the caller is responsible for ensuring that
the lifetime of the character buffer extends
until the view is no longer being accessed.
@par Example
@code
system::result< url_view > = parse_relative_ref( "images/dot.gif?v=hide#a" );
@endcode
@par BNF
@code
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
relative-part = "//" authority path-abempty
/ path-absolute
/ path-noscheme
/ path-abempty
/ path-empty
@endcode
@return A @ref result containing a value or an error
@param s The string to parse
@throw std::length_error `s.size() > url_view::max_size`
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.2"
>4.2. Relative Reference (rfc3986)</a>
@li <a href="https://www.rfc-editor.org/errata/eid5428"
>Errata ID: 5428 (rfc3986)</a>
@see
@ref parse_absolute_uri,
@ref parse_origin_form,
@ref parse_uri,
@ref parse_uri_reference,
@ref url_view.
*/
BOOST_URL_DECL
system::result<url_view>
parse_relative_ref(
core::string_view s);
//------------------------------------------------
/** Return a reference to a parsed URL string
This function parses a string according
to the grammar below and returns a view
referencing the passed string upon success,
else returns an error.
Ownership of the string is not transferred;
the caller is responsible for ensuring that
the lifetime of the character buffer extends
until the view is no longer being accessed.
@par Example
@code
system::result< url_view > = parse_uri( "https://www.example.com/index.htm?id=guest#s1" );
@endcode
@par BNF
@code
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
@endcode
@throw std::length_error `s.size() > url_view::max_size`
@return A @ref result containing a value or an error
@param s The string to parse
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3"
>3. Syntax Components (rfc3986)</a>
@see
@ref parse_absolute_uri,
@ref parse_origin_form,
@ref parse_relative_ref,
@ref parse_uri_reference,
@ref url_view.
*/
BOOST_URL_DECL
system::result<url_view>
parse_uri(
core::string_view s);
//------------------------------------------------
/** Return a reference to a parsed URL string
This function parses a string according
to the grammar below and returns a view
referencing the passed string upon success,
else returns an error.
Ownership of the string is not transferred;
the caller is responsible for ensuring that
the lifetime of the character buffer extends
until the view is no longer being accessed.
@par Example
@code
system::result< url_view > = parse_uri_reference( "ws://echo.example.com/?name=boost#demo" );
@endcode
@par BNF
@code
URI-reference = URI / relative-ref
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
relative-part = "//" authority path-abempty
/ path-absolute
/ path-noscheme
/ path-abempty
/ path-empty
@endcode
@throw std::length_error `s.size() > url_view::max_size`
@return A @ref result containing a value or an error
@param s The string to parse
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.1"
>4.1. URI Reference (rfc3986)</a>
@li <a href="https://www.rfc-editor.org/errata/eid5428"
>Errata ID: 5428 (rfc3986)</a>
@see
@ref parse_absolute_uri,
@ref parse_origin_form,
@ref parse_relative_ref,
@ref parse_uri,
@ref url_view.
*/
BOOST_URL_DECL
system::result<url_view>
parse_uri_reference(
core::string_view s);
} // url
} // boost
#endif
+54
View File
@@ -0,0 +1,54 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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_PARSE_PATH_HPP
#define BOOST_URL_PARSE_PATH_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/segments_encoded_view.hpp>
namespace boost {
namespace urls {
/** Parse a string and return an encoded segment view
This function parses the string and returns the
corresponding path object if the string is valid,
otherwise returns an error.
@par BNF
@code
path = [ "/" ] segment *( "/" segment )
@endcode
@par Exception Safety
No-throw guarantee.
@return A valid view on success, otherwise an
error code.
@param s The string to parse
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.3"
>3.3. Path (rfc3986)</a>
@see
@ref segments_encoded_view.
*/
BOOST_URL_DECL
system::result<segments_encoded_view>
parse_path(core::string_view s) noexcept;
} // urls
} // boost
#endif
+52
View File
@@ -0,0 +1,52 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/CPPAlliance/url
//
#ifndef BOOST_URL_PARSE_PARAMS_HPP
#define BOOST_URL_PARSE_PARAMS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/params_encoded_view.hpp>
#include <boost/core/detail/string_view.hpp>
namespace boost {
namespace urls {
/** Parse a string and return an encoded params view
This function parses the string and returns the
corresponding params object if the string is valid,
otherwise returns an error.
@par BNF
@code
@endcode
@par Exception Safety
No-throw guarantee.
@return A valid view on success, otherwise an
error code.
@param s The string to parse
@par Specification
@see
@ref params_encoded_view.
*/
BOOST_URL_DECL
system::result<params_encoded_view>
parse_query(core::string_view s) noexcept;
} // urls
} // boost
#endif
+462
View File
@@ -0,0 +1,462 @@
//
// 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_PCT_STRING_VIEW_HPP
#define BOOST_URL_PCT_STRING_VIEW_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/encoding_opts.hpp>
#include <boost/url/error_types.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/string_token.hpp>
#include <boost/url/grammar/string_view_base.hpp>
#include <cstddef>
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
namespace boost {
namespace urls {
//------------------------------------------------
#ifndef BOOST_URL_DOCS
class decode_view;
class pct_string_view;
pct_string_view
make_pct_string_view_unsafe(
char const*, std::size_t,
std::size_t) noexcept;
namespace detail {
core::string_view&
ref(pct_string_view& s) noexcept;
} // detail
#endif
//------------------------------------------------
/** A reference to a valid percent-encoded string
Objects of this type behave like a
`core::string_view` and have the same interface,
but offer an additional invariant: they can
only be constructed from strings containing
valid percent-escapes.
Attempting construction from a string
containing invalid or malformed percent
escapes results in an exception.
@par Operators
The following operators are supported between
@ref pct_string_view and any object that is
convertible to `core::string_view`
@code
bool operator==( pct_string_view, pct_string_view ) noexcept;
bool operator!=( pct_string_view, pct_string_view ) noexcept;
bool operator<=( pct_string_view, pct_string_view ) noexcept;
bool operator< ( pct_string_view, pct_string_view ) noexcept;
bool operator> ( pct_string_view, pct_string_view ) noexcept;
bool operator>=( pct_string_view, pct_string_view ) noexcept;
@endcode
*/
class pct_string_view final
: public grammar::string_view_base
{
std::size_t dn_ = 0;
#ifndef BOOST_URL_DOCS
friend
pct_string_view
make_pct_string_view_unsafe(
char const*, std::size_t,
std::size_t) noexcept;
friend
core::string_view&
detail::ref(pct_string_view&) noexcept;
#endif
// unsafe
pct_string_view(
char const* data,
std::size_t size,
std::size_t dn) noexcept
: string_view_base(data, size)
, dn_(dn)
{
}
BOOST_URL_DECL
void
decode_impl(
string_token::arg& dest,
encoding_opts opt) const;
public:
/** Constructor
Default constructed string are empty.
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
constexpr pct_string_view() = default;
/** Constructor
The copy references the same
underlying character buffer.
Ownership is not transferred.
@par Postconditions
@code
this->data() == other.data()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@par other The string to copy.
*/
constexpr
pct_string_view(
pct_string_view const& other) = default;
/** Constructor
The newly constructed string references
the specified character buffer.
Ownership is not transferred.
@par Postconditions
@code
this->data() == core::string_view(s).data()
@endcode
@par Complexity
Linear in `core::string_view(s).size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
The string contains an invalid percent encoding.
@tparam String A type convertible to `core::string_view`
@param s The string to construct from.
*/
template<
class String
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
std::is_convertible<
String,
core::string_view
>::value>::type
#endif
>
pct_string_view(
String const& s)
: pct_string_view(
detail::to_sv(s))
{
}
/** Constructor (deleted)
*/
pct_string_view(
std::nullptr_t) = delete;
/** Constructor
The newly constructed string references
the specified character buffer. Ownership
is not transferred.
@par Postconditions
@code
this->data() == s && this->size() == len
@endcode
@par Complexity
Linear in `len`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
The string contains an invalid percent encoding.
@param s, len The string to construct from.
*/
pct_string_view(
char const* s,
std::size_t len)
: pct_string_view(
core::string_view(s, len))
{
}
/** Constructor
The newly constructed string references
the specified character buffer. Ownership
is not transferred.
@par Postconditions
@code
this->data() == s.data() && this->size() == s.size()
@endcode
@par Complexity
Linear in `s.size()`.
@par Exception Safety
Exceptions thrown on invalid input.
@throw system_error
The string contains an invalid percent encoding.
@param s The string to construct from.
*/
BOOST_URL_DECL
pct_string_view(
core::string_view s);
/** Assignment
The copy references the same
underlying character buffer.
Ownership is not transferred.
@par Postconditions
@code
this->data() == other.data()
@endcode
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@par other The string to copy.
*/
pct_string_view& operator=(
pct_string_view const& other) = default;
friend
BOOST_URL_DECL
system::result<pct_string_view>
make_pct_string_view(
core::string_view s) noexcept;
//--------------------------------------------
/** Return the decoded size
This function returns the number of
characters in the resulting string if
percent escapes were converted into
ordinary characters.
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
*/
std::size_t
decoded_size() const noexcept
{
return dn_;
}
/** Return the string as a range of decoded characters
@par Complexity
Constant.
@par Exception Safety
Throws nothing.
@see
@ref decode_view.
*/
decode_view
operator*() const noexcept;
/** Return the string with percent-decoding
This function converts percent escapes
in the string into ordinary characters
and returns the result.
When called with no arguments, the
return type is `std::string`.
Otherwise, the return type and style
of output is determined by which string
token is passed.
@par Example
@code
assert( pct_string_view( "Program%20Files" ).decode() == "Program Files" );
@endcode
@par Complexity
Linear in `this->size()`.
@par Exception Safety
Calls to allocate may throw.
String tokens may throw exceptions.
@param opt The options for encoding. If
this parameter is omitted, the default
options are used.
@param token An optional string token.
If this parameter is omitted, then
a new `std::string` is returned.
Otherwise, the function return type
is the result type of the token.
@see
@ref encoding_opts,
@ref string_token::return_string.
*/
template<BOOST_URL_STRTOK_TPARAM>
BOOST_URL_STRTOK_RETURN
decode(
encoding_opts opt = {},
BOOST_URL_STRTOK_ARG(token)) const
{
/* If you get a compile error here, it
means that the token you passed does
not meet the requirements stated
in the documentation.
*/
static_assert(
string_token::is_token<
StringToken>::value,
"Type requirements not met");
decode_impl(token, opt);
return token.result();
}
#ifndef BOOST_URL_DOCS
// arrow support
pct_string_view const*
operator->() const noexcept
{
return this;
}
#endif
//--------------------------------------------
// VFALCO No idea why this fails in msvc
/** Swap
*/
/*BOOST_CXX14_CONSTEXPR*/ void swap(
pct_string_view& s ) noexcept
{
string_view_base::swap(s);
std::swap(dn_, s.dn_);
}
};
//------------------------------------------------
#ifndef BOOST_URL_DOCS
namespace detail {
// obtain modifiable reference to
// underlying string, to handle
// self-intersection on modifiers.
inline
core::string_view&
ref(pct_string_view& s) noexcept
{
return s.s_;
}
} // detail
#endif
//------------------------------------------------
/** Return a valid percent-encoded string
If `s` is a valid percent-encoded string,
the function returns the buffer as a valid
view which may be used to perform decoding
or measurements.
Otherwise the result contains an error code.
Upon success, the returned view references
the original character buffer;
Ownership is not transferred.
@par Complexity
Linear in `s.size()`.
@par Exception Safety
Throws nothing.
@param s The string to validate.
*/
BOOST_URL_DECL
system::result<pct_string_view>
make_pct_string_view(
core::string_view s) noexcept;
#ifndef BOOST_URL_DOCS
// VFALCO semi-private for now
inline
pct_string_view
make_pct_string_view_unsafe(
char const* data,
std::size_t size,
std::size_t decoded_size) noexcept
{
#if 0
BOOST_ASSERT(! make_pct_string_view(
core::string_view(data, size)).has_error());
#endif
return pct_string_view(
data, size, decoded_size);
}
#endif
#ifndef BOOST_URL_DOCS
namespace detail {
template <>
inline
core::string_view
to_sv(pct_string_view const& s) noexcept
{
return s.substr();
}
} // detail
#endif
} // urls
} // boost
#endif
+74
View File
@@ -0,0 +1,74 @@
//
// 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_RFC_ABSOLUTE_URI_RULE_HPP
#define BOOST_URL_RFC_ABSOLUTE_URI_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/error_types.hpp>
#include <boost/url/url_view.hpp>
namespace boost {
namespace urls {
/** Rule for absolute-URI
@par Value Type
@code
using value_type = url_view;
@endcode
@par Example
Rules are used with the function @ref grammar::parse.
@code
system::result< url_view > rv = grammar::parse( "http://example.com/index.htm?id=1", absolute_uri_rule );
@endcode
@par BNF
@code
absolute-URI = scheme ":" hier-part [ "?" query ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-4.3"
>4.3. Absolute URI (rfc3986)</a>
@see
@ref grammar::parse,
@ref parse_absolute_uri,
@ref url_view.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ absolute_uri_rule;
#else
struct absolute_uri_rule_t
{
using value_type = url_view;
BOOST_URL_DECL
auto
parse(
char const*& it,
char const* end
) const noexcept ->
system::result<value_type>;
};
constexpr absolute_uri_rule_t absolute_uri_rule{};
#endif
} // urls
} // boost
#endif
+69
View File
@@ -0,0 +1,69 @@
//
// 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_RFC_AUTHORITY_RULE_HPP
#define BOOST_URL_RFC_AUTHORITY_RULE_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/authority_view.hpp>
#include <boost/url/error_types.hpp>
namespace boost {
namespace urls {
/** Rule for authority
@par Value Type
@code
using value_type = authority_view;
@endcode
@par Example
Rules are used with the function @ref grammar::parse.
@code
system::result< authority_view > rv = grammar::parse( "user:pass@example.com:8080", authority_rule );
@endcode
@par BNF
@code
authority = [ userinfo "@" ] host [ ":" port ]
@endcode
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2"
>3.2. Authority (rfc3986)</a>
@see
@ref authority_view,
@ref grammar::parse,
@ref parse_authority.
*/
#ifdef BOOST_URL_DOCS
constexpr __implementation_defined__ authority_rule;
#else
struct authority_rule_t
{
using value_type = authority_view;
BOOST_URL_DECL
auto
parse(
char const*& it,
char const* end
) const noexcept ->
system::result<value_type>;
};
constexpr authority_rule_t authority_rule{};
#endif
} // urls
} // boost
#endif
+87
View File
@@ -0,0 +1,87 @@
//
// Copyright (c) 2022 alandefreitas (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_RFC_DETAIL_CHARSETS_HPP
#define BOOST_URL_RFC_DETAIL_CHARSETS_HPP
#include <boost/url/rfc/pchars.hpp>
#include <boost/url/rfc/sub_delim_chars.hpp>
#include <boost/url/rfc/unreserved_chars.hpp>
namespace boost {
namespace urls {
namespace detail {
constexpr
auto
user_chars =
unreserved_chars + sub_delim_chars;
constexpr
auto
password_chars =
unreserved_chars + sub_delim_chars + ':';
constexpr
auto
userinfo_chars =
password_chars;
constexpr
auto
host_chars =
unreserved_chars + sub_delim_chars;
constexpr
auto
reg_name_chars =
unreserved_chars + '-' + '.';
constexpr
auto
segment_chars =
pchars;
constexpr
auto
path_chars =
segment_chars + '/';
constexpr
auto
query_chars =
pchars + '/' + '?';
constexpr
auto
param_key_chars = pchars
+ '/' + '?' + '[' + ']'
- '&' - '=';
constexpr
auto
param_value_chars = pchars
+ '/' + '?'
- '&';
constexpr
auto
fragment_chars =
pchars + '/' + '?' + '#';
constexpr
auto
nocolon_pchars =
pchars - ':';
} // detail
} // urls
} // boost
#endif

Some files were not shown because too many files have changed in this diff Show More