ext-boost/boost/url/detail/impl/params_iter_impl.ipp
2023-05-22 18:45:02 +10:00

246 lines
4.7 KiB
C++

//
// 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_IMPL_PARAMS_ITER_IMPL_IPP
#define BOOST_URL_DETAIL_IMPL_PARAMS_ITER_IMPL_IPP
#include <boost/url/detail/params_iter_impl.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace urls {
namespace detail {
/* index zero-based index of param
pos offset from start 0 = '?'
nk size of key with '?' or '&'
nv size of value with '='
dk decoded key size no '?' or '&'
dv decoded value size no '='
*/
params_iter_impl::
params_iter_impl(
query_ref const& ref_) noexcept
: ref(ref_)
, index(0)
, pos(0)
{
if(index < ref_.nparam())
setup();
}
params_iter_impl::
params_iter_impl(
query_ref const& ref_,
int) noexcept
: ref(ref_)
, index(ref_.nparam())
, pos(ref_.size())
{
}
params_iter_impl::
params_iter_impl(
query_ref const& ref_,
std::size_t pos_,
std::size_t index_) noexcept
: ref(ref_)
, index(index_)
, pos(pos_)
{
BOOST_ASSERT(
pos <= ref.size());
if(index < ref_.nparam())
setup();
}
// set up state for key/value at pos
void
params_iter_impl::
setup() noexcept
{
dk = 1;
dv = 0;
auto const end = ref.end();
BOOST_ASSERT(pos != ref.size());
auto p0 = ref.begin() + pos;
auto p = p0;
// key
for(;;)
{
if( p == end ||
*p == '&')
{
// no value
nk = 1 + p - p0;
dk = nk - dk;
nv = 0;
return;
}
if(*p == '=')
break;
if(*p == '%')
{
BOOST_ASSERT(
end - p >= 3);
dk += 2;
p += 2;
}
++p;
}
nk = 1 + p - p0;
dk = nk - dk;
p0 = p;
// value
for(;;)
{
++p;
if( p == end ||
*p == '&')
break;
if(*p == '%')
{
BOOST_ASSERT(
end - p >= 3);
dv += 2;
p += 2;
}
}
nv = p - p0;
dv = nv - dv - 1;
}
void
params_iter_impl::
increment() noexcept
{
BOOST_ASSERT(
index < ref.nparam());
pos += nk + nv;
++index;
if(index < ref.nparam())
setup();
}
void
params_iter_impl::
decrement() noexcept
{
BOOST_ASSERT(index > 0);
--index;
dk = 1; // for '&' or '?'
dv = 1; // for '='
auto const begin = ref.begin();
BOOST_ASSERT(pos > 0);
auto p1 = begin + (pos - 1);
auto p = p1;
// find key or '='
for(;;)
{
if(p == begin)
{
// key
nk = 1 + p1 - p; // with '?'
dk = nk - dv;
nv = 0;
dv = 0;
pos -= nk;
return;
}
else if(*--p == '&')
{
// key
nk = p1 - p; // with '&'
dk = nk - dv;
nv = 0;
dv = 0;
pos -= nk;
return;
}
if(*p == '=')
{
// value
nv = p1 - p; // with '='
break;
}
if(*p == '%')
dv += 2;
}
// find key and value
for(;;)
{
if(p == begin)
{
// key and value
nk = 1 + p1 - p - nv; // with '?'
dk = nk - dk;
dv = nv - dv;
pos -= nk + nv;
return;
}
if(*--p == '&')
{
// key and value
nk = p1 - p - nv; // with '&'
dk = nk - dk;
dv = nv - dv;
pos -= nk + nv;
return;
}
if(*p == '=')
{
// value
nv = p1 - p; // with '='
dv += dk;
dk = 0;
}
else if(*p == '%')
{
dk += 2;
}
}
}
param_pct_view
params_iter_impl::
dereference() const noexcept
{
BOOST_ASSERT(index < ref.nparam());
BOOST_ASSERT(pos < ref.size());
auto const p = ref.begin() + pos;
if(nv)
return {
make_pct_string_view_unsafe(
p, nk - 1, dk),
make_pct_string_view_unsafe(
p + nk, nv - 1, dv)};
return {
make_pct_string_view_unsafe(
p, nk - 1, dk),
no_value};
}
pct_string_view
params_iter_impl::
key() const noexcept
{
BOOST_ASSERT(index < ref.nparam());
BOOST_ASSERT(pos < ref.size());
auto const p = ref.begin() + pos;
return make_pct_string_view_unsafe(
p, nk - 1, dk);
}
} // detail
} // url
} // boost
#endif