range_rule.hpp 13 KB

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