range_rule.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_GRAMMAR_RANGE_RULE_HPP
  10. #define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
  11. #include <boost/url/detail/config.hpp>
  12. #include <boost/url/error.hpp>
  13. #include <boost/core/detail/string_view.hpp>
  14. #include <boost/url/grammar/parse.hpp>
  15. #include <boost/url/grammar/type_traits.hpp>
  16. #include <boost/static_assert.hpp>
  17. #include <cstddef>
  18. #include <iterator>
  19. #include <type_traits>
  20. #include <stddef.h> // ::max_align_t
  21. namespace boost {
  22. namespace urls {
  23. namespace grammar {
  24. /** A forward range of parsed elements
  25. Objects of this type are forward ranges
  26. returned when parsing using the
  27. @ref range_rule.
  28. Iteration is performed by re-parsing the
  29. underlying character buffer. Ownership
  30. of the buffer is not transferred; the
  31. caller is responsible for ensuring that
  32. the lifetime of the buffer extends until
  33. it is no longer referenced by the range.
  34. @note
  35. The implementation may use temporary,
  36. recycled storage for type-erasure. Objects
  37. of type `range` are intended to be used
  38. ephemerally. That is, for short durations
  39. such as within a function scope. If it is
  40. necessary to store the range for a long
  41. period of time or with static storage
  42. duration, it is necessary to copy the
  43. contents to an object of a different type.
  44. @tparam T The value type of the range
  45. @see
  46. @ref parse,
  47. @ref range_rule.
  48. */
  49. template<class T>
  50. class range
  51. {
  52. // buffer size for type-erased rule
  53. static constexpr
  54. std::size_t BufferSize = 128;
  55. struct small_buffer
  56. {
  57. alignas(alignof(::max_align_t))
  58. unsigned char buf[BufferSize];
  59. void const* addr() const noexcept
  60. {
  61. return buf;
  62. }
  63. void* addr() noexcept
  64. {
  65. return buf;
  66. }
  67. };
  68. small_buffer sb_;
  69. core::string_view s_;
  70. std::size_t n_ = 0;
  71. //--------------------------------------------
  72. struct any_rule;
  73. template<class R, bool>
  74. struct impl1;
  75. template<
  76. class R0, class R1, bool>
  77. struct impl2;
  78. template<
  79. class R0, class R1>
  80. friend struct range_rule_t;
  81. any_rule&
  82. get() noexcept
  83. {
  84. return *reinterpret_cast<
  85. any_rule*>(sb_.addr());
  86. }
  87. any_rule const&
  88. get() const noexcept
  89. {
  90. return *reinterpret_cast<
  91. any_rule const*>(
  92. sb_.addr());
  93. }
  94. template<class R>
  95. range(
  96. core::string_view s,
  97. std::size_t n,
  98. R const& r);
  99. template<
  100. class R0, class R1>
  101. range(
  102. core::string_view s,
  103. std::size_t n,
  104. R0 const& first,
  105. R1 const& next);
  106. public:
  107. /** The type of each element of the range
  108. */
  109. using value_type = T;
  110. /** The type of each element of the range
  111. */
  112. using reference = T const&;
  113. /** The type of each element of the range
  114. */
  115. using const_reference = T const&;
  116. /** Provided for compatibility, unused
  117. */
  118. using pointer = void const*;
  119. /** The type used to represent unsigned integers
  120. */
  121. using size_type = std::size_t;
  122. /** The type used to represent signed integers
  123. */
  124. using difference_type = std::ptrdiff_t;
  125. /** A constant, forward iterator to elements of the range
  126. */
  127. class iterator;
  128. /** A constant, forward iterator to elements of the range
  129. */
  130. using const_iterator = iterator;
  131. /** Destructor
  132. */
  133. ~range();
  134. /** Constructor
  135. Default-constructed ranges have
  136. zero elements.
  137. @par Exception Safety
  138. Throws nothing.
  139. */
  140. range() noexcept;
  141. /** Constructor
  142. The new range references the
  143. same underlying character buffer.
  144. Ownership is not transferred; the
  145. caller is responsible for ensuring
  146. that the lifetime of the buffer
  147. extends until it is no longer
  148. referenced. The moved-from object
  149. becomes as if default-constructed.
  150. @par Exception Safety
  151. Throws nothing.
  152. */
  153. range(range&&) noexcept;
  154. /** Constructor
  155. The copy references the same
  156. underlying character buffer.
  157. Ownership is not transferred; the
  158. caller is responsible for ensuring
  159. that the lifetime of the buffer
  160. extends until it is no longer
  161. referenced.
  162. @par Exception Safety
  163. Throws nothing.
  164. */
  165. range(range const&) noexcept;
  166. /** Assignment
  167. After the move, this references the
  168. same underlying character buffer. Ownership
  169. is not transferred; the caller is responsible
  170. for ensuring that the lifetime of the buffer
  171. extends until it is no longer referenced.
  172. The moved-from object becomes as if
  173. default-constructed.
  174. @par Exception Safety
  175. Throws nothing.
  176. */
  177. range&
  178. operator=(range&&) noexcept;
  179. /** Assignment
  180. The copy references the same
  181. underlying character buffer.
  182. Ownership is not transferred; the
  183. caller is responsible for ensuring
  184. that the lifetime of the buffer
  185. extends until it is no longer
  186. referenced.
  187. @par Exception Safety
  188. Throws nothing.
  189. */
  190. range&
  191. operator=(range const&) noexcept;
  192. /** Return an iterator to the beginning
  193. */
  194. iterator begin() const noexcept;
  195. /** Return an iterator to the end
  196. */
  197. iterator end() const noexcept;
  198. /** Return true if the range is empty
  199. */
  200. bool
  201. empty() const noexcept
  202. {
  203. return n_ == 0;
  204. }
  205. /** Return the number of elements in the range
  206. */
  207. std::size_t
  208. size() const noexcept
  209. {
  210. return n_;
  211. }
  212. /** Return the matching part of the string
  213. */
  214. core::string_view
  215. string() const noexcept
  216. {
  217. return s_;
  218. }
  219. };
  220. //------------------------------------------------
  221. #ifndef BOOST_URL_DOCS
  222. template<
  223. class R0,
  224. class R1 = void>
  225. struct range_rule_t;
  226. #endif
  227. //------------------------------------------------
  228. /** Match a repeating number of elements
  229. Elements are matched using the passed rule.
  230. <br>
  231. Normally when the rule returns an error,
  232. the range ends and the input is rewound to
  233. one past the last character that matched
  234. successfully. However, if the rule returns
  235. the special value @ref error::end_of_range, the
  236. input is not rewound. This allows for rules
  237. which consume input without producing
  238. elements in the range. For example, to
  239. relax the grammar for a comma-delimited
  240. list by allowing extra commas in between
  241. elements.
  242. @par Value Type
  243. @code
  244. using value_type = range< typename Rule::value_type >;
  245. @endcode
  246. @par Example
  247. Rules are used with the function @ref parse.
  248. @code
  249. // range = 1*( ";" token )
  250. system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
  251. range_rule(
  252. tuple_rule(
  253. squelch( delim_rule( ';' ) ),
  254. token_rule( alpha_chars ) ),
  255. 1 ) );
  256. @endcode
  257. @par BNF
  258. @code
  259. range = <N>*<M>next
  260. @endcode
  261. @par Specification
  262. @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
  263. >3.6. Variable Repetition (rfc5234)</a>
  264. @param next The rule to use for matching
  265. each element. The range extends until this
  266. rule returns an error.
  267. @param N The minimum number of elements for
  268. the range to be valid. If omitted, this
  269. defaults to zero.
  270. @param M The maximum number of elements for
  271. the range to be valid. If omitted, this
  272. defaults to unlimited.
  273. @see
  274. @ref alpha_chars,
  275. @ref delim_rule,
  276. @ref error::end_of_range,
  277. @ref parse,
  278. @ref range,
  279. @ref tuple_rule,
  280. @ref squelch.
  281. */
  282. #ifdef BOOST_URL_DOCS
  283. template<class Rule>
  284. constexpr
  285. __implementation_defined__
  286. range_rule(
  287. Rule next,
  288. std::size_t N = 0,
  289. std::size_t M =
  290. std::size_t(-1)) noexcept;
  291. #else
  292. template<class R>
  293. struct range_rule_t<R>
  294. {
  295. using value_type =
  296. range<typename R::value_type>;
  297. system::result<value_type>
  298. parse(
  299. char const*& it,
  300. char const* end) const;
  301. private:
  302. constexpr
  303. range_rule_t(
  304. R const& next,
  305. std::size_t N,
  306. std::size_t M) noexcept
  307. : next_(next)
  308. , N_(N)
  309. , M_(M)
  310. {
  311. }
  312. template<class R_>
  313. friend
  314. constexpr
  315. range_rule_t<R_>
  316. range_rule(
  317. R_ const& next,
  318. std::size_t N,
  319. std::size_t M) noexcept;
  320. R const next_;
  321. std::size_t N_;
  322. std::size_t M_;
  323. };
  324. template<class Rule>
  325. constexpr
  326. range_rule_t<Rule>
  327. range_rule(
  328. Rule const& next,
  329. std::size_t N = 0,
  330. std::size_t M =
  331. std::size_t(-1)) noexcept
  332. {
  333. // If you get a compile error here it
  334. // means that your rule does not meet
  335. // the type requirements. Please check
  336. // the documentation.
  337. static_assert(
  338. is_rule<Rule>::value,
  339. "Rule requirements not met");
  340. return range_rule_t<Rule>{
  341. next, N, M};
  342. }
  343. #endif
  344. //------------------------------------------------
  345. /** Match a repeating number of elements
  346. Two rules are used for match. The rule
  347. `first` is used for matching the first
  348. element, while the `next` rule is used
  349. to match every subsequent element.
  350. <br>
  351. Normally when the rule returns an error,
  352. the range ends and the input is rewound to
  353. one past the last character that matched
  354. successfully. However, if the rule returns
  355. the special value @ref error::end_of_range, the
  356. input is not rewound. This allows for rules
  357. which consume input without producing
  358. elements in the range. For example, to
  359. relax the grammar for a comma-delimited
  360. list by allowing extra commas in between
  361. elements.
  362. @par Value Type
  363. @code
  364. using value_type = range< typename Rule::value_type >;
  365. @endcode
  366. @par Example
  367. Rules are used with the function @ref parse.
  368. @code
  369. // range = [ token ] *( "," token )
  370. system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
  371. range_rule(
  372. token_rule( alpha_chars ), // first
  373. tuple_rule( // next
  374. squelch( delim_rule(',') ),
  375. token_rule( alpha_chars ) ) ) );
  376. @endcode
  377. @par BNF
  378. @code
  379. range = <1>*<1>first
  380. / first <N-1>*<M-1>next
  381. @endcode
  382. @par Specification
  383. @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
  384. >3.6. Variable Repetition (rfc5234)</a>
  385. @param first The rule to use for matching
  386. the first element. If this rule returns
  387. an error, the range is empty.
  388. @param next The rule to use for matching
  389. each subsequent element. The range extends
  390. until this rule returns an error.
  391. @param N The minimum number of elements for
  392. the range to be valid. If omitted, this
  393. defaults to zero.
  394. @param M The maximum number of elements for
  395. the range to be valid. If omitted, this
  396. defaults to unlimited.
  397. @see
  398. @ref alpha_chars,
  399. @ref delim_rule,
  400. @ref error::end_of_range,
  401. @ref parse,
  402. @ref range,
  403. @ref tuple_rule,
  404. @ref squelch.
  405. */
  406. #ifdef BOOST_URL_DOCS
  407. template<
  408. class Rule1, class Rule2>
  409. constexpr
  410. __implementation_defined__
  411. range_rule(
  412. Rule1 first,
  413. Rule2 next,
  414. std::size_t N = 0,
  415. std::size_t M =
  416. std::size_t(-1)) noexcept;
  417. #else
  418. template<class R0, class R1>
  419. struct range_rule_t
  420. {
  421. using value_type =
  422. range<typename R0::value_type>;
  423. system::result<value_type>
  424. parse(
  425. char const*& it,
  426. char const* end) const;
  427. private:
  428. constexpr
  429. range_rule_t(
  430. R0 const& first,
  431. R1 const& next,
  432. std::size_t N,
  433. std::size_t M) noexcept
  434. : first_(first)
  435. , next_(next)
  436. , N_(N)
  437. , M_(M)
  438. {
  439. }
  440. template<
  441. class R0_, class R1_>
  442. friend
  443. constexpr
  444. auto
  445. range_rule(
  446. R0_ const& first,
  447. R1_ const& next,
  448. std::size_t N,
  449. std::size_t M) noexcept ->
  450. #if 1
  451. typename std::enable_if<
  452. ! std::is_integral<R1_>::value,
  453. range_rule_t<R0_, R1_>>::type;
  454. #else
  455. range_rule_t<R0_, R1_>;
  456. #endif
  457. R0 const first_;
  458. R1 const next_;
  459. std::size_t N_;
  460. std::size_t M_;
  461. };
  462. template<
  463. class Rule1, class Rule2>
  464. constexpr
  465. auto
  466. range_rule(
  467. Rule1 const& first,
  468. Rule2 const& next,
  469. std::size_t N = 0,
  470. std::size_t M =
  471. std::size_t(-1)) noexcept ->
  472. #if 1
  473. typename std::enable_if<
  474. ! std::is_integral<Rule2>::value,
  475. range_rule_t<Rule1, Rule2>>::type
  476. #else
  477. range_rule_t<Rule1, Rule2>
  478. #endif
  479. {
  480. // If you get a compile error here it
  481. // means that your rule does not meet
  482. // the type requirements. Please check
  483. // the documentation.
  484. static_assert(
  485. is_rule<Rule1>::value,
  486. "Rule requirements not met");
  487. static_assert(
  488. is_rule<Rule2>::value,
  489. "Rule requirements not met");
  490. // If you get a compile error here it
  491. // means that your rules do not have
  492. // the exact same value_type. Please
  493. // check the documentation.
  494. static_assert(
  495. std::is_same<
  496. typename Rule1::value_type,
  497. typename Rule2::value_type>::value,
  498. "Rule requirements not met");
  499. return range_rule_t<Rule1, Rule2>{
  500. first, next, N, M};
  501. }
  502. #endif
  503. } // grammar
  504. } // urls
  505. } // boost
  506. #include <boost/url/grammar/impl/range_rule.hpp>
  507. #endif