any_segments_iter.hpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/url
  8. //
  9. #ifndef BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP
  10. #define BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP
  11. #include <boost/url/pct_string_view.hpp>
  12. #include <boost/static_assert.hpp>
  13. #include <cstddef>
  14. #include <iterator>
  15. #include <type_traits>
  16. namespace boost {
  17. namespace urls {
  18. namespace detail {
  19. struct BOOST_SYMBOL_VISIBLE
  20. any_segments_iter
  21. {
  22. protected:
  23. explicit
  24. any_segments_iter(
  25. core::string_view s_ = {}) noexcept
  26. : s(s_)
  27. {
  28. }
  29. virtual ~any_segments_iter() = default;
  30. public:
  31. // this is adjusted
  32. // when self-intersecting
  33. core::string_view s;
  34. // the first segment,
  35. // to handle special cases
  36. core::string_view front;
  37. // quick number of segments
  38. // 0 = zero
  39. // 1 = one
  40. // 2 = two, or more
  41. int fast_nseg = 0;
  42. // whether the segments should encode colons
  43. // when we measure and copy. the calling
  44. // function uses this for the first
  45. // segment in some cases, such as:
  46. // "x:y:z" -> remove_scheme -> "y%3Az"
  47. // as "y:z" would no longer represent a path
  48. bool encode_colons = false;
  49. // Rewind the iterator to the beginning
  50. virtual void rewind() noexcept = 0;
  51. // Measure and increment the current
  52. // element. n is increased by the
  53. // encoded size. Returns false on
  54. // end of range.
  55. virtual bool measure(std::size_t& n) = 0;
  56. // Copy and increment the current
  57. // element, encoding as needed.
  58. virtual void copy(char*& dest,
  59. char const* end) noexcept = 0;
  60. };
  61. //------------------------------------------------
  62. //
  63. // segment_iter
  64. //
  65. //------------------------------------------------
  66. // A 1-segment range
  67. // allowing self-intersection
  68. struct BOOST_SYMBOL_VISIBLE
  69. segment_iter
  70. : any_segments_iter
  71. {
  72. virtual ~segment_iter() = default;
  73. explicit
  74. segment_iter(
  75. core::string_view s) noexcept;
  76. private:
  77. bool at_end_ = false;
  78. void rewind() noexcept override;
  79. bool measure(std::size_t&) noexcept override;
  80. void copy(char*&, char const*) noexcept override;
  81. };
  82. //------------------------------------------------
  83. //
  84. // segments_iter
  85. //
  86. //------------------------------------------------
  87. struct segments_iter_base
  88. {
  89. protected:
  90. BOOST_URL_DECL static void
  91. measure_impl(std::size_t&,
  92. core::string_view, bool) noexcept;
  93. BOOST_URL_DECL static void
  94. copy_impl(char*&, char const*,
  95. core::string_view, bool) noexcept;
  96. };
  97. // iterates segments in a
  98. // plain segment range
  99. template<class FwdIt>
  100. struct segments_iter
  101. : any_segments_iter
  102. , segments_iter_base
  103. {
  104. BOOST_STATIC_ASSERT(
  105. std::is_convertible<
  106. typename std::iterator_traits<
  107. FwdIt>::reference,
  108. core::string_view>::value);
  109. segments_iter(
  110. FwdIt first,
  111. FwdIt last) noexcept
  112. : it_(first)
  113. , it0_(first)
  114. , end_(last)
  115. {
  116. if(first != last)
  117. {
  118. front = *first;
  119. auto it = first;
  120. if(++it == last)
  121. fast_nseg = 1;
  122. else
  123. fast_nseg = 2;
  124. }
  125. else
  126. {
  127. fast_nseg = 0;
  128. }
  129. }
  130. private:
  131. FwdIt it_;
  132. FwdIt it0_;
  133. FwdIt end_;
  134. void
  135. rewind() noexcept override
  136. {
  137. it_ = it0_;
  138. }
  139. bool
  140. measure(
  141. std::size_t& n) noexcept override
  142. {
  143. if(it_ == end_)
  144. return false;
  145. measure_impl(n,
  146. detail::to_sv(*it_),
  147. encode_colons);
  148. ++it_;
  149. return true;
  150. }
  151. void
  152. copy(
  153. char*& dest,
  154. char const* end) noexcept override
  155. {
  156. copy_impl(dest, end,
  157. detail::to_sv(*it_++),
  158. encode_colons);
  159. }
  160. };
  161. //------------------------------------------------
  162. //
  163. // segment_encoded_iter
  164. //
  165. //------------------------------------------------
  166. // A 1-segment range
  167. // allowing self-intersection
  168. struct BOOST_SYMBOL_VISIBLE
  169. segment_encoded_iter
  170. : any_segments_iter
  171. {
  172. virtual ~segment_encoded_iter() = default;
  173. explicit
  174. segment_encoded_iter(
  175. pct_string_view const& s) noexcept;
  176. private:
  177. bool at_end_ = false;
  178. void rewind() noexcept override;
  179. bool measure(std::size_t&) noexcept override;
  180. void copy(char*&, char const*) noexcept override;
  181. };
  182. //------------------------------------------------
  183. //
  184. // segments_encoded_iter
  185. //
  186. //------------------------------------------------
  187. // Validating and copying from
  188. // a string of encoded segments
  189. struct segments_encoded_iter_base
  190. {
  191. protected:
  192. BOOST_URL_DECL static void
  193. measure_impl(std::size_t&,
  194. core::string_view, bool) noexcept;
  195. BOOST_URL_DECL static void
  196. copy_impl(char*&, char const*,
  197. core::string_view, bool) noexcept;
  198. };
  199. // iterates segments in an
  200. // encoded segment range
  201. template<class FwdIt>
  202. struct segments_encoded_iter
  203. : public any_segments_iter
  204. , public segments_encoded_iter_base
  205. {
  206. BOOST_STATIC_ASSERT(
  207. std::is_convertible<
  208. typename std::iterator_traits<
  209. FwdIt>::reference,
  210. core::string_view>::value);
  211. segments_encoded_iter(
  212. FwdIt first,
  213. FwdIt last)
  214. : it_(first)
  215. , it0_(first)
  216. , end_(last)
  217. {
  218. if(it_ != end_)
  219. {
  220. // throw on invalid input
  221. front = pct_string_view(
  222. detail::to_sv(*first));
  223. auto it = first;
  224. if(++it == last)
  225. fast_nseg = 1;
  226. else
  227. fast_nseg = 2;
  228. }
  229. else
  230. {
  231. fast_nseg = 0;
  232. }
  233. }
  234. private:
  235. FwdIt it_;
  236. FwdIt it0_;
  237. FwdIt end_;
  238. void
  239. rewind() noexcept override
  240. {
  241. it_ = it0_;
  242. }
  243. bool
  244. measure(
  245. std::size_t& n) override
  246. {
  247. if(it_ == end_)
  248. return false;
  249. // throw on invalid input
  250. measure_impl(n,
  251. pct_string_view(
  252. detail::to_sv(*it_++)),
  253. encode_colons);
  254. return true;
  255. }
  256. void
  257. copy(
  258. char*& dest,
  259. char const* end) noexcept override
  260. {
  261. copy_impl(dest, end,
  262. detail::to_sv(*it_++),
  263. encode_colons);
  264. }
  265. };
  266. //------------------------------------------------
  267. template<class FwdIt>
  268. segments_iter<FwdIt>
  269. make_segments_iter(
  270. FwdIt first, FwdIt last)
  271. {
  272. return segments_iter<
  273. FwdIt>(first, last);
  274. }
  275. template<class FwdIt>
  276. segments_encoded_iter<FwdIt>
  277. make_segments_encoded_iter(
  278. FwdIt first, FwdIt last)
  279. {
  280. return segments_encoded_iter<
  281. FwdIt>(first, last);
  282. }
  283. } // detail
  284. } // urls
  285. } // boost
  286. #endif