2
0
mirror of https://github.com/boostorg/url.git synced 2026-02-13 12:52:14 +00:00

segments refactoring

This commit is contained in:
Vinnie Falco
2021-09-25 19:14:45 -07:00
parent 9737783672
commit 4bbbc15ecc
31 changed files with 3763 additions and 694 deletions

View File

@@ -18,6 +18,7 @@
#include <boost/url/pct_encoding_types.hpp>
#include <boost/url/query_params_view.hpp>
#include <boost/url/scheme.hpp>
#include <boost/url/segments.hpp>
#include <boost/url/segments_encoded.hpp>
#include <boost/url/segments_encoded_view.hpp>
#include <boost/url/segments_view.hpp>

View File

@@ -0,0 +1,34 @@
//
// 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/CPPAlliance/url
//
#ifndef BOOST_URL_ARROW_PROXY_HPP
#define BOOST_URL_ARROW_PROXY_HPP
#include <boost/url/detail/config.hpp>
namespace boost {
namespace urls {
// https://quuxplusone.github.io/blog/2019/02/06/arrow-proxy/
template<class T>
struct arrow_proxy
{
T t;
T *operator->() noexcept
{
return &t;
}
};
} // urls
} // boost
#endif

View File

@@ -169,6 +169,73 @@ public:
}
};
//------------------------------------------------
class plain_segs_iter_base
{
protected:
BOOST_URL_DECL
static
void
measure_impl(
string_view s,
std::size_t& n) noexcept;
BOOST_URL_DECL
static
void
copy_impl(
string_view s,
char*& dest,
char const* end) noexcept;
};
// iterates segments in an
// encoded segment range
template<class FwdIt>
class plain_segs_iter
: public any_path_iter
, public plain_segs_iter_base
{
FwdIt it_;
FwdIt end_;
public:
plain_segs_iter(
FwdIt first,
FwdIt last) noexcept
: it_(first)
, end_(last)
{
}
bool
measure(
std::size_t& n,
error_code&
) noexcept override
{
if(it_ == end_)
return false;
measure_impl(*it_, n);
++it_;
return true;
}
void
copy(
char*& dest,
char const* end
) noexcept override
{
copy_impl(*it_,
dest, end);
++it_;
}
};
//------------------------------------------------
template<class FwdIt>
enc_segs_iter<FwdIt>
make_enc_segs_iter(
@@ -178,6 +245,15 @@ make_enc_segs_iter(
first, last);
}
template<class FwdIt>
plain_segs_iter<FwdIt>
make_plain_segs_iter(
FwdIt first, FwdIt last)
{
return plain_segs_iter<FwdIt>(
first, last);
}
} // detail
} // urls
} // boost

View File

@@ -10,10 +10,6 @@
#ifndef BOOST_URL_DETAIL_COPIED_STRINGS_HPP
#define BOOST_URL_DETAIL_COPIED_STRINGS_HPP
#ifndef BOOST_URL_SOURCE
#error
#endif
#include <boost/url/string.hpp>
namespace boost {

View File

@@ -21,7 +21,7 @@ namespace urls {
namespace detail {
any_path_iter::
~any_path_iter() = default;
~any_path_iter() noexcept = default;
//------------------------------------------------
@@ -91,6 +91,7 @@ copy(
char*& dest,
char const* end) noexcept
{
(void)end;
BOOST_ASSERT(static_cast<
std::size_t>(
end - dest) >= n_);
@@ -200,6 +201,7 @@ copy_impl(
char*& dest,
char const* end) noexcept
{
(void)end;
BOOST_ASSERT(static_cast<
std::size_t>(end - dest) >=
s.size());
@@ -213,6 +215,30 @@ copy_impl(
//------------------------------------------------
void
plain_segs_iter_base::
measure_impl(
string_view s,
std::size_t& n) noexcept
{
n += pct_encode_size(
s, pchars);
}
void
plain_segs_iter_base::
copy_impl(
string_view s,
char*& dest,
char const* end) noexcept
{
dest = pct_encode(
dest, end, s, {},
pchars);
}
//------------------------------------------------
} // detail
} // urls
} // boost

View File

@@ -0,0 +1,76 @@
//
// 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/CPPAlliance/url
//
#ifndef BOOST_URL_DETAIL_OPTIONAL_ALLOCATOR_HPP
#define BOOST_URL_DETAIL_OPTIONAL_ALLOCATOR_HPP
#include <new>
namespace boost {
namespace urls {
namespace detail {
// VFALCO This is so we can make
// iterators default-constructible
template<class Allocator>
class optional_allocator
{
char buf_[sizeof(Allocator)];
bool has_value_ = false;
public:
~optional_allocator()
{
if(has_value_)
(*(*this)).~Allocator();
}
optional_allocator() = default;
explicit
optional_allocator(
Allocator const& a) noexcept
: has_value_(true)
{
::new(buf_) Allocator(a);
}
optional_allocator(
optional_allocator const& other) noexcept
: has_value_(other.has_value_)
{
if(has_value_)
::new(buf_) Allocator(*other);
}
optional_allocator&
operator=(optional_allocator const& other
) noexcept
{
if(has_value_)
(*(*this)).~Allocator();
has_value_ = other.has_value_;
if(has_value_)
::new(buf_) Allocator(*other);
return *this;
}
Allocator const&
operator*() const noexcept
{
return *reinterpret_cast<
Allocator const*>(buf_);
}
};
} // detail
} // urls
} // boost
#endif

View File

@@ -11,6 +11,7 @@
#define BOOST_URL_DETAIL_OVER_ALLOCATOR_HPP
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/type_traits/is_final.hpp>
#include <boost/type_traits/type_with_alignment.hpp>

File diff suppressed because it is too large Load Diff

View File

@@ -44,6 +44,9 @@ public:
reference&
operator=(reference const& other)
{
if( u_ == other.u_ &&
i_ == other.i_)
return *this;
*this = string_view(other);
return *this;
}
@@ -108,100 +111,6 @@ public:
}
#endif
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value &&
! std::is_same<reference, T>::value,
bool>::type
#endif
>
friend
bool
operator==(
reference const& x1,
T const& x2 ) noexcept
{
return
string_view(x1) ==
to_string_view(x2);
}
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value &&
! std::is_same<reference, T>::value,
bool>::type
#endif
>
friend
bool
operator==(
T const& x1,
reference x2 ) noexcept
{
return
to_string_view(x1) ==
string_view(x2);
}
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value,
bool>::type
#endif
>
friend
bool
operator!=(
reference const& x1,
T const& x2 ) noexcept
{
return !( x1 == x2 );
}
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value,
bool>::type
#endif
>
friend
bool
operator!=(
T const& x1,
reference const& x2 ) noexcept
{
return !( x1 == x2);
}
/** Swap two elements
*/
BOOST_URL_DECL
@@ -266,100 +175,6 @@ public:
return { s.data(), s.size() };
}
#endif
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value &&
! std::is_same<reference, T>::value,
bool>::type
#endif
>
friend
bool
operator==(
const_reference const& x1,
T const& x2 ) noexcept
{
return
string_view(x1) ==
to_string_view(x2);
}
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value &&
! std::is_same<reference, T>::value,
bool>::type
#endif
>
friend
bool
operator==(
T const& x1,
const_reference x2 ) noexcept
{
return
to_string_view(x1) ==
string_view(x2);
}
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value,
bool>::type
#endif
>
friend
bool
operator!=(
const_reference const& x1,
T const& x2 ) noexcept
{
return !( x1 == x2 );
}
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value,
bool>::type
#endif
>
friend
bool
operator!=(
T const& x1,
const_reference const& x2 ) noexcept
{
return !(x1 == x2);
}
};
//------------------------------------------------
@@ -1006,52 +821,99 @@ operator=(
const_reference const& other) ->
reference&
{
if( u_ == other.u_ &&
i_ == other.i_)
return *this;
*this = string_view(other);
return *this;
}
inline
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value>::type
#endif
>
bool
operator==(
segments_encoded::
const_reference const& c,
segments_encoded::
reference const& r) noexcept
const_reference const& x1,
T const& x2 ) noexcept
{
return string_view(c) == string_view(r);
return
string_view(x1) ==
to_string_view(x2);
}
inline
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value>::type
#endif
>
bool
operator==(
T const& x1,
segments_encoded::
reference const& r,
segments_encoded::
const_reference const& c) noexcept
const_reference const& x2 ) noexcept
{
return string_view(r) == string_view(c);
return
to_string_view(x1) ==
string_view(x2);
}
inline
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value>::type
#endif
>
bool
operator!=(
segments_encoded::
const_reference const& c,
segments_encoded::
reference const& r) noexcept
const_reference const& x1,
T const& x2 ) noexcept
{
return string_view(c) != string_view(r);
return !( x1 == x2 );
}
inline
/** Comparison
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value>::type
#endif
>
bool
operator!=(
T const& x1,
segments_encoded::
reference const& r,
segments_encoded::
const_reference const& c) noexcept
const_reference const& x2 ) noexcept
{
return string_view(r) != string_view(c);
return !(x1 == x2);
}
} // urls

View File

@@ -10,69 +10,67 @@
#ifndef BOOST_URL_IMPL_SEGMENTS_VIEW_HPP
#define BOOST_URL_IMPL_SEGMENTS_VIEW_HPP
#include <boost/url/segments_encoded_view.hpp>
#include <boost/url/detail/except.hpp>
#include <boost/url/detail/pct_encoding.hpp>
#include <boost/url/rfc/paths_bnf.hpp>
#include <cstdint>
#include <boost/url/arrow_proxy.hpp>
#include <boost/url/pct_encoding_types.hpp>
#include <cstddef>
namespace boost {
namespace urls {
template<class Alloc>
class segments_view<Alloc>::
class segments_view::
iterator
{
std::size_t i_ = 0;
string_type<Alloc> s_;
char const* begin_ = nullptr;
char const* pos_ = nullptr;
char const* next_ = nullptr;
char const* end_ = nullptr;
string_value::allocator a_;
pct_encoded_str t_;
friend segments_view;
explicit
BOOST_URL_DECL
iterator(
string_view s,
Alloc const& a);
string_value::
allocator const& a) noexcept;
// end ctor
BOOST_URL_DECL
iterator(
std::size_t n,
string_view s,
Alloc const& a) noexcept;
string_value::
allocator const& a) noexcept;
public:
using value_type = string_type<Alloc>;
using value_type = string_value;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
iterator() noexcept = default;
BOOST_URL_DECL
iterator() noexcept;
BOOST_URL_DECL
iterator(
iterator const&) noexcept = default;
iterator& operator=(
iterator const&) noexcept = default;
iterator const&) noexcept;
std::size_t
index() const noexcept
{
return i_;
}
BOOST_URL_DECL
iterator&
operator=(
iterator const&) noexcept;
value_type const&
operator*() const noexcept
{
return s_;
}
BOOST_URL_DECL
string_value
operator*() const noexcept;
value_type const*
arrow_proxy<string_value>
operator->() const noexcept
{
return &s_;
return {**this};
}
bool
@@ -93,9 +91,11 @@ public:
end_ != other.end_;
}
BOOST_URL_DECL
iterator&
operator++() noexcept;
BOOST_URL_DECL
iterator&
operator--() noexcept;
@@ -116,184 +116,6 @@ public:
}
};
//------------------------------------------------
template<class Alloc>
segments_view<Alloc>::
segments_view(
segments_encoded_view const& sv,
Alloc const& a) noexcept
: s_(sv.s_)
, n_(sv.n_)
, a_(a)
{
}
//------------------------------------------------
template<class Alloc>
segments_view<Alloc>::
iterator::
iterator(
string_view s,
Alloc const& a)
: s_(a)
, begin_(s.data())
, pos_(s.data())
, next_(s.data())
, end_(s.data() + s.size())
{
using bnf::parse;
using bnf_t = path_rootless_bnf;
using detail::pct_decode_unchecked;
if(next_ == end_)
{
next_ = nullptr;
return;
}
error_code ec;
if(*next_ == '/')
{
// "/" segment
pct_encoded_str t;
bnf_t::increment(next_,
end_, ec, t);
BOOST_ASSERT(! ec);
s_ = pct_decode_unchecked(
t.str, t.decoded_size, {},
s_.get_allocator());
}
else
{
// segment-nz
pct_encoded_str t;
bnf_t::begin(next_,
end_, ec, t);
BOOST_ASSERT(! ec);
s_ = pct_decode_unchecked(
t.str, t.decoded_size, {},
s_.get_allocator());
}
}
template<class Alloc>
segments_view<Alloc>::
iterator::
iterator(
std::size_t n,
string_view s,
Alloc const& a) noexcept
: i_(n)
, s_(a)
, begin_(s.data())
, pos_(s.data() + s.size())
, end_(s.data() + s.size())
{
}
template<class Alloc>
auto
segments_view<Alloc>::
iterator::
operator++() noexcept ->
iterator&
{
using bnf::parse;
using bnf_t = path_rootless_bnf;
using detail::pct_decode_unchecked;
BOOST_ASSERT(next_ != nullptr);
++i_;
pos_ = next_;
error_code ec;
// "/" segment
pct_encoded_str t;
bnf_t::increment(
next_, end_, ec, t);
if(ec == error::end)
{
next_ = nullptr;
return *this;
}
BOOST_ASSERT(! ec);
s_ = pct_decode_unchecked(
t.str, t.decoded_size, {},
s_.get_allocator());
return *this;
}
template<class Alloc>
auto
segments_view<Alloc>::
iterator::
operator--() noexcept ->
iterator&
{
using bnf::parse;
using bnf_t = path_rootless_bnf;
using detail::pct_decode_unchecked;
BOOST_ASSERT(i_ != 0);
BOOST_ASSERT(pos_ != begin_);
--i_;
error_code ec;
while(--pos_ != begin_)
{
if(*pos_ != '/')
continue;
// "/" segment
next_ = pos_;
pct_encoded_str t;
bnf_t::increment(next_,
end_, ec, t);
BOOST_ASSERT(! ec);
s_ = pct_decode_unchecked(
t.str, t.decoded_size, {},
s_.get_allocator());
return *this;
}
next_ = pos_;
if(*next_ == '/')
{
// "/" segment
pct_encoded_str t;
bnf_t::increment(next_,
end_, ec, t);
BOOST_ASSERT(! ec);
s_ = pct_decode_unchecked(
t.str, t.decoded_size, {},
s_.get_allocator());
}
else
{
// segment-nz
pct_encoded_str t;
bnf_t::begin(next_,
end_, ec, t);
BOOST_ASSERT(! ec);
s_ = pct_decode_unchecked(
t.str, t.decoded_size, {},
s_.get_allocator());
}
return *this;
}
template<class Alloc>
auto
segments_view<Alloc>::
begin() const noexcept ->
iterator
{
return iterator(s_, a_);
}
template<class Alloc>
auto
segments_view<Alloc>::
end() const noexcept ->
iterator
{
return iterator(n_, s_, a_);
}
} // urls
} // boost

View File

@@ -0,0 +1,193 @@
//
// 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/CPPAlliance/url
//
#ifndef BOOST_URL_IMPL_SEGMENTS_VIEW_IPP
#define BOOST_URL_IMPL_SEGMENTS_VIEW_IPP
#include <boost/url/segments_view.hpp>
#include <boost/url/detail/pct_encoding.hpp>
#include <boost/url/bnf/parse.hpp>
#include <boost/url/rfc/paths_bnf.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace urls {
segments_view::
segments_view(
segments_view const&) noexcept = default;
//------------------------------------------------
segments_view::
iterator::
iterator(
string_view s,
string_value::allocator const& a) noexcept
: begin_(s.data())
, pos_(s.data())
, next_(s.data())
, end_(s.data() + s.size())
, a_(a)
{
using bnf::parse;
using bnf_t = path_rootless_bnf;
using detail::pct_decode_unchecked;
if(next_ == end_)
{
next_ = nullptr;
return;
}
error_code ec;
if(*next_ == '/')
{
// "/" segment
bnf_t::increment(next_,
end_, ec, t_);
BOOST_ASSERT(! ec);
}
else
{
// segment-nz
bnf_t::begin(next_,
end_, ec, t_);
BOOST_ASSERT(! ec);
}
}
segments_view::
iterator::
iterator(
std::size_t,
string_view s,
string_value::
allocator const& a) noexcept
: begin_(s.data())
, pos_(s.data() + s.size())
, end_(s.data() + s.size())
, a_(a)
{
}
segments_view::
iterator::
iterator() noexcept = default;
segments_view::
iterator::
iterator(
iterator const&) noexcept = default;
auto
segments_view::
iterator::
operator=(
iterator const&) noexcept ->
iterator& = default;
string_value
segments_view::
iterator::
operator*() const noexcept
{
char* dest;
auto s = a_.make_string_value(
t_.decoded_size, dest);
detail::pct_decode_unchecked(
dest,
dest + t_.decoded_size,
t_.str,
{});
return s;
}
auto
segments_view::
iterator::
operator++() noexcept ->
iterator&
{
using bnf::parse;
using bnf_t = path_rootless_bnf;
using detail::pct_decode_unchecked;
BOOST_ASSERT(next_ != nullptr);
pos_ = next_;
error_code ec;
// "/" segment
bnf_t::increment(
next_, end_, ec, t_);
if(ec == error::end)
{
next_ = nullptr;
return *this;
}
BOOST_ASSERT(! ec);
return *this;
}
auto
segments_view::
iterator::
operator--() noexcept ->
iterator&
{
using bnf::parse;
using bnf_t = path_rootless_bnf;
using detail::pct_decode_unchecked;
BOOST_ASSERT(pos_ != begin_);
error_code ec;
while(--pos_ != begin_)
{
if(*pos_ != '/')
continue;
// "/" segment
next_ = pos_;
bnf_t::increment(next_,
end_, ec, t_);
BOOST_ASSERT(! ec);
return *this;
}
next_ = pos_;
if(*next_ == '/')
{
// "/" segment
bnf_t::increment(next_,
end_, ec, t_);
BOOST_ASSERT(! ec);
}
else
{
// segment-nz
bnf_t::begin(next_,
end_, ec, t_);
BOOST_ASSERT(! ec);
}
return *this;
}
auto
segments_view::
begin() const noexcept ->
iterator
{
return iterator(s_, a_);
}
auto
segments_view::
end() const noexcept ->
iterator
{
return iterator(n_, s_, a_);
}
} // urls
} // boost
#endif

View File

@@ -16,90 +16,22 @@
namespace boost {
namespace urls {
struct basic_static_pool::item
{
void* p;
std::size_t n;
bool
in_use() const noexcept
{
return (reinterpret_cast<
std::uintptr_t>(p) & 1) != 0;
}
void
use() noexcept
{
p = reinterpret_cast<
void*>((reinterpret_cast<
std::uintptr_t>(p) | 1));
}
void
free() noexcept
{
p = reinterpret_cast<
void*>((reinterpret_cast<
std::uintptr_t>(p) & ~1));
}
void*
ptr() const noexcept
{
return reinterpret_cast<
void*>((reinterpret_cast<
std::uintptr_t>(p) & ~1));
}
};
void*
basic_static_pool::
allocate(
std::size_t bytes,
std::size_t align)
{
if( align < 2)
align = 2;
bytes = alignment::align_up(
auto n = alignment::align_up(
bytes, align);
item* it0 = reinterpret_cast<
item*>(base_);
item* it1 = it0 + n_;
{
// find best fit
item* best = nullptr;
std::size_t bestn =
std::size_t(-1);
auto it = it0;
while(it != it1)
{
if( ! it->in_use() &&
it->n >= bytes &&
it->n < bestn)
{
best = it;
bestn = it->n;
}
++it;
}
if(best)
{
it->use();
return it->p;
}
}
auto const u0 = std::uintptr_t(top_);
auto const u = align * (
(u0 + align - 1) / align);
auto const p =
reinterpret_cast<char*>(u);
if( u < u0 || bytes >
capacity_ - (p - base_))
auto p = reinterpret_cast<char*>(
reinterpret_cast<
std::uintptr_t>(top_ - n) &
~(align - 1));
if(p < begin_)
detail::throw_bad_alloc(
BOOST_CURRENT_LOCATION);
top_ = reinterpret_cast<
char*>(p + bytes);
++n_;
return p;
}
@@ -110,6 +42,11 @@ deallocate(
std::size_t,
std::size_t) noexcept
{
BOOST_ASSERT(n_ > 0);
--n_;
if(n_ > 0)
return;
top_ = end_;
}
} // urls

View File

@@ -0,0 +1,241 @@
//
// 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/CPPAllinace/url
//
#ifndef BOOST_URL_IMPL_STRING_HPP
#define BOOST_URL_IMPL_STRING_HPP
#include <boost/url/detail/over_allocator.hpp>
namespace boost {
namespace urls {
struct string_value::base
{
std::size_t refs = 1;
virtual void destroy() noexcept = 0;
};
template<class Allocator>
auto
string_value::
construct(
std::size_t n,
Allocator const& a,
char*& dest) ->
base*
{
class impl;
using allocator_type =
detail::over_allocator<
impl, Allocator>;
class impl : public base
{
allocator_type a_;
public:
explicit
impl(
allocator_type const& a)
: a_(a)
{
}
void
destroy() noexcept override
{
auto a(a_);
a.deallocate(this, 1);
}
};
if(n == 0)
{
dest = nullptr;
return nullptr;
}
allocator_type al(n, a);
auto p = ::new(
al.allocate(1)) impl(al);
dest = reinterpret_cast<
char*>(p + 1);
static_cast<string_view&>(
*this) = { dest, n };
return p;
}
string_value::
~string_value()
{
if( p_ &&
--p_->refs == 0)
p_->destroy();
}
template<class Allocator>
string_value::
string_value(
std::size_t n,
Allocator const& a,
char*& dest)
: p_(construct(n, a, dest))
{
}
template<class Allocator>
string_value::
string_value(
string_view s,
Allocator const& a)
{
char* dest;
p_ = construct(
s.size(), a, dest);
std::memcpy(dest,
s.data(), s.size());
}
string_value::
string_value(
string_value const& other) noexcept
: string_view(other)
, p_(other.p_)
{
if(p_)
++p_->refs;
}
string_value&
string_value::
operator=(
string_value const& other) noexcept
{
if( p_ &&
--p_->refs == 0)
p_->destroy();
p_ = other.p_;
if(p_)
++p_->refs;
static_cast<string_view&>(
*this) = other;
return *this;
}
//------------------------------------------------
class string_value::allocator
{
struct base
{
std::size_t refs = 1;
virtual
~base()
{
}
virtual
string_value
alloc(
std::size_t n,
char*& dest) = 0;
virtual
void
destroy() noexcept = 0;
};
base* p_ = nullptr;
public:
~allocator()
{
if( p_ &&
--p_->refs == 0)
p_->destroy();
}
allocator() = default;
allocator(
allocator const& other) noexcept
: p_(other.p_)
{
++p_->refs;
}
allocator&
operator=(
allocator const& other) noexcept
{
if( p_ &&
--p_->refs)
p_->destroy();
p_ = other.p_;
if(p_)
++p_->refs;
return *this;
}
template<class Allocator>
explicit
allocator(Allocator const& a)
{
class impl;
using allocator_type = typename
detail::allocator_traits<
Allocator>::template
rebind_alloc<impl>;
class impl : public base
{
allocator_type a_;
public:
impl(allocator_type const& a)
: a_(a)
{
}
string_value
alloc(
std::size_t n,
char*& dest) override
{
return string_value(
n, a_, dest);
}
void
destroy() noexcept override
{
auto a(a_);
a.deallocate(this, 1);
}
};
allocator_type al(a);
p_ = ::new(al.allocate(1)) impl(al);
}
string_value
make_string_value(
std::size_t n,
char*& dest) const
{
return p_->alloc(n, dest);
}
};
} // urls
} // boost
#endif

View File

@@ -13,6 +13,15 @@
namespace boost {
namespace urls {
template<class Allocator>
segments<Allocator>
url::
segments(Allocator const& a) noexcept
{
return urls::segments<Allocator>(
*this, a);
}
} // urls
} // boost

View File

@@ -715,6 +715,7 @@ set_encoded_host(string_view s)
case urls::host_type::ipv6:
return set_host(t.ipv6);
case urls::host_type::none:
case urls::host_type::name:
{
auto dest =
@@ -1296,26 +1297,12 @@ set_path(
string_view
url::
encoded_segment(
int index) const noexcept
std::size_t i) const noexcept
{
std::size_t i;
raw_segment r;
if(index >= 0)
{
i = static_cast<
std::size_t>(index);
if(i >= nseg_)
return empty_;
r = get_segment(i);
}
else
{
i = static_cast<
std::size_t>(-index);
if(i > nseg_)
return empty_;
r = get_segment(nseg_ - i);
}
if(i >= nseg_)
return empty_;
r = get_segment(i);
string_view s = {
s_ + r.pos, r.len };
if(s.starts_with('/'))

View File

@@ -384,29 +384,14 @@ segment_count() const noexcept
string_view
url_view::
encoded_segment(
int index) const noexcept
std::size_t i) const noexcept
{
std::size_t i;
if(index >= 0)
{
i = static_cast<
std::size_t>(index);
if(i >= nseg_)
return empty_;
auto pv = encoded_segments();
auto it = pv.begin();
while(i--)
++it;
return *it;
}
i = static_cast<
std::size_t>(-index);
if(i > nseg_)
if(i >= nseg_)
return empty_;
auto pv = encoded_segments();
auto it = pv.end();
auto it = pv.begin();
while(i--)
--it;
++it;
return *it;
}

View File

@@ -0,0 +1,938 @@
//
// 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/CPPAlliance/url
//
#ifndef BOOST_URL_SEGMENTS_HPP
#define BOOST_URL_SEGMENTS_HPP
#include <boost/url/detail/config.hpp>
#include <boost/url/string.hpp>
#include <boost/url/detail/except.hpp>
#include <boost/url/detail/parts_base.hpp>
#include <boost/assert.hpp>
#include <initializer_list>
#include <iterator>
namespace boost {
namespace urls {
#ifndef BOOST_URL_DOCS
class url;
#endif
/** A reference-like container to modifiable URL segments
This class implements a <em>RandomAccessContainer</em>
representing the path segments in a @ref url as
percent-encoded strings. Ownership of the segments
is not transferred; the container references the
buffer in the url. Therefore, the lifetime of the
url must remain valid until this container no
longer exists.
Objects of this type are not constructed directly;
Instead, call the corresponding non-const member
function of @ref url to obtain an instance of
the container:
@par Example
@code
url u = parse_relative_ref( "/path/to/file.txt" );
segments se = u.segments();
for( segments::value_type s : se )
std::cout << s << std::endl;
@endcode
The @ref reference and @ref const_reference
nested types are defined as publicly accessible
nested classes. They proxy the behavior of a
reference to a percent-encoded string in the
underlying URL. The primary use of these
references is to provide l-values that can be
returned from element-accessing operations.
Any reads or writes which happen through a
@ref reference or @ref const_reference
potentially read or write the underlying
@ref url.
@see
@ref url.
*/
template<class Allocator>
class segments
: private detail::parts_base
{
url* u_ = nullptr;
Allocator a_;
friend class url;
explicit
segments(
url& u,
Allocator const& a) noexcept
: u_(&u)
, a_(a)
{
}
public:
#ifdef BOOST_URL_DOCS
/** A random-access iterator referencing segments in a url path
When dereferenced, this iterator returns a
proxy which allows conversion to stringlike
types, assignments which change the underlying
container, and comparisons.
*/
using iterator = __see_below__;
/** A random-access iterator referencing segments in a url path
When dereferenced, this iterator returns a
proxy which allows conversion to stringlike
types, and comparisons.
*/
using const_iterator = __see_below__;
/** A proxy for a percent-encoded path segment
This type is a proxy for a modifiable
percent-encoded path segment. It supports
assignment, conversion to stringlike types,
and comparison.
*/
using reference = __see_below__;
/** A proxy for a percent-encoded path segment
This type is a proxy for a read-only
percent-encoded path segment. It supports
conversion to stringlike types, and comparison.
*/
using const_reference = __see_below__;
#else
class iterator;
class const_iterator;
class reference;
class const_reference;
#endif
/** A type which can represent a segment as a value
This type allows for making a copy of
a segment where ownership is retained
in the copy.
*/
using value_type = string_type<Allocator>;
/** An unsigned integer type
*/
using size_type = std::size_t;
/** A signed integer type
*/
using difference_type = std::ptrdiff_t;
//--------------------------------------------
//
// Members
//
//--------------------------------------------
/** Replace the contents of the container
This function replaces the contents
with an initializer list of
percent-encoded strings.
Each string must contain a valid
percent-encoding or else an
exception is thrown.
The behavior is undefined any string
refers to the contents of `*this`.
All iterators and references to elements
of the container are invalidated,
including the @ref end iterator.
@par Requires
@code
is_stringlike< T >::value == true
@endcode
@par Example
@code
url u = parse_relative_uri( "/path/to/file.txt" );
u.segments() = { "etc", "init.rc" };
assert( u.encoded_path() == "/etc/init.rc") );
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@param init An initializer list of strings.
@throw std::invalid_argument invalid percent-encoding
*/
template<class T>
#ifdef BOOST_URL_DOCS
segments&
#else
typename std::enable_if<
is_stringlike<T>::value,
segments&>::type
#endif
operator=(std::initializer_list<T> init)
{
assign(init);
return *this;
}
/** Replace the contents of the container
This function replaces the contents
with a range of percent-encoded
strings.
Each string must contain a valid
percent-encoding or else an
exception is thrown.
The behavior is undefined if either
argument is an iterator into `*this`.
All iterators and references to elements
of the container are invalidated,
including the @ref end iterator.
@par Requires
@code
is_stringlike< std::iterator_traits< FwdIt >::value_type >::value == true
@endcode
@par Example
@code
url u = parse_relative_uri( "/path/to/file.txt" );
segments se = u.segments();
std::vector< std::string > v = { "etc", "init.rc" };
se.insert( u.end() - 1, v.begin(), v.end() );
assert( u.encoded_path() == "/etc/init.rc") );
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@param first An iterator to the first
element in the range
@param last An iterator to one past the
last element in the range
@throw std::invalid_argument invalid percent-encoding
*/
template<class FwdIt>
#ifdef BOOST_URL_DOCS
void
#else
typename std::enable_if<
is_stringlike<typename
std::iterator_traits<
FwdIt>::value_type>::value,
void>::type
#endif
assign(FwdIt first, FwdIt last);
/** Replace the contents of the container
This function replaces the contents
with an initializer list of
percent-encoded strings.
Each string must contain a valid
percent-encoding or else an
exception is thrown.
The behavior is undefined any string
refers to the contents of `*this`.
All iterators and references to elements
of the container are invalidated,
including the @ref end iterator.
@par Requires
@code
is_stringlike< T >::value == true
@endcode
@par Example
@code
url u = parse_relative_uri( "/path/to/file.txt" );
u.segments().assign( { "etc", "init.rc" } );
assert( u.encoded_path() == "/etc/init.rc") );
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@param init An initializer list of strings.
@throw std::invalid_argument invalid percent-encoding
*/
template<class T>
#ifdef BOOST_URL_DOCS
void
#else
typename std::enable_if<
is_stringlike<T>::value,
void>::type
#endif
assign(std::initializer_list<T> init)
{
assign(init.begin(), init.end());
}
//--------------------------------------------
//
// Element Access
//
//--------------------------------------------
/** Return an element with bounds checking
This function returns a proxy reference
to the i-th element. If i is greater than
@ref size, an exception is thrown.
@par Exception Safety
Strong guarantee.
Exception thrown on invalid parameter.
@throws std::out_of_range `i >= size()`
@return A proxy reference to the element.
@param i The zero-based index of the
element.
*/
inline
reference
at(std::size_t i);
/** Return an element with bounds checking
This function returns a proxy reference
to the i-th element. If i is greater than
@ref size, an exception is thrown.
@par Exception Safety
Strong guarantee.
Exception thrown on invalid parameter.
@throws std::out_of_range `i >= size()`
@return A proxy reference to the element.
@param i The zero-based index of the
element.
*/
inline
const_reference
at(std::size_t i) const;
/** Return an element
This function returns a proxy reference
to the i-th element.
@par Preconditions
@code
i < size()
@endcode
@par Exception Safety
Strong guarantee.
@return A proxy reference to the element.
@param i The zero-based index of the
element.
*/
inline
reference
operator[](std::size_t i) noexcept;
/** Return an element
This function returns a proxy reference
to the i-th element.
@par Preconditions
@code
i < size()
@endcode
@par Exception Safety
Strong guarantee.
@return A proxy reference to the element.
@param i The zero-based index of the
element.
*/
inline
const_reference
operator[](std::size_t i) const noexcept;
/** Return the first element
*/
inline
const_reference
front() const;
/** Return the first element
*/
inline
reference
front();
/** Return the last element
*/
inline
const_reference
back() const;
/** Return the last element
*/
inline
reference
back();
//--------------------------------------------
//
// Iterators
//
//--------------------------------------------
/** Return an iterator to the beginning
*/
inline
iterator
begin() noexcept;
/** Return an iterator to the beginning
*/
inline
const_iterator
begin() const noexcept;
/** Return an iterator to the beginning
*/
inline
const_iterator
cbegin() const noexcept;
/** Return an iterator to the end
*/
inline
iterator
end() noexcept;
/** Return an iterator to the end
*/
inline
const_iterator
end() const noexcept;
/** Return an iterator to the end
*/
inline
const_iterator
cend() const noexcept;
//--------------------------------------------
//
// Capacity
//
//--------------------------------------------
/** Return true if the container is empty
This function returns true if there are
no elements in the container. That is, if
the underlying path is the empty string.
*/
bool
empty() const noexcept
{
return size() == 0;
}
/** Return the number of elements in the container
This function returns the number of
elements in the underlying path. Empty
segments count towards this total.
@par Exception Safety
Throws nothing.
*/
BOOST_URL_DECL
std::size_t
size() const noexcept;
//--------------------------------------------
//
// Modifiers
//
//--------------------------------------------
private:
template<class FwdIt>
iterator
insert(
const_iterator before,
FwdIt first,
FwdIt last,
std::input_iterator_tag) = delete;
template<class FwdIt>
iterator
insert(
const_iterator before,
FwdIt first,
FwdIt last,
std::forward_iterator_tag);
public:
/** Remove the contents of the container
This function removes all the segments
from the container, leaving the
underlying URL with an empty path.
@par Postconditions
@code
empty() == true
@endcode
@par Exception Safety
Throws nothing.
*/
inline
void
clear() noexcept;
/** Insert an element
This function inserts a segment specified
by the percent-encoded string `s`, at the
position preceding `before`.
The string must contain a valid
percent-encoding, or else an exception
is thrown.
All references and iterators starting
from the newly inserted element and
up to and including the last element
and @ref end iterators are invalidated.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@return An iterator pointing to the
inserted value.
@param before An iterator before which the
new element should be inserted.
@param s A valid percent-encoded string
to be inserted.
@throw std::invalid_argument invalid percent-encoding
*/
BOOST_URL_DECL
iterator
insert(
const_iterator before,
string_view s);
/** Insert an element
This function inserts a segment specified
by the percent-encoded stringlike `t`,
at the position preceding `before`.
The stringlike must contain a valid
percent-encoding, or else an exception
is thrown.
All references and iterators starting
from the newly inserted element and
up to and including the last element
and @ref end iterators are invalidated.
This function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@return An iterator pointing to the
inserted value.
@param before An iterator before which the
new element should be inserted.
@param t The stringlike value to insert.
@throw std::invalid_argument invalid percent-encoding
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value,
bool>::type
#endif
>
iterator
insert(
const_iterator before,
T const& t);
/** Insert a range of segments
This function inserts a range
of percent-encoded strings.
Each string must contain a valid
percent-encoding or else an
exception is thrown.
The behavior is undefined if either
argument is an iterator into `this`.
All references and iterators starting
from the newly inserted elements and
up to and including the last element
and @ref end iterators are invalidated.
@par Requires
@code
is_stringlike< std::iterator_traits< FwdIt >::value_type >::value == true
@endcode
@par Example
@code
url u = parse_relative_uri( "/path/file.txt" );
segments se = u.segments();
std::vector< std::string > v = { "to", "the" };
se.insert( u.end() - 1, v.begin(), v.end() );
assert( u.encoded_path() == "/path/to/the/file.txt") );
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@return An iterator to one past the last
newly inserted element or `before` if
the range is empty.
@param before An iterator before which the
new element should be inserted.
@param first An iterator to the first
element to insert.
@param last An iterator to one past the
last element to insert.
@throw std::invalid_argument invalid percent-encoding
*/
template<class FwdIt>
#ifdef BOOST_URL_DOCS
iterator
#else
typename std::enable_if<
is_stringlike<typename
std::iterator_traits<
FwdIt>::value_type>::value,
iterator>::type
#endif
insert(
const_iterator before,
FwdIt first,
FwdIt last);
/** Insert a range of segments
This function inserts a range of
percent-encoded strings passed as
an initializer-list.
Each string must contain a valid
percent-encoding or else an exception
is thrown.
All references and iterators starting
from the newly inserted elements and
up to and including the last element
and @ref end iterators are invalidated.
@par Requires
@code
is_stringlike< T >::value == true
@endcode
@par Example
@code
url u = parse_relative_uri( "/path/file.txt" );
segments se = u.segments();
se.insert( u.end() - 1, { "to", "the" } );
assert( u.encoded_path() == "/path/to/the/file.txt") );
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@return An iterator to one past the last
newly inserted element or `before` if
the range is empty.
@param before An iterator before which the
new elements should be inserted.
@param init The initializer list containing
percent-encoded segments to insert.
@throw std::invalid_argument invalid percent-encoding
*/
template<class T>
#ifdef BOOST_URL_DOCS
iterator
#else
typename std::enable_if<
is_stringlike<T>::value,
iterator>::type
#endif
insert(
const_iterator before,
std::initializer_list<T> init);
/** Erase an element
This function erases the element pointed
to by `pos`, which must be a valid
iterator for the container.
All references and iterators starting
from pos and up to and including
the last element and @ref end iterators
are invalidated.
@par Preconditions
`pos` points to a valid element in
this container.
@par Example
@code
url u = parse_relative_uri( "/path/to/file.txt" );
segments se = u.segments();
se.erase( se.begin() + 1 );
assert( u.encoded_path() == "/path/file.txt" );
@endcode
@par Exception Safety
Throws nothing.
@return An iterator following
the last element erased.
@param pos An iterator to the
element to erase.
*/
inline
iterator
erase(
const_iterator pos) noexcept;
/** Erase a range of elements
This function erases the elements
in the range `[first, last)`, which
must be a valid range in the container.
All references and iterators starting
from `first` and up to and including
the last element and @ref end iterators
are invalidated.
@par Preconditions
`[first, last)` is a valid range in
this container.
@par Example
@code
url u = parse_relative_uri( "/path/to/the/file.txt" );
segments se = u.segments();
se.erase( se.begin() + 1, se.begin() + 3 );
assert( u.encoded_path() == "/path/file.txt" );
@endcode
@return An iterator following
the last element erased.
@param first The beginning of the
range to erase.
@param last The end of the range
to erase.
@throw std::invalid_argument invalid percent-encoding
*/
BOOST_URL_DECL
iterator
erase(
const_iterator first,
const_iterator last) noexcept;
/** Add an element to the end
This function appends a segment
containing the percent-encoded string
`s` to the end of the container.
The percent-encoding must be valid or
else an exception is thrown.
All @ref end iterators are invalidated.
@par Example
@code
url u = parse_relative_uri( "/path/to" );
u.segments().push_back( "file.txt" );
assert( u.encoded_path() == "/path/to/file.txt" );
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@param s The string to add
@throw std::invalid_argument invalid percent-encoding
*/
inline
void
push_back(
string_view s);
/** Add an element to the end
This function appends a segment
containing the percent-encoded stringlike
`t` to the end of the container.
The percent-encoding must be valid
or else an exception is thrown.
All @ref end iterators are invalidated.
The function participates in overload
resolution only if
`is_stringlike<T>::value == true`.
@par Example
@code
url u = parse_relative_uri( "/path/to" );
u.segments().push_back( "file.txt" );
assert( u.encoded_path() == "/path/to/file.txt" );
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
Exceptions thrown on invalid input.
@param t The stringlike to add
@throw std::invalid_argument invalid percent-encoding
*/
template<class T
#ifndef BOOST_URL_DOCS
, class = typename std::enable_if<
is_stringlike<T>::value,
bool>::type
#endif
>
void
push_back(
T const& t)
{
return push_back(
to_string_view(t));
}
/** Remove the last element
This function removes the last element
from the container, which must not be
empty or else undefined behavior occurs.
Iterators and references to
the last element, as well as the
@ref end iterator, are invalidated.
@par Preconditions
@code
not empty()
@endcode
@par Example
@code
url u = parse_relative_uri( "/path/to/file.txt" );
u.segments().pop_back();
assert( u.encoded_path() == "/path/to" );
@endcode
@par Exception Safety
Throws nothing.
*/
inline
void
pop_back() noexcept;
};
} // urls
} // boost
// VFALCO This include is at the bottom of
// url.hpp because of a circular dependency
//#include <boost/url/impl/segments.hpp>
#endif

View File

@@ -37,7 +37,6 @@ class segments_encoded_view
string_view s_;
std::size_t n_;
template<class Alloc>
friend class segments_view;
friend class url_view;

View File

@@ -12,50 +12,43 @@
#include <boost/url/detail/config.hpp>
#include <boost/url/string.hpp>
#include <boost/url/detail/pct_encoding.hpp>
#include <boost/url/rfc/pct_encoded_bnf.hpp>
#include <cstddef>
#include <iosfwd>
#include <utility>
namespace boost {
namespace urls {
class segments_encoded_view;
/** A BidirectionalRange view of read-only path segments with percent-decoding applied
*/
template<class Allocator>
class segments_view
{
string_view s_;
std::size_t n_;
Allocator a_;
string_value::allocator a_;
friend class url;
friend class url_view;
template<class Allocator>
segments_view(
string_view s,
std::size_t n,
Allocator const& alloc) noexcept
Allocator const& a)
: s_(s)
, n_(n)
, a_(alloc)
, a_(a)
{
}
public:
class iterator;
BOOST_URL_DECL
segments_view(
segments_view const&) noexcept = default;
segments_view& operator=(
segments_view const&) noexcept = default;
segments_view const&) noexcept;
explicit
segments_view(
segments_encoded_view const& sv,
Allocator const& = {}) noexcept;
segments_view& operator=(
segments_view const&) noexcept = delete;
/** Return true if the range contains no elements
*/
@@ -75,11 +68,13 @@ public:
/** Return an iterator to the beginning of the range
*/
BOOST_URL_DECL
iterator
begin() const noexcept;
/** Return an iterator to the end of the range
*/
BOOST_URL_DECL
iterator
end() const noexcept;
};

View File

@@ -37,6 +37,7 @@ in a translation unit of the program.
#include <boost/url/impl/scheme.ipp>
#include <boost/url/impl/segments_encoded.ipp>
#include <boost/url/impl/segments_encoded_view.ipp>
#include <boost/url/impl/segments_view.ipp>
#include <boost/url/impl/static_pool.ipp>
#include <boost/url/impl/static_url.ipp>
#include <boost/url/impl/url.ipp>

View File

@@ -21,13 +21,11 @@ namespace urls {
*/
class basic_static_pool
{
char* const base_;
std::size_t const capacity_;
char* begin_;
char* end_;
char* top_;
std::size_t n_ = 0;
struct item;
BOOST_URL_DECL
void*
allocate(
@@ -52,9 +50,9 @@ public:
basic_static_pool(
char* buffer,
std::size_t size)
: base_(buffer)
, capacity_(size)
, top_(buffer)
: begin_(buffer)
, end_(buffer + size)
, top_(end_)
{
}

View File

@@ -13,13 +13,13 @@
#include <boost/url/detail/config.hpp>
#include <boost/type_traits/make_void.hpp>
#include <boost/utility/string_view.hpp>
#include <memory>
#include <string>
#include <type_traits>
#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
#include <string_view>
#define BOOST_URL_HAS_STRING_VIEW
# include <string_view>
# define BOOST_URL_HAS_STRING_VIEW
#endif
#include <type_traits>
namespace boost {
namespace urls {
@@ -160,7 +160,54 @@ to_string_view(
}
#endif
//------------------------------------------------
class string_value : public string_view
{
struct base;
base* p_ = nullptr;
template<class Allocator>
base*
construct(
std::size_t n,
Allocator const& a,
char*& dest);
public:
class allocator;
inline
~string_value();
string_value() = default;
template<class Allocator>
string_value(
std::size_t n,
Allocator const& a,
char*& dest);
template< class Allocator =
std::allocator<char> >
explicit
string_value(
string_view s,
Allocator const& a = {});
inline
string_value(
string_value const& other) noexcept;
inline
string_value&
operator=(string_value const& other) noexcept;
};
} // urls
} // boost
#include <boost/url/impl/string.hpp>
#endif

View File

@@ -14,6 +14,7 @@
#include <boost/url/ipv4_address.hpp>
#include <boost/url/ipv6_address.hpp>
#include <boost/url/scheme.hpp>
#include <boost/url/segments.hpp>
#include <boost/url/segments_encoded.hpp>
#include <boost/url/url_view.hpp>
#include <boost/url/detail/pct_encoding.hpp>
@@ -57,8 +58,9 @@ struct any_path_iter;
class BOOST_SYMBOL_VISIBLE url
: public url_view
{
template<class Allocator>
friend class urls::segments;
friend class segments_encoded;
friend class segments_encoded::reference;
#ifndef BOOST_URL_DOCS
protected:
@@ -946,43 +948,13 @@ public:
/** Return a path segment by index
This function returns an indexed
path segment as a percent-encoded
string. The behavior depends on
`i`:
This function returns a zero-based,
indexed path segment as a percent-encoded
string.
@li If `i` is 0 the first path
segment is returned;
@li If `i` is positive, then
the `i` + 1th path segment is
returned. For example if `i == 2`
then the third segment is returned.
In other words, `i` is zero based.
@li If `i` is negative, then the
function negates `i`, and counts from
the end of the path rather than the
beginning. For example if `i == -1`
then the last path segment is returned.
If the `i` is out of range, an empty
string is returned. To determine the
number of segments, call @ref segment_count.
@par Example
@par Preconditions
@code
url_view u = parse_relative_ref( "/path/to/the/file.txt" );
assert( u.encoded_segment( -2 ) == "the" );
assert( u.encoded_segment( -1 ) == "file.txt" );
assert( u.encoded_segment( 0 ) == "path" );
assert( u.encoded_segment( 1 ) == "to" );
@endcode
@par BNF
@code
path = [ "/" ] segment *( "/" segment )
i < segment_count()
@endcode
@par Exception Safety
@@ -998,12 +970,17 @@ public:
virtual
string_view
encoded_segment(
int i) const noexcept override;
std::size_t i) const noexcept override;
BOOST_URL_DECL
segments_encoded
encoded_segments() noexcept;
template<class Allocator =
std::allocator<char>>
urls::segments<Allocator>
segments(Allocator const& = {}) noexcept;
//--------------------------------------------
//
// Query
@@ -1237,6 +1214,8 @@ operator<<(std::ostream& os, url const& u);
} // urls
} // boost
#include <boost/url/impl/segments.hpp>
#include <boost/url/impl/segments_encoded.hpp>
#include <boost/url/impl/url.hpp>
#endif

View File

@@ -15,6 +15,7 @@
#include <boost/url/ipv4_address.hpp>
#include <boost/url/ipv6_address.hpp>
#include <boost/url/scheme.hpp>
#include <boost/url/segments_encoded_view.hpp>
#include <boost/url/segments_view.hpp>
#include <boost/url/query_params_view.hpp>
#include <boost/url/scheme.hpp>
@@ -1344,44 +1345,10 @@ public:
/** Return a path segment by index
This function returns an indexed
path segment as a percent-encoded
string. The behavior depends on
`i`:
@li If `i` is 0 the first path
segment is returned;
@li If `i` is positive, then
the `i` + 1th path segment is
returned. For example if `i == 2`
then the third segment is returned.
In other words, `i` is zero based.
@li If `i` is negative, then the
function negates `i`, and counts from
the end of the path rather than the
beginning. For example if `i == -1`
then the last path segment is returned.
If the `i` is out of range, an empty
string is returned. To determine the
number of segments, call @ref segment_count.
@par Example
@code
url_view u = parse_relative_ref( "/path/to/the/file.txt" );
assert( u.encoded_segment( -2 ) == "the" );
assert( u.encoded_segment( -1 ) == "file.txt" );
assert( u.encoded_segment( 0 ) == "path" );
assert( u.encoded_segment( 1 ) == "to" );
@endcode
@par BNF
@code
path = [ "/" ] segment *( "/" segment )
@endcode
This function returns a zero-based,
indexed path segment as a percent-encoded
string. If `i >= segment_count()`, an
empty string is returned.
@par Exception Safety
Throws nothing.
@@ -1396,7 +1363,7 @@ public:
virtual
string_view
encoded_segment(
int i) const noexcept;
std::size_t i) const noexcept;
/** Return a path segment by index
@@ -1502,10 +1469,10 @@ public:
*/
template<class Allocator =
std::allocator<char>>
segments_view<Allocator>
segments_view
segments(Allocator const& alloc = {}) const noexcept
{
return segments_view<Allocator>(
return segments_view(
encoded_path(), nseg_, alloc);
}