hexdig_chars.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //
  2. // Copyright (c) 2021 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_HEXDIG_CHARS_HPP
  10. #define BOOST_URL_GRAMMAR_HEXDIG_CHARS_HPP
  11. #include <boost/url/detail/config.hpp>
  12. #include <boost/url/grammar/detail/charset.hpp>
  13. namespace boost {
  14. namespace urls {
  15. namespace grammar {
  16. namespace implementation_defined {
  17. struct hexdig_chars_t
  18. {
  19. /** Determine if a character is a hexadecimal digit
  20. @param c The character to test
  21. @return `true` if `c` is a hexadecimal digit.
  22. */
  23. constexpr
  24. bool
  25. operator()(char c) const noexcept
  26. {
  27. return
  28. (c >= '0' && c <= '9') ||
  29. (c >= 'A' && c <= 'F') ||
  30. (c >= 'a' && c <= 'f');
  31. }
  32. #ifdef BOOST_URL_USE_SSE2
  33. char const*
  34. find_if(
  35. char const* first,
  36. char const* last) const noexcept
  37. {
  38. return detail::find_if_pred(
  39. *this, first, last);
  40. }
  41. char const*
  42. find_if_not(
  43. char const* first,
  44. char const* last) const noexcept
  45. {
  46. return detail::find_if_not_pred(
  47. *this, first, last);
  48. }
  49. #endif
  50. };
  51. }
  52. /** The set of hexadecimal digits
  53. @par Example
  54. Character sets are used with rules and the
  55. functions @ref find_if and @ref find_if_not.
  56. @code
  57. system::result< core::string_view > rv = parse( "8086FC19", token_rule( hexdig_chars ) );
  58. @endcode
  59. @par BNF
  60. @code
  61. HEXDIG = DIGIT
  62. / "A" / "B" / "C" / "D" / "E" / "F"
  63. / "a" / "b" / "c" / "d" / "e" / "f"
  64. @endcode
  65. @note The RFCs are inconsistent on the case
  66. sensitivity of hexadecimal digits. Existing
  67. uses suggest case-insensitivity is a de-facto
  68. standard.
  69. @par Specification
  70. @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1"
  71. >B.1. Core Rules (rfc5234)</a>
  72. @li <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-1.2"
  73. >1.2. Syntax Notation (rfc7230)</a>
  74. @li <a href="https://datatracker.ietf.org/doc/html/rfc5952#section-2.3"
  75. >2.3. Uppercase or Lowercase (rfc5952)</a>
  76. @li <a href="https://datatracker.ietf.org/doc/html/rfc5952#section-4.3"
  77. >4.3. Lowercase (rfc5952)</a>
  78. @see
  79. @ref find_if,
  80. @ref find_if_not,
  81. @ref hexdig_value,
  82. @ref parse,
  83. @ref token_rule.
  84. */
  85. constexpr implementation_defined::hexdig_chars_t hexdig_chars{};
  86. /** Return the decimal value of a hex character
  87. This function returns the decimal
  88. value of a hexadecimal character,
  89. or -1 if the argument is not a
  90. valid hexadecimal digit.
  91. @par BNF
  92. @code
  93. HEXDIG = DIGIT
  94. / "A" / "B" / "C" / "D" / "E" / "F"
  95. / "a" / "b" / "c" / "d" / "e" / "f"
  96. @endcode
  97. @param ch The character to check
  98. @return The decimal value or -1
  99. */
  100. inline
  101. signed char
  102. hexdig_value(char ch) noexcept
  103. {
  104. // Idea for a switch statement to
  105. // minimize emitted assembly from
  106. // Glen Fernandes
  107. signed char res;
  108. switch(ch)
  109. {
  110. default: res = -1; break;
  111. case '0': res = 0; break;
  112. case '1': res = 1; break;
  113. case '2': res = 2; break;
  114. case '3': res = 3; break;
  115. case '4': res = 4; break;
  116. case '5': res = 5; break;
  117. case '6': res = 6; break;
  118. case '7': res = 7; break;
  119. case '8': res = 8; break;
  120. case '9': res = 9; break;
  121. case 'a': case 'A': res = 10; break;
  122. case 'b': case 'B': res = 11; break;
  123. case 'c': case 'C': res = 12; break;
  124. case 'd': case 'D': res = 13; break;
  125. case 'e': case 'E': res = 14; break;
  126. case 'f': case 'F': res = 15; break;
  127. }
  128. return res;
  129. }
  130. } // grammar
  131. } // urls
  132. } // boost
  133. #endif