unpack.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright (C) 2020 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_PARSER_DETAIL_TEXT_UNPACK_HPP
  7. #define BOOST_PARSER_DETAIL_TEXT_UNPACK_HPP
  8. #include <boost/parser/detail/text/transcode_iterator_fwd.hpp>
  9. #include <type_traits>
  10. #include <optional>
  11. namespace boost::parser::detail { namespace text {
  12. struct no_op_repacker
  13. {
  14. template<class T>
  15. T operator()(T x) const
  16. {
  17. return x;
  18. }
  19. };
  20. namespace detail {
  21. // Using this custom template is quite a bit faster than using lambdas.
  22. // Unexpected.
  23. template<
  24. typename RepackedIterator,
  25. typename I,
  26. typename S,
  27. typename Then,
  28. bool Bidi>
  29. struct repacker
  30. {
  31. repacker() = default;
  32. #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  33. template<bool Enable = Bidi, typename = std::enable_if_t<Enable>>
  34. #endif
  35. repacker(I first, S last, Then then)
  36. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  37. requires Bidi
  38. #endif
  39. : first{first},
  40. last{last},
  41. then{then}
  42. {}
  43. #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  44. template<bool Enable = !Bidi, typename = std::enable_if_t<Enable>>
  45. #endif
  46. repacker(S last, Then then)
  47. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  48. requires(!Bidi)
  49. #endif
  50. :
  51. last{last}, then{then}
  52. {}
  53. auto operator()(I it) const
  54. {
  55. if constexpr (Bidi) {
  56. return then(RepackedIterator(*first, it, last));
  57. } else {
  58. return then(RepackedIterator(it, last));
  59. }
  60. }
  61. std::optional<I> first;
  62. [[no_unique_address]] S last;
  63. [[no_unique_address]] Then then;
  64. };
  65. template<typename I, typename S, typename Repack>
  66. constexpr auto
  67. unpack_iterator_and_sentinel_impl(I first, S last, Repack repack);
  68. template<
  69. format FromFormat,
  70. format ToFormat,
  71. typename I,
  72. typename S,
  73. typename ErrorHandler,
  74. typename Repack>
  75. constexpr auto unpack_iterator_and_sentinel_impl(
  76. utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
  77. utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> last,
  78. Repack repack);
  79. template<
  80. format FromFormat,
  81. format ToFormat,
  82. typename I,
  83. typename S,
  84. typename ErrorHandler,
  85. typename Repack>
  86. constexpr auto unpack_iterator_and_sentinel_impl(
  87. utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
  88. S last,
  89. Repack repack);
  90. template<typename I, typename S, typename Repack>
  91. constexpr auto
  92. unpack_iterator_and_sentinel(I first, S last, Repack repack)
  93. {
  94. return detail::unpack_iterator_and_sentinel_impl(
  95. first, last, repack);
  96. }
  97. struct unpack_iterator_and_sentinel_cpo
  98. {
  99. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  100. template<
  101. utf_iter I,
  102. std::sentinel_for<I> S,
  103. typename Repack = no_op_repacker>
  104. requires std::forward_iterator<I>
  105. #else
  106. template<typename I, typename S, typename Repack = no_op_repacker>
  107. #endif
  108. constexpr auto
  109. operator()(I first, S last, Repack repack = Repack()) const
  110. {
  111. return unpack_iterator_and_sentinel(first, last, repack);
  112. }
  113. };
  114. }
  115. inline namespace cpo {
  116. inline constexpr detail::unpack_iterator_and_sentinel_cpo
  117. unpack_iterator_and_sentinel{};
  118. }
  119. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  120. template<format FormatTag, utf_iter I, std::sentinel_for<I> S, class Repack>
  121. #else
  122. template<format FormatTag, typename I, typename S, class Repack>
  123. #endif
  124. struct unpack_result
  125. {
  126. static constexpr format format_tag = FormatTag;
  127. I first;
  128. [[no_unique_address]] S last;
  129. [[no_unique_address]] Repack repack;
  130. };
  131. namespace detail {
  132. struct no_such_type
  133. {};
  134. template<typename I, typename S, typename Repack>
  135. constexpr auto
  136. unpack_iterator_and_sentinel_impl(I first, S last, Repack repack)
  137. {
  138. using value_type = detail::iter_value_t<I>;
  139. if constexpr (
  140. std::is_same_v<value_type, char>
  141. #if defined(__cpp_char8_t)
  142. || std::is_same_v<value_type, char8_t>
  143. #endif
  144. ) {
  145. return unpack_result<format::utf8, I, S, Repack>{
  146. first, last, repack};
  147. } else if constexpr (
  148. #if defined(_MSC_VER)
  149. std::is_same_v<value_type, wchar_t> ||
  150. #endif
  151. std::is_same_v<value_type, char16_t>) {
  152. return unpack_result<format::utf16, I, S, Repack>{
  153. first, last, repack};
  154. } else if constexpr (
  155. #if !defined(_MSC_VER)
  156. std::is_same_v<value_type, wchar_t> ||
  157. #endif
  158. std::is_same_v<value_type, char32_t>) {
  159. return unpack_result<format::utf32, I, S, Repack>{
  160. first, last, repack};
  161. } else {
  162. static_assert(
  163. std::is_same_v<Repack, no_such_type>,
  164. "Unpacked iterator is not a utf_iter!");
  165. return 0;
  166. }
  167. }
  168. }
  169. }}
  170. #include <boost/parser/detail/text/transcode_iterator.hpp>
  171. namespace boost::parser::detail { namespace text { namespace detail {
  172. template<
  173. format FromFormat,
  174. format ToFormat,
  175. typename I,
  176. typename S,
  177. typename ErrorHandler,
  178. typename Repack>
  179. constexpr auto unpack_iterator_and_sentinel_impl(
  180. utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
  181. utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> last,
  182. Repack repack)
  183. {
  184. using iterator = utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>;
  185. if constexpr (
  186. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  187. std::bidirectional_iterator<I>
  188. #else
  189. std::is_base_of_v<
  190. std::bidirectional_iterator_tag,
  191. typename std::iterator_traits<I>::iterator_category>
  192. #endif
  193. ) {
  194. return boost::parser::detail::text::unpack_iterator_and_sentinel(
  195. first.base(),
  196. last.base(),
  197. repacker<
  198. iterator,
  199. decltype(first.begin()),
  200. decltype(first.end()),
  201. Repack,
  202. true>(first.begin(), first.end(), repack));
  203. } else {
  204. return boost::parser::detail::text::unpack_iterator_and_sentinel(
  205. first.base(),
  206. last.base(),
  207. repacker<iterator, int, decltype(first.end()), Repack, false>(
  208. first.end(), repack));
  209. }
  210. }
  211. template<
  212. format FromFormat,
  213. format ToFormat,
  214. typename I,
  215. typename S,
  216. typename ErrorHandler,
  217. typename Repack>
  218. constexpr auto unpack_iterator_and_sentinel_impl(
  219. utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
  220. S last,
  221. Repack repack)
  222. {
  223. using iterator = utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>;
  224. if constexpr (
  225. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  226. std::bidirectional_iterator<I>
  227. #else
  228. std::is_base_of_v<
  229. std::bidirectional_iterator_tag,
  230. typename std::iterator_traits<I>::iterator_category>
  231. #endif
  232. ) {
  233. return boost::parser::detail::text::unpack_iterator_and_sentinel(
  234. first.base(),
  235. last,
  236. repacker<
  237. iterator,
  238. decltype(first.begin()),
  239. decltype(first.end()),
  240. Repack,
  241. true>(first.begin(), first.end(), repack));
  242. } else {
  243. return boost::parser::detail::text::unpack_iterator_and_sentinel(
  244. first.base(),
  245. last,
  246. repacker<iterator, int, S, Repack, false>(last, repack));
  247. }
  248. }
  249. }}}
  250. #endif