ext-boost/boost/url/detail/any_segments_iter.hpp
2023-05-22 18:45:02 +10:00

369 lines
7.6 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_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(
string_view s_ = {}) noexcept
: s(s_)
{
}
virtual ~any_segments_iter() = default;
public:
// this is adjusted
// when self-intersecting
string_view s;
// the first segment,
// to handle special cases
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;
};
//------------------------------------------------
// iterates segments in a string
struct BOOST_SYMBOL_VISIBLE
path_iter
: any_segments_iter
{
virtual ~path_iter() = default;
explicit
path_iter(
string_view s) noexcept;
protected:
std::size_t pos_;
std::size_t next_;
void increment() noexcept;
void rewind() noexcept override;
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
// iterates segments in an encoded string
struct BOOST_SYMBOL_VISIBLE
path_encoded_iter
: public path_iter
{
virtual ~path_encoded_iter() = default;
explicit
path_encoded_iter(
pct_string_view s) noexcept;
private:
bool measure(std::size_t&) noexcept override;
void copy(char*&, char const*) noexcept override;
};
//------------------------------------------------
//
// 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(
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&,
string_view, bool) noexcept;
BOOST_URL_DECL static void
copy_impl(char*&, char const*,
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,
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&,
string_view, bool) noexcept;
BOOST_URL_DECL static void
copy_impl(char*&, char const*,
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,
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