Warning, file /include/boost/parser/detail/text/transcode_iterator.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006 #ifndef BOOST_PARSER_DETAIL_TEXT_TRANSCODE_ITERATOR_HPP
0007 #define BOOST_PARSER_DETAIL_TEXT_TRANSCODE_ITERATOR_HPP
0008
0009 #include <boost/parser/detail/debug_assert.hpp>
0010 #include <boost/parser/detail/text/transcode_iterator_fwd.hpp>
0011 #include <boost/parser/detail/text/concepts.hpp>
0012 #include <boost/parser/detail/text/utf.hpp>
0013 #include <boost/parser/detail/text/detail/algorithm.hpp>
0014
0015 #include <boost/parser/detail/stl_interfaces/iterator_interface.hpp>
0016
0017 #include <array>
0018 #include <iterator>
0019 #include <type_traits>
0020 #include <stdexcept>
0021 #include <string_view>
0022
0023 namespace boost::parser::detail { namespace text {
0024
0025 namespace {
0026 constexpr char16_t high_surrogate_base = 0xd7c0;
0027 constexpr char16_t low_surrogate_base = 0xdc00;
0028 constexpr char32_t high_surrogate_min = 0xd800;
0029 constexpr char32_t high_surrogate_max = 0xdbff;
0030 constexpr char32_t low_surrogate_min = 0xdc00;
0031 constexpr char32_t low_surrogate_max = 0xdfff;
0032 constexpr char32_t replacement_character = 0xfffd;
0033 }
0034
0035 namespace detail {
0036 constexpr bool in(unsigned char lo, unsigned char c, unsigned char hi)
0037 {
0038 return lo <= c && c <= hi;
0039 }
0040
0041 struct throw_on_encoding_error
0042 {};
0043
0044 template<typename OutIter>
0045 inline constexpr OutIter read_into_buf(char32_t cp, OutIter buf)
0046 {
0047 if (cp < 0x80) {
0048 *buf = static_cast<char>(cp);
0049 ++buf;
0050 } else if (cp < 0x800) {
0051 *buf = static_cast<char>(0xC0 + (cp >> 6));
0052 ++buf;
0053 *buf = static_cast<char>(0x80 + (cp & 0x3f));
0054 ++buf;
0055 } else if (cp < 0x10000) {
0056 *buf = static_cast<char>(0xe0 + (cp >> 12));
0057 ++buf;
0058 *buf = static_cast<char>(0x80 + ((cp >> 6) & 0x3f));
0059 ++buf;
0060 *buf = static_cast<char>(0x80 + (cp & 0x3f));
0061 ++buf;
0062 } else {
0063 *buf = static_cast<char>(0xf0 + (cp >> 18));
0064 ++buf;
0065 *buf = static_cast<char>(0x80 + ((cp >> 12) & 0x3f));
0066 ++buf;
0067 *buf = static_cast<char>(0x80 + ((cp >> 6) & 0x3f));
0068 ++buf;
0069 *buf = static_cast<char>(0x80 + (cp & 0x3f));
0070 ++buf;
0071 }
0072 return buf;
0073 }
0074
0075 template<typename OutIter>
0076 constexpr OutIter write_cp_utf8(char32_t cp, OutIter out)
0077 {
0078 return detail::read_into_buf(cp, out);
0079 }
0080
0081 template<typename OutIter>
0082 constexpr OutIter write_cp_utf16(char32_t cp, OutIter out)
0083 {
0084 if (cp < 0x10000) {
0085 *out = static_cast<char16_t>(cp);
0086 ++out;
0087 } else {
0088 *out = static_cast<char16_t>(cp >> 10) + high_surrogate_base;
0089 ++out;
0090 *out = static_cast<char16_t>(cp & 0x3ff) + low_surrogate_base;
0091 ++out;
0092 }
0093 return out;
0094 }
0095
0096 inline constexpr char32_t surrogates_to_cp(char16_t hi, char16_t lo)
0097 {
0098 return char32_t((hi - high_surrogate_base) << 10) +
0099 (lo - low_surrogate_base);
0100 }
0101
0102 template<typename T, typename U>
0103 using enable_utf8_cp = std::enable_if<is_char_iter_v<T>, U>;
0104 template<typename T, typename U = T>
0105 using enable_utf8_cp_t = typename enable_utf8_cp<T, U>::type;
0106
0107 template<typename T, typename U>
0108 using enable_utf16_cp = std::enable_if<is_16_iter_v<T>, U>;
0109 template<typename T, typename U = T>
0110 using enable_utf16_cp_t = typename enable_utf16_cp<T, U>::type;
0111
0112 template<typename I>
0113 auto bidirectional_at_most()
0114 {
0115 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0116 if constexpr (std::bidirectional_iterator<I>) {
0117 return std::bidirectional_iterator_tag{};
0118 } else if constexpr (std::forward_iterator<I>) {
0119 return std::forward_iterator_tag{};
0120 } else if constexpr (std::input_iterator<I>) {
0121 return std::input_iterator_tag{};
0122 }
0123 #else
0124 using category =
0125 typename std::iterator_traits<I>::iterator_category;
0126 if constexpr (std::is_base_of_v<
0127 std::bidirectional_iterator_tag,
0128 category>) {
0129 return std::bidirectional_iterator_tag{};
0130 } else {
0131 return category{};
0132 }
0133 #endif
0134 }
0135
0136 template<typename I>
0137 using bidirectional_at_most_t = decltype(bidirectional_at_most<I>());
0138 }
0139
0140
0141 inline constexpr bool surrogate(char32_t c)
0142 {
0143 return high_surrogate_min <= c && c <= low_surrogate_max;
0144 }
0145
0146
0147 inline constexpr bool high_surrogate(char32_t c)
0148 {
0149 return high_surrogate_min <= c && c <= high_surrogate_max;
0150 }
0151
0152
0153 inline constexpr bool low_surrogate(char32_t c)
0154 {
0155 return low_surrogate_min <= c && c <= low_surrogate_max;
0156 }
0157
0158
0159
0160
0161 inline constexpr bool reserved_noncharacter(char32_t c)
0162 {
0163 bool const byte01_reserved = (c & 0xffff) >= 0xfffe;
0164 bool const byte2_at_most_0x10 = ((c & 0xff0000u) >> 16) <= 0x10;
0165 return (byte01_reserved && byte2_at_most_0x10) ||
0166 (0xfdd0 <= c && c <= 0xfdef);
0167 }
0168
0169
0170
0171
0172 inline constexpr bool scalar_value(char32_t c)
0173 {
0174 return c <= 0x10ffff && !surrogate(c);
0175 }
0176
0177
0178
0179
0180
0181 inline constexpr bool unreserved_scalar_value(char32_t c)
0182 {
0183 return scalar_value(c) && !reserved_noncharacter(c);
0184 }
0185
0186
0187
0188 constexpr bool lead_code_unit(char8_type c)
0189 {
0190 return uint8_t((unsigned char)c - 0xc2) <= 0x32;
0191 }
0192
0193
0194 constexpr bool continuation(char8_type c) { return (int8_t)c < -0x40; }
0195
0196
0197
0198
0199
0200 inline constexpr int utf8_code_units(char8_type first_unit_)
0201 {
0202 auto first_unit = (unsigned int)first_unit_;
0203 return first_unit <= 0x7f ? 1
0204 : boost::parser::detail::text::lead_code_unit(first_unit)
0205 ? int(0xe0 <= first_unit) + int(0xf0 <= first_unit) + 2
0206 : -1;
0207 }
0208
0209
0210
0211
0212
0213 inline constexpr int utf16_code_units(char16_t first_unit)
0214 {
0215 if (boost::parser::detail::text::low_surrogate(first_unit))
0216 return -1;
0217 if (boost::parser::detail::text::high_surrogate(first_unit))
0218 return 2;
0219 return 1;
0220 }
0221
0222 namespace detail {
0223
0224 template<typename Iter>
0225 struct optional_iter
0226 {
0227 constexpr optional_iter() : it_(), valid_(false) {}
0228 constexpr optional_iter(Iter it) : it_(it), valid_(true) {}
0229
0230 constexpr operator bool() const { return valid_; }
0231 constexpr Iter operator*() const
0232 {
0233 BOOST_PARSER_DEBUG_ASSERT(valid_);
0234 return it_;
0235 }
0236 Iter & operator*()
0237 {
0238 BOOST_PARSER_DEBUG_ASSERT(valid_);
0239 return it_;
0240 }
0241
0242 friend BOOST_PARSER_CONSTEXPR bool
0243 operator==(optional_iter lhs, optional_iter rhs)
0244 {
0245 return lhs.valid_ == rhs.valid_ &&
0246 (!lhs.valid_ || lhs.it_ == rhs.it_);
0247 }
0248 friend BOOST_PARSER_CONSTEXPR bool
0249 operator!=(optional_iter lhs, optional_iter rhs)
0250 {
0251 return !(lhs == rhs);
0252 }
0253
0254 private:
0255 Iter it_;
0256 bool valid_;
0257 };
0258
0259
0260 template<typename Iter>
0261 constexpr optional_iter<Iter> end_of_invalid_utf8(Iter it)
0262 {
0263 BOOST_PARSER_DEBUG_ASSERT(!boost::parser::detail::text::continuation(*it));
0264
0265 if (detail::in(0, *it, 0x7f))
0266 return optional_iter<Iter>{};
0267
0268 if (detail::in(0xc2, *it, 0xdf)) {
0269 auto next = it;
0270 if (!boost::parser::detail::text::continuation(*++next))
0271 return next;
0272 return optional_iter<Iter>{};
0273 }
0274
0275 if (detail::in(0xe0, *it, 0xe0)) {
0276 auto next = it;
0277 if (!detail::in(0xa0, *++next, 0xbf))
0278 return next;
0279 if (!boost::parser::detail::text::continuation(*++next))
0280 return next;
0281 return optional_iter<Iter>{};
0282 }
0283 if (detail::in(0xe1, *it, 0xec)) {
0284 auto next = it;
0285 if (!boost::parser::detail::text::continuation(*++next))
0286 return next;
0287 if (!boost::parser::detail::text::continuation(*++next))
0288 return next;
0289 return optional_iter<Iter>{};
0290 }
0291 if (detail::in(0xed, *it, 0xed)) {
0292 auto next = it;
0293 if (!detail::in(0x80, *++next, 0x9f))
0294 return next;
0295 if (!boost::parser::detail::text::continuation(*++next))
0296 return next;
0297 return optional_iter<Iter>{};
0298 }
0299 if (detail::in(0xee, *it, 0xef)) {
0300 auto next = it;
0301 if (!boost::parser::detail::text::continuation(*++next))
0302 return next;
0303 if (!boost::parser::detail::text::continuation(*++next))
0304 return next;
0305 return optional_iter<Iter>{};
0306 }
0307
0308 if (detail::in(0xf0, *it, 0xf0)) {
0309 auto next = it;
0310 if (!detail::in(0x90, *++next, 0xbf))
0311 return next;
0312 if (!boost::parser::detail::text::continuation(*++next))
0313 return next;
0314 if (!boost::parser::detail::text::continuation(*++next))
0315 return next;
0316 return optional_iter<Iter>{};
0317 }
0318 if (detail::in(0xf1, *it, 0xf3)) {
0319 auto next = it;
0320 if (!boost::parser::detail::text::continuation(*++next))
0321 return next;
0322 if (!boost::parser::detail::text::continuation(*++next))
0323 return next;
0324 if (!boost::parser::detail::text::continuation(*++next))
0325 return next;
0326 return optional_iter<Iter>{};
0327 }
0328 if (detail::in(0xf4, *it, 0xf4)) {
0329 auto next = it;
0330 if (!detail::in(0x80, *++next, 0x8f))
0331 return next;
0332 if (!boost::parser::detail::text::continuation(*++next))
0333 return next;
0334 if (!boost::parser::detail::text::continuation(*++next))
0335 return next;
0336 return optional_iter<Iter>{};
0337 }
0338
0339 return it;
0340 }
0341
0342 template<typename Iter>
0343 constexpr Iter decrement(Iter it)
0344 {
0345 Iter retval = it;
0346
0347 int backup = 0;
0348 while (backup < 4 && boost::parser::detail::text::continuation(*--retval)) {
0349 ++backup;
0350 }
0351 backup = it - retval;
0352
0353 if (boost::parser::detail::text::continuation(*retval))
0354 return it - 1;
0355
0356 optional_iter<Iter> first_invalid = end_of_invalid_utf8(retval);
0357 if (first_invalid == retval)
0358 ++*first_invalid;
0359 while (first_invalid && (*first_invalid - retval) < backup) {
0360 backup -= *first_invalid - retval;
0361 retval = *first_invalid;
0362 first_invalid = end_of_invalid_utf8(retval);
0363 if (first_invalid == retval)
0364 ++*first_invalid;
0365 }
0366
0367 if (1 < backup) {
0368 int const cp_bytes = boost::parser::detail::text::utf8_code_units(*retval);
0369 if (cp_bytes < backup)
0370 retval = it - 1;
0371 }
0372
0373 return retval;
0374 }
0375
0376 template<typename Iter>
0377 constexpr Iter decrement(Iter first, Iter it)
0378 {
0379 Iter retval = it;
0380
0381 int backup = 0;
0382 while (backup < 4 && retval != first &&
0383 boost::parser::detail::text::continuation(*--retval)) {
0384 ++backup;
0385 }
0386 backup = (int)std::distance(retval, it);
0387
0388 if (boost::parser::detail::text::continuation(*retval)) {
0389 if (it != first)
0390 --it;
0391 return it;
0392 }
0393
0394 optional_iter<Iter> first_invalid = end_of_invalid_utf8(retval);
0395 if (first_invalid == retval)
0396 ++*first_invalid;
0397 while (first_invalid &&
0398 std::distance(retval, *first_invalid) < backup) {
0399 backup -= (int)std::distance(retval, *first_invalid);
0400 retval = *first_invalid;
0401 first_invalid = end_of_invalid_utf8(retval);
0402 if (first_invalid == retval)
0403 ++*first_invalid;
0404 }
0405
0406 if (1 < backup) {
0407 int const cp_bytes = boost::parser::detail::text::utf8_code_units(*retval);
0408 if (cp_bytes < backup) {
0409 if (it != first)
0410 --it;
0411 retval = it;
0412 }
0413 }
0414
0415 return retval;
0416 }
0417
0418 enum char_class : uint8_t {
0419 ill = 0,
0420 asc = 1,
0421 cr1 = 2,
0422 cr2 = 3,
0423 cr3 = 4,
0424 l2a = 5,
0425 l3a = 6,
0426 l3b = 7,
0427 l3c = 8,
0428 l4a = 9,
0429 l4b = 10,
0430 l4c = 11,
0431 };
0432
0433 enum table_state : uint8_t {
0434 bgn = 0,
0435 e_d = bgn,
0436 err = 12,
0437 cs1 = 24,
0438 cs2 = 36,
0439 cs3 = 48,
0440 p3a = 60,
0441 p3b = 72,
0442 p4a = 84,
0443 p4b = 96,
0444 invalid_table_state = 200
0445 };
0446
0447 struct first_cu
0448 {
0449 unsigned char initial_octet;
0450 table_state next;
0451 };
0452
0453 namespace {
0454 constexpr first_cu first_cus[256] = {
0455 {0x00, bgn}, {0x01, bgn}, {0x02, bgn}, {0x03, bgn}, {0x04, bgn},
0456 {0x05, bgn}, {0x06, bgn}, {0x07, bgn}, {0x08, bgn}, {0x09, bgn},
0457 {0x0a, bgn}, {0x0b, bgn}, {0x0c, bgn}, {0x0d, bgn}, {0x0e, bgn},
0458 {0x0f, bgn}, {0x10, bgn}, {0x11, bgn}, {0x12, bgn}, {0x13, bgn},
0459 {0x14, bgn}, {0x15, bgn}, {0x16, bgn}, {0x17, bgn}, {0x18, bgn},
0460 {0x19, bgn}, {0x1a, bgn}, {0x1b, bgn}, {0x1c, bgn}, {0x1d, bgn},
0461 {0x1e, bgn}, {0x1f, bgn}, {0x20, bgn}, {0x21, bgn}, {0x22, bgn},
0462 {0x23, bgn}, {0x24, bgn}, {0x25, bgn}, {0x26, bgn}, {0x27, bgn},
0463 {0x28, bgn}, {0x29, bgn}, {0x2a, bgn}, {0x2b, bgn}, {0x2c, bgn},
0464 {0x2d, bgn}, {0x2e, bgn}, {0x2f, bgn}, {0x30, bgn}, {0x31, bgn},
0465 {0x32, bgn}, {0x33, bgn}, {0x34, bgn}, {0x35, bgn}, {0x36, bgn},
0466 {0x37, bgn}, {0x38, bgn}, {0x39, bgn}, {0x3a, bgn}, {0x3b, bgn},
0467 {0x3c, bgn}, {0x3d, bgn}, {0x3e, bgn}, {0x3f, bgn}, {0x40, bgn},
0468 {0x41, bgn}, {0x42, bgn}, {0x43, bgn}, {0x44, bgn}, {0x45, bgn},
0469 {0x46, bgn}, {0x47, bgn}, {0x48, bgn}, {0x49, bgn}, {0x4a, bgn},
0470 {0x4b, bgn}, {0x4c, bgn}, {0x4d, bgn}, {0x4e, bgn}, {0x4f, bgn},
0471 {0x50, bgn}, {0x51, bgn}, {0x52, bgn}, {0x53, bgn}, {0x54, bgn},
0472 {0x55, bgn}, {0x56, bgn}, {0x57, bgn}, {0x58, bgn}, {0x59, bgn},
0473 {0x5a, bgn}, {0x5b, bgn}, {0x5c, bgn}, {0x5d, bgn}, {0x5e, bgn},
0474 {0x5f, bgn}, {0x60, bgn}, {0x61, bgn}, {0x62, bgn}, {0x63, bgn},
0475 {0x64, bgn}, {0x65, bgn}, {0x66, bgn}, {0x67, bgn}, {0x68, bgn},
0476 {0x69, bgn}, {0x6a, bgn}, {0x6b, bgn}, {0x6c, bgn}, {0x6d, bgn},
0477 {0x6e, bgn}, {0x6f, bgn}, {0x70, bgn}, {0x71, bgn}, {0x72, bgn},
0478 {0x73, bgn}, {0x74, bgn}, {0x75, bgn}, {0x76, bgn}, {0x77, bgn},
0479 {0x78, bgn}, {0x79, bgn}, {0x7a, bgn}, {0x7b, bgn}, {0x7c, bgn},
0480 {0x7d, bgn}, {0x7e, bgn}, {0x7f, bgn}, {0x00, err}, {0x01, err},
0481 {0x02, err}, {0x03, err}, {0x04, err}, {0x05, err}, {0x06, err},
0482 {0x07, err}, {0x08, err}, {0x09, err}, {0x0a, err}, {0x0b, err},
0483 {0x0c, err}, {0x0d, err}, {0x0e, err}, {0x0f, err}, {0x10, err},
0484 {0x11, err}, {0x12, err}, {0x13, err}, {0x14, err}, {0x15, err},
0485 {0x16, err}, {0x17, err}, {0x18, err}, {0x19, err}, {0x1a, err},
0486 {0x1b, err}, {0x1c, err}, {0x1d, err}, {0x1e, err}, {0x1f, err},
0487 {0x20, err}, {0x21, err}, {0x22, err}, {0x23, err}, {0x24, err},
0488 {0x25, err}, {0x26, err}, {0x27, err}, {0x28, err}, {0x29, err},
0489 {0x2a, err}, {0x2b, err}, {0x2c, err}, {0x2d, err}, {0x2e, err},
0490 {0x2f, err}, {0x30, err}, {0x31, err}, {0x32, err}, {0x33, err},
0491 {0x34, err}, {0x35, err}, {0x36, err}, {0x37, err}, {0x38, err},
0492 {0x39, err}, {0x3a, err}, {0x3b, err}, {0x3c, err}, {0x3d, err},
0493 {0x3e, err}, {0x3f, err}, {0xc0, err}, {0xc1, err}, {0x02, cs1},
0494 {0x03, cs1}, {0x04, cs1}, {0x05, cs1}, {0x06, cs1}, {0x07, cs1},
0495 {0x08, cs1}, {0x09, cs1}, {0x0a, cs1}, {0x0b, cs1}, {0x0c, cs1},
0496 {0x0d, cs1}, {0x0e, cs1}, {0x0f, cs1}, {0x10, cs1}, {0x11, cs1},
0497 {0x12, cs1}, {0x13, cs1}, {0x14, cs1}, {0x15, cs1}, {0x16, cs1},
0498 {0x17, cs1}, {0x18, cs1}, {0x19, cs1}, {0x1a, cs1}, {0x1b, cs1},
0499 {0x1c, cs1}, {0x1d, cs1}, {0x1e, cs1}, {0x1f, cs1}, {0x00, p3a},
0500 {0x01, cs2}, {0x02, cs2}, {0x03, cs2}, {0x04, cs2}, {0x05, cs2},
0501 {0x06, cs2}, {0x07, cs2}, {0x08, cs2}, {0x09, cs2}, {0x0a, cs2},
0502 {0x0b, cs2}, {0x0c, cs2}, {0x0d, p3b}, {0x0e, cs2}, {0x0f, cs2},
0503 {0x00, p4a}, {0x01, cs3}, {0x02, cs3}, {0x03, cs3}, {0x04, p4b},
0504 {0xf5, err}, {0xf6, err}, {0xf7, err}, {0xf8, err}, {0xf9, err},
0505 {0xfa, err}, {0xfb, err}, {0xfc, err}, {0xfd, err}, {0xfe, err},
0506 {0xff, err},
0507 };
0508
0509 constexpr char_class octet_classes[256] = {
0510 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0511 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0512 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0513 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0514 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0515 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0516 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0517 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0518 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc,
0519 asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, asc, cr1, cr1,
0520 cr1, cr1, cr1, cr1, cr1, cr1, cr1, cr1, cr1, cr1, cr1, cr1, cr1,
0521 cr1, cr2, cr2, cr2, cr2, cr2, cr2, cr2, cr2, cr2, cr2, cr2, cr2,
0522 cr2, cr2, cr2, cr2, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3,
0523 cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3,
0524 cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, cr3, ill, ill, l2a,
0525 l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a,
0526 l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a, l2a,
0527 l2a, l2a, l2a, l3a, l3b, l3b, l3b, l3b, l3b, l3b, l3b, l3b, l3b,
0528 l3b, l3b, l3b, l3c, l3b, l3b, l4a, l4b, l4b, l4b, l4c, ill, ill,
0529 ill, ill, ill, ill, ill, ill, ill, ill, ill,
0530 };
0531
0532 constexpr table_state transitions[108] = {
0533 err, e_d, err, err, err, cs1, p3a, cs2, p3b, p4a, cs3, p4b,
0534 err, err, err, err, err, err, err, err, err, err, err, err,
0535 err, err, e_d, e_d, e_d, err, err, err, err, err, err, err,
0536 err, err, cs1, cs1, cs1, err, err, err, err, err, err, err,
0537 err, err, cs2, cs2, cs2, err, err, err, err, err, err, err,
0538 err, err, err, err, cs1, err, err, err, err, err, err, err,
0539 err, err, cs1, cs1, err, err, err, err, err, err, err, err,
0540 err, err, err, cs2, cs2, err, err, err, err, err, err, err,
0541 err, err, cs2, err, err, err, err, err, err, err, err, err,
0542 };
0543 }
0544
0545 template<typename InputIter, typename Sentinel>
0546 char32_t advance(InputIter & first, Sentinel last)
0547 {
0548 char32_t retval = 0;
0549
0550 first_cu const info = first_cus[(unsigned char)*first];
0551 ++first;
0552
0553 retval = info.initial_octet;
0554 int state = info.next;
0555
0556 while (state != bgn) {
0557 if (first != last) {
0558 unsigned char const cu = *first;
0559 retval = (retval << 6) | (cu & 0x3f);
0560 char_class const class_ = octet_classes[cu];
0561 state = transitions[state + class_];
0562 if (state == err)
0563 return replacement_character;
0564 ++first;
0565 } else {
0566 return replacement_character;
0567 }
0568 }
0569
0570 return retval;
0571 }
0572
0573 template<typename Derived, typename Iter>
0574 struct trans_ins_iter
0575 {
0576 using value_type = void;
0577 using difference_type =
0578 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0579 std::ptrdiff_t;
0580 #else
0581 void;
0582 #endif
0583 using pointer = void;
0584 using reference = void;
0585 using iterator_category = std::output_iterator_tag;
0586
0587 constexpr trans_ins_iter() {}
0588 constexpr trans_ins_iter(Iter it) : it_(it) {}
0589 constexpr Derived & operator*() { return derived(); }
0590 constexpr Derived & operator++() { return derived(); }
0591 constexpr Derived operator++(int) { return derived(); }
0592 constexpr Iter base() const { return it_; }
0593
0594 protected:
0595 constexpr Iter & iter() { return it_; }
0596
0597 private:
0598 constexpr Derived & derived()
0599 {
0600 return static_cast<Derived &>(*this);
0601 }
0602 Iter it_;
0603 };
0604
0605 template<typename Derived, typename I, typename ValueType>
0606 using trans_iter = stl_interfaces::iterator_interface<
0607 Derived,
0608 bidirectional_at_most_t<I>,
0609 ValueType,
0610 ValueType>;
0611 }
0612
0613 }}
0614
0615 namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V1 {
0616
0617 #if defined(BOOST_TEXT_DOXYGEN)
0618
0619
0620
0621
0622 template<utf8_range R>
0623 requires std::ranges::forward_range<R>
0624 constexpr std::ranges::borrowed_iterator_t<R> find_invalid_encoding(R && r);
0625
0626
0627
0628
0629 template<utf16_range R>
0630 requires std::ranges::forward_range<R>
0631 constexpr std::ranges::borrowed_iterator_t<R> find_invalid_encoding(R && r);
0632
0633
0634 template<utf8_range R>
0635 requires std::ranges::forward_range<R>
0636 constexpr bool encoded(R && r);
0637
0638
0639 template<utf16_range R>
0640 requires std::ranges::forward_range<R>
0641 constexpr bool encoded(R && r);
0642
0643
0644
0645 template<utf8_range R>
0646 requires std::ranges::forward_range<R>
0647 constexpr bool starts_encoded(R && r);
0648
0649
0650
0651 template<utf16_range R>
0652 requires std::ranges::forward_range<R>
0653 constexpr bool starts_encoded(R && r);
0654
0655
0656
0657 template<utf8_range R>
0658 requires std::ranges::bidirectional_range<R> &&
0659 std::ranges::common_range<R>
0660 constexpr bool ends_encoded(R && r);
0661
0662
0663
0664 template<utf8_range R>
0665 requires std::ranges::bidirectional_range<R> &&
0666 std::ranges::common_range<R>
0667 constexpr bool ends_encoded(R && r);
0668
0669 #endif
0670
0671 template<typename Iter>
0672 constexpr detail::enable_utf8_cp_t<Iter>
0673 find_invalid_encoding(Iter first, Iter last)
0674 {
0675 while (first != last) {
0676 int const cp_bytes = boost::parser::detail::text::utf8_code_units(*first);
0677 if (cp_bytes == -1 || last - first < cp_bytes)
0678 return first;
0679
0680 if (detail::end_of_invalid_utf8(first))
0681 return first;
0682
0683 first += cp_bytes;
0684 }
0685
0686 return last;
0687 }
0688
0689 template<typename Iter>
0690 constexpr detail::enable_utf16_cp_t<Iter>
0691 find_invalid_encoding(Iter first, Iter last)
0692 {
0693 while (first != last) {
0694 int const cp_units = boost::parser::detail::text::utf16_code_units(*first);
0695 if (cp_units == -1 || last - first < cp_units)
0696 return first;
0697
0698 if (cp_units == 2 && !boost::parser::detail::text::low_surrogate(*(first + 1)))
0699 return first;
0700
0701 first += cp_units;
0702 }
0703
0704 return last;
0705 }
0706
0707 template<typename Iter>
0708 constexpr detail::enable_utf8_cp_t<Iter, bool> encoded(
0709 Iter first, Iter last)
0710 {
0711 return v1::find_invalid_encoding(first, last) == last;
0712 }
0713
0714 template<typename Iter>
0715 constexpr detail::enable_utf16_cp_t<Iter, bool> encoded(
0716 Iter first, Iter last)
0717 {
0718 return v1::find_invalid_encoding(first, last) == last;
0719 }
0720
0721 template<typename Iter>
0722 constexpr detail::enable_utf8_cp_t<Iter, bool>
0723 starts_encoded(Iter first, Iter last)
0724 {
0725 if (first == last)
0726 return true;
0727
0728 int const cp_bytes = boost::parser::detail::text::utf8_code_units(*first);
0729 if (cp_bytes == -1 || last - first < cp_bytes)
0730 return false;
0731
0732 return !detail::end_of_invalid_utf8(first);
0733 }
0734
0735 template<typename Iter>
0736 constexpr detail::enable_utf16_cp_t<Iter, bool>
0737 starts_encoded(Iter first, Iter last)
0738 {
0739 if (first == last)
0740 return true;
0741
0742 int const cp_units = boost::parser::detail::text::utf16_code_units(*first);
0743 if (cp_units == -1 || last - first < cp_units)
0744 return false;
0745
0746 return cp_units == 1 || boost::parser::detail::text::low_surrogate(*(first + 1));
0747 }
0748
0749 template<typename Iter>
0750 constexpr detail::enable_utf8_cp_t<Iter, bool>
0751 ends_encoded(Iter first, Iter last)
0752 {
0753 if (first == last)
0754 return true;
0755
0756 auto it = last;
0757 while (first != --it && boost::parser::detail::text::continuation(*it))
0758 ;
0759
0760 return v1::starts_encoded(it, last);
0761 }
0762
0763 template<typename Iter>
0764 constexpr detail::enable_utf16_cp_t<Iter, bool>
0765 ends_encoded(Iter first, Iter last)
0766 {
0767 if (first == last)
0768 return true;
0769
0770 auto it = last;
0771 if (boost::parser::detail::text::low_surrogate(*--it))
0772 --it;
0773
0774 return v1::starts_encoded(it, last);
0775 }
0776
0777 }}}
0778
0779 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0780
0781 namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 {
0782
0783 template<utf8_range R>
0784 requires std::ranges::forward_range<R>
0785 constexpr std::ranges::borrowed_iterator_t<R> find_invalid_encoding(R && r)
0786 {
0787 auto first = std::ranges::begin(r);
0788 auto last = std::ranges::end(r);
0789
0790 while (first != last) {
0791 int const cp_bytes = boost::parser::detail::text::utf8_code_units(*first);
0792 if (cp_bytes == -1 || last - first < cp_bytes)
0793 return first;
0794
0795 if (detail::end_of_invalid_utf8(first))
0796 return first;
0797
0798 first += cp_bytes;
0799 }
0800
0801 if constexpr (std::ranges::borrowed_range<R>) {
0802 return last;
0803 } else {
0804 return std::ranges::dangling{};
0805 }
0806 }
0807
0808 template<utf16_range R>
0809 requires std::ranges::forward_range<R>
0810 constexpr std::ranges::borrowed_iterator_t<R> find_invalid_encoding(R && r)
0811 {
0812 auto first = std::ranges::begin(r);
0813 auto last = std::ranges::end(r);
0814
0815 while (first != last) {
0816 int const cp_units = boost::parser::detail::text::utf16_code_units(*first);
0817 if (cp_units == -1 || last - first < cp_units)
0818 return first;
0819
0820 if (cp_units == 2 && !boost::parser::detail::text::low_surrogate(*(first + 1)))
0821 return first;
0822
0823 first += cp_units;
0824 }
0825
0826 if constexpr (std::ranges::borrowed_range<R>) {
0827 return last;
0828 } else {
0829 return std::ranges::dangling{};
0830 }
0831 }
0832
0833 template<utf8_range R>
0834 requires std::ranges::forward_range<R>
0835 constexpr bool encoded(R && r)
0836 {
0837 return boost::parser::detail::text::v1::find_invalid_encoding(r.begin(), r.end()) ==
0838 r.end();
0839 }
0840
0841 template<utf16_range R>
0842 requires std::ranges::forward_range<R>
0843 constexpr bool encoded(R && r)
0844 {
0845 return boost::parser::detail::text::v1::find_invalid_encoding(r.begin(), r.end()) ==
0846 r.end();
0847 }
0848
0849 template<utf8_range R>
0850 requires std::ranges::forward_range<R>
0851 constexpr bool starts_encoded(R && r)
0852 {
0853 auto first = std::ranges::begin(r);
0854 auto last = std::ranges::end(r);
0855
0856 if (first == last)
0857 return true;
0858
0859 int const cp_bytes = boost::parser::detail::text::utf8_code_units(*first);
0860 if (cp_bytes == -1 || last - first < cp_bytes)
0861 return false;
0862
0863 return !detail::end_of_invalid_utf8(first);
0864 }
0865
0866 template<utf16_range R>
0867 requires std::ranges::forward_range<R>
0868 constexpr bool starts_encoded(R && r)
0869 {
0870 auto first = std::ranges::begin(r);
0871 auto last = std::ranges::end(r);
0872
0873 if (first == last)
0874 return true;
0875
0876 int const cp_units = boost::parser::detail::text::utf16_code_units(*first);
0877 if (cp_units == -1 || last - first < cp_units)
0878 return false;
0879
0880 return cp_units == 1 || boost::parser::detail::text::low_surrogate(*(first + 1));
0881 }
0882
0883 template<utf8_range R>
0884 requires std::ranges::bidirectional_range<R> &&
0885 std::ranges::common_range<R>
0886 constexpr bool ends_encoded(R && r)
0887 {
0888 auto first = std::ranges::begin(r);
0889 auto last = std::ranges::end(r);
0890
0891 if (first == last)
0892 return true;
0893
0894 auto it = last;
0895 while (first != --it && boost::parser::detail::text::continuation(*it))
0896 ;
0897
0898 return boost::parser::detail::text::starts_encoded(it, last);
0899 }
0900
0901 template<utf16_range R>
0902 requires std::ranges::bidirectional_range<R> &&
0903 std::ranges::common_range<R>
0904 constexpr bool ends_encoded(R && r)
0905 {
0906 auto first = std::ranges::begin(r);
0907 auto last = std::ranges::end(r);
0908
0909 if (first == last)
0910 return true;
0911
0912 auto it = last;
0913 if (boost::parser::detail::text::low_surrogate(*--it))
0914 --it;
0915
0916 return boost::parser::detail::text::starts_encoded(it, last);
0917 }
0918
0919 }}}
0920
0921 #endif
0922
0923 namespace boost::parser::detail { namespace text {
0924
0925
0926
0927 struct use_replacement_character
0928 {
0929 constexpr char32_t operator()(std::string_view) const noexcept
0930 {
0931 return replacement_character;
0932 }
0933 };
0934
0935
0936
0937 struct null_sentinel_t
0938 {
0939 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0940 template<std::input_iterator I>
0941 requires std::default_initializable<std::iter_value_t<I>> &&
0942 std::equality_comparable_with<std::iter_reference_t<I>, std::iter_value_t<I>>
0943 #else
0944 template<typename I>
0945 #endif
0946 friend constexpr bool operator==(I it, null_sentinel_t)
0947 {
0948 return *it == detail::iter_value_t<I>{};
0949 }
0950 #if !defined(__cpp_impl_three_way_comparison)
0951 template<typename I>
0952 friend constexpr bool operator==(null_sentinel_t, I it)
0953 {
0954 return *it == detail::iter_value_t<I>{};
0955 }
0956 template<typename I>
0957 friend constexpr bool operator!=(I it, null_sentinel_t)
0958 {
0959 return *it != detail::iter_value_t<I>{};
0960 }
0961 template<typename I>
0962 friend constexpr bool operator!=(null_sentinel_t, I it)
0963 {
0964 return *it != detail::iter_value_t<I>{};
0965 }
0966 #endif
0967 };
0968
0969 #if defined(__cpp_inline_variables)
0970 inline constexpr null_sentinel_t null_sentinel;
0971 #else
0972 namespace {
0973 constexpr null_sentinel_t null_sentinel;
0974 }
0975 #endif
0976
0977
0978 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0979 template<std::output_iterator<char8_t> Iter>
0980 #else
0981 template<typename Iter>
0982 #endif
0983 struct utf_32_to_8_out_iterator
0984 : detail::trans_ins_iter<utf_32_to_8_out_iterator<Iter>, Iter>
0985 {
0986 constexpr utf_32_to_8_out_iterator() {}
0987 explicit constexpr utf_32_to_8_out_iterator(Iter it) :
0988 detail::trans_ins_iter<utf_32_to_8_out_iterator<Iter>, Iter>(it)
0989 {}
0990
0991 constexpr utf_32_to_8_out_iterator & operator=(char32_t cp)
0992 {
0993 auto & out = this->iter();
0994 out = detail::write_cp_utf8(cp, out);
0995 return *this;
0996 }
0997 };
0998
0999
1000
1001 template<typename Cont>
1002 struct utf_32_to_8_insert_iterator : detail::trans_ins_iter<
1003 utf_32_to_8_insert_iterator<Cont>,
1004 std::insert_iterator<Cont>>
1005 {
1006 constexpr utf_32_to_8_insert_iterator() {}
1007 constexpr utf_32_to_8_insert_iterator(
1008 Cont & c, typename Cont::iterator it) :
1009 detail::trans_ins_iter<
1010 utf_32_to_8_insert_iterator<Cont>,
1011 std::insert_iterator<Cont>>(std::insert_iterator<Cont>(c, it))
1012 {}
1013
1014 constexpr utf_32_to_8_insert_iterator & operator=(char32_t cp)
1015 {
1016 auto & out = this->iter();
1017 out = detail::write_cp_utf8(cp, out);
1018 return *this;
1019 }
1020 };
1021
1022
1023
1024 template<typename Cont>
1025 struct utf_32_to_8_front_insert_iterator
1026 : detail::trans_ins_iter<
1027 utf_32_to_8_front_insert_iterator<Cont>,
1028 std::front_insert_iterator<Cont>>
1029 {
1030 constexpr utf_32_to_8_front_insert_iterator() {}
1031 explicit constexpr utf_32_to_8_front_insert_iterator(Cont & c) :
1032 detail::trans_ins_iter<
1033 utf_32_to_8_front_insert_iterator<Cont>,
1034 std::front_insert_iterator<Cont>>(
1035 std::front_insert_iterator<Cont>(c))
1036 {}
1037
1038 constexpr utf_32_to_8_front_insert_iterator & operator=(char32_t cp)
1039 {
1040 auto & out = this->iter();
1041 out = detail::write_cp_utf8(cp, out);
1042 return *this;
1043 }
1044 };
1045
1046
1047
1048 template<typename Cont>
1049 struct utf_32_to_8_back_insert_iterator
1050 : detail::trans_ins_iter<
1051 utf_32_to_8_back_insert_iterator<Cont>,
1052 std::back_insert_iterator<Cont>>
1053 {
1054 constexpr utf_32_to_8_back_insert_iterator() {}
1055 explicit constexpr utf_32_to_8_back_insert_iterator(Cont & c) :
1056 detail::trans_ins_iter<
1057 utf_32_to_8_back_insert_iterator<Cont>,
1058 std::back_insert_iterator<Cont>>(
1059 std::back_insert_iterator<Cont>(c))
1060 {}
1061
1062 constexpr utf_32_to_8_back_insert_iterator & operator=(char32_t cp)
1063 {
1064 auto & out = this->iter();
1065 out = detail::write_cp_utf8(cp, out);
1066 return *this;
1067 }
1068 };
1069
1070
1071 namespace detail {
1072 template<typename OutIter>
1073 OutIter assign_8_to_32_insert(
1074 unsigned char cu, char32_t & cp, int & state, OutIter out)
1075 {
1076 auto write = [&] {
1077 *out = cp;
1078 ++out;
1079 state = invalid_table_state;
1080 };
1081 auto start_cp = [&] {
1082 first_cu const info = first_cus[cu];
1083 state = info.next;
1084 cp = info.initial_octet;
1085 if (state == bgn)
1086 write();
1087 };
1088 if (state == invalid_table_state) {
1089 start_cp();
1090 } else {
1091 cp = (cp << 6) | (cu & 0x3f);
1092 char_class const class_ = octet_classes[cu];
1093 state = transitions[state + class_];
1094 if (state == bgn) {
1095 write();
1096 } else if (state == err) {
1097 *out = replacement_character;
1098 ++out;
1099 start_cp();
1100 }
1101 }
1102 return out;
1103 }
1104 }
1105
1106
1107 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
1108 template<std::output_iterator<char32_t> Iter>
1109 #else
1110 template<typename Iter>
1111 #endif
1112 struct utf_8_to_32_out_iterator
1113 : detail::trans_ins_iter<utf_8_to_32_out_iterator<Iter>, Iter>
1114 {
1115 constexpr utf_8_to_32_out_iterator() {}
1116 explicit constexpr utf_8_to_32_out_iterator(Iter it) :
1117 detail::trans_ins_iter<utf_8_to_32_out_iterator<Iter>, Iter>(it),
1118 state_(detail::invalid_table_state)
1119 {}
1120
1121 constexpr utf_8_to_32_out_iterator & operator=(char8_type cu)
1122 {
1123 auto & out = this->iter();
1124 out = detail::assign_8_to_32_insert(cu, cp_, state_, out);
1125 return *this;
1126 }
1127
1128 #ifndef BOOST_TEXT_DOXYGEN
1129 private:
1130 int state_;
1131 char32_t cp_;
1132 #endif
1133 };
1134
1135
1136
1137 template<typename Cont>
1138 struct utf_8_to_32_insert_iterator : detail::trans_ins_iter<
1139 utf_8_to_32_insert_iterator<Cont>,
1140 std::insert_iterator<Cont>>
1141 {
1142 constexpr utf_8_to_32_insert_iterator() {}
1143 constexpr utf_8_to_32_insert_iterator(
1144 Cont & c, typename Cont::iterator it) :
1145 detail::trans_ins_iter<
1146 utf_8_to_32_insert_iterator<Cont>,
1147 std::insert_iterator<Cont>>(std::insert_iterator<Cont>(c, it)),
1148 state_(detail::invalid_table_state)
1149 {}
1150
1151 constexpr utf_8_to_32_insert_iterator & operator=(char16_t cu)
1152 {
1153 auto & out = this->iter();
1154 out = detail::assign_8_to_32_insert(cu, cp_, state_, out);
1155 return *this;
1156 }
1157
1158 #ifndef BOOST_TEXT_DOXYGEN
1159 private:
1160 int state_;
1161 char32_t cp_;
1162 #endif
1163 };
1164
1165
1166
1167 template<typename Cont>
1168 struct utf_8_to_32_front_insert_iterator
1169 : detail::trans_ins_iter<
1170 utf_8_to_32_front_insert_iterator<Cont>,
1171 std::front_insert_iterator<Cont>>
1172 {
1173 constexpr utf_8_to_32_front_insert_iterator() {}
1174 explicit constexpr utf_8_to_32_front_insert_iterator(Cont & c) :
1175 detail::trans_ins_iter<
1176 utf_8_to_32_front_insert_iterator<Cont>,
1177 std::front_insert_iterator<Cont>>(
1178 std::front_insert_iterator<Cont>(c)),
1179 state_(detail::invalid_table_state)
1180 {}
1181
1182 constexpr utf_8_to_32_front_insert_iterator & operator=(char16_t cu)
1183 {
1184 auto & out = this->iter();
1185 out = detail::assign_8_to_32_insert(cu, cp_, state_, out);
1186 return *this;
1187 }
1188
1189 #ifndef BOOST_TEXT_DOXYGEN
1190 private:
1191 int state_;
1192 char32_t cp_;
1193 #endif
1194 };
1195
1196
1197
1198 template<typename Cont>
1199 struct utf_8_to_32_back_insert_iterator
1200 : detail::trans_ins_iter<
1201 utf_8_to_32_back_insert_iterator<Cont>,
1202 std::back_insert_iterator<Cont>>
1203 {
1204 constexpr utf_8_to_32_back_insert_iterator() {}
1205 explicit constexpr utf_8_to_32_back_insert_iterator(Cont & c) :
1206 detail::trans_ins_iter<
1207 utf_8_to_32_back_insert_iterator<Cont>,
1208 std::back_insert_iterator<Cont>>(
1209 std::back_insert_iterator<Cont>(c)),
1210 state_(detail::invalid_table_state)
1211 {}
1212
1213 constexpr utf_8_to_32_back_insert_iterator & operator=(char16_t cu)
1214 {
1215 auto & out = this->iter();
1216 out = detail::assign_8_to_32_insert(cu, cp_, state_, out);
1217 return *this;
1218 }
1219
1220 #ifndef BOOST_TEXT_DOXYGEN
1221 private:
1222 int state_;
1223 char32_t cp_;
1224 #endif
1225 };
1226
1227
1228
1229 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
1230 template<std::output_iterator<char16_t> Iter>
1231 #else
1232 template<typename Iter>
1233 #endif
1234 struct utf_32_to_16_out_iterator
1235 : detail::trans_ins_iter<utf_32_to_16_out_iterator<Iter>, Iter>
1236 {
1237 constexpr utf_32_to_16_out_iterator() {}
1238 explicit constexpr utf_32_to_16_out_iterator(Iter it) :
1239 detail::trans_ins_iter<utf_32_to_16_out_iterator<Iter>, Iter>(it)
1240 {}
1241
1242 constexpr utf_32_to_16_out_iterator & operator=(char32_t cp)
1243 {
1244 auto & out = this->iter();
1245 out = detail::write_cp_utf16(cp, out);
1246 return *this;
1247 }
1248 };
1249
1250
1251
1252 template<typename Cont>
1253 struct utf_32_to_16_insert_iterator
1254 : detail::trans_ins_iter<
1255 utf_32_to_16_insert_iterator<Cont>,
1256 std::insert_iterator<Cont>>
1257 {
1258 constexpr utf_32_to_16_insert_iterator() {}
1259 constexpr utf_32_to_16_insert_iterator(
1260 Cont & c, typename Cont::iterator it) :
1261 detail::trans_ins_iter<
1262 utf_32_to_16_insert_iterator<Cont>,
1263 std::insert_iterator<Cont>>(std::insert_iterator<Cont>(c, it))
1264 {}
1265
1266 constexpr utf_32_to_16_insert_iterator & operator=(char32_t cp)
1267 {
1268 auto & out = this->iter();
1269 out = detail::write_cp_utf16(cp, out);
1270 return *this;
1271 }
1272 };
1273
1274
1275
1276 template<typename Cont>
1277 struct utf_32_to_16_front_insert_iterator
1278 : detail::trans_ins_iter<
1279 utf_32_to_16_front_insert_iterator<Cont>,
1280 std::front_insert_iterator<Cont>>
1281 {
1282 constexpr utf_32_to_16_front_insert_iterator() {}
1283 explicit constexpr utf_32_to_16_front_insert_iterator(Cont & c) :
1284 detail::trans_ins_iter<
1285 utf_32_to_16_front_insert_iterator<Cont>,
1286 std::front_insert_iterator<Cont>>(
1287 std::front_insert_iterator<Cont>(c))
1288 {}
1289
1290 constexpr utf_32_to_16_front_insert_iterator & operator=(char32_t cp)
1291 {
1292 auto & out = this->iter();
1293 out = detail::write_cp_utf16(cp, out);
1294 return *this;
1295 }
1296 };
1297
1298
1299
1300 template<typename Cont>
1301 struct utf_32_to_16_back_insert_iterator
1302 : detail::trans_ins_iter<
1303 utf_32_to_16_back_insert_iterator<Cont>,
1304 std::back_insert_iterator<Cont>>
1305 {
1306 constexpr utf_32_to_16_back_insert_iterator() {}
1307 explicit constexpr utf_32_to_16_back_insert_iterator(Cont & c) :
1308 detail::trans_ins_iter<
1309 utf_32_to_16_back_insert_iterator<Cont>,
1310 std::back_insert_iterator<Cont>>(
1311 std::back_insert_iterator<Cont>(c))
1312 {}
1313
1314 constexpr utf_32_to_16_back_insert_iterator & operator=(char32_t cp)
1315 {
1316 auto & out = this->iter();
1317 out = detail::write_cp_utf16(cp, out);
1318 return *this;
1319 }
1320 };
1321
1322
1323 namespace detail {
1324 template<typename OutIter>
1325 OutIter
1326 assign_16_to_32_insert(char16_t & prev_cu, char16_t cu, OutIter out)
1327 {
1328 if (high_surrogate(cu)) {
1329 if (prev_cu) {
1330 *out = replacement_character;
1331 ++out;
1332 }
1333 prev_cu = cu;
1334 } else if (low_surrogate(cu)) {
1335 if (prev_cu) {
1336 *out = detail::surrogates_to_cp(prev_cu, cu);
1337 ++out;
1338 } else {
1339 *out = replacement_character;
1340 ++out;
1341 }
1342 prev_cu = 0;
1343 } else {
1344 if (prev_cu) {
1345 *out = replacement_character;
1346 ++out;
1347 }
1348 *out = cu;
1349 ++out;
1350 prev_cu = 0;
1351 }
1352 return out;
1353 }
1354 }
1355
1356
1357 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
1358 template<std::output_iterator<char32_t> Iter>
1359 #else
1360 template<typename Iter>
1361 #endif
1362 struct utf_16_to_32_out_iterator
1363 : detail::trans_ins_iter<utf_16_to_32_out_iterator<Iter>, Iter>
1364 {
1365 constexpr utf_16_to_32_out_iterator() {}
1366 explicit constexpr utf_16_to_32_out_iterator(Iter it) :
1367 detail::trans_ins_iter<utf_16_to_32_out_iterator<Iter>, Iter>(it),
1368 prev_cu_(0)
1369 {}
1370
1371 constexpr utf_16_to_32_out_iterator & operator=(char16_t cu)
1372 {
1373 auto & out = this->iter();
1374 out = detail::assign_16_to_32_insert(prev_cu_, cu, out);
1375 return *this;
1376 }
1377
1378 #ifndef BOOST_TEXT_DOXYGEN
1379 private:
1380 char16_t prev_cu_;
1381 #endif
1382 };
1383
1384
1385
1386 template<typename Cont>
1387 struct utf_16_to_32_insert_iterator
1388 : detail::trans_ins_iter<
1389 utf_16_to_32_insert_iterator<Cont>,
1390 std::insert_iterator<Cont>>
1391 {
1392 constexpr utf_16_to_32_insert_iterator() {}
1393 constexpr utf_16_to_32_insert_iterator(
1394 Cont & c, typename Cont::iterator it) :
1395 detail::trans_ins_iter<
1396 utf_16_to_32_insert_iterator<Cont>,
1397 std::insert_iterator<Cont>>(std::insert_iterator<Cont>(c, it)),
1398 prev_cu_(0)
1399 {}
1400
1401 constexpr utf_16_to_32_insert_iterator & operator=(char16_t cu)
1402 {
1403 auto & out = this->iter();
1404 out = detail::assign_16_to_32_insert(prev_cu_, cu, out);
1405 return *this;
1406 }
1407
1408 #ifndef BOOST_TEXT_DOXYGEN
1409 private:
1410 char16_t prev_cu_;
1411 #endif
1412 };
1413
1414
1415
1416 template<typename Cont>
1417 struct utf_16_to_32_front_insert_iterator
1418 : detail::trans_ins_iter<
1419 utf_16_to_32_front_insert_iterator<Cont>,
1420 std::front_insert_iterator<Cont>>
1421 {
1422 constexpr utf_16_to_32_front_insert_iterator() {}
1423 explicit constexpr utf_16_to_32_front_insert_iterator(Cont & c) :
1424 detail::trans_ins_iter<
1425 utf_16_to_32_front_insert_iterator<Cont>,
1426 std::front_insert_iterator<Cont>>(
1427 std::front_insert_iterator<Cont>(c)),
1428 prev_cu_(0)
1429 {}
1430
1431 constexpr utf_16_to_32_front_insert_iterator & operator=(char16_t cu)
1432 {
1433 auto & out = this->iter();
1434 out = detail::assign_16_to_32_insert(prev_cu_, cu, out);
1435 return *this;
1436 }
1437
1438 #ifndef BOOST_TEXT_DOXYGEN
1439 private:
1440 char16_t prev_cu_;
1441 #endif
1442 };
1443
1444
1445
1446 template<typename Cont>
1447 struct utf_16_to_32_back_insert_iterator
1448 : detail::trans_ins_iter<
1449 utf_16_to_32_back_insert_iterator<Cont>,
1450 std::back_insert_iterator<Cont>>
1451 {
1452 constexpr utf_16_to_32_back_insert_iterator() {}
1453 explicit constexpr utf_16_to_32_back_insert_iterator(Cont & c) :
1454 detail::trans_ins_iter<
1455 utf_16_to_32_back_insert_iterator<Cont>,
1456 std::back_insert_iterator<Cont>>(
1457 std::back_insert_iterator<Cont>(c)),
1458 prev_cu_(0)
1459 {}
1460
1461 constexpr utf_16_to_32_back_insert_iterator & operator=(char16_t cu)
1462 {
1463 auto & out = this->iter();
1464 out = detail::assign_16_to_32_insert(prev_cu_, cu, out);
1465 return *this;
1466 }
1467
1468 #ifndef BOOST_TEXT_DOXYGEN
1469 private:
1470 char16_t prev_cu_;
1471 #endif
1472 };
1473
1474
1475 namespace detail {
1476 template<typename OutIter>
1477 OutIter
1478 assign_16_to_8_insert(char16_t & prev_cu, char16_t cu, OutIter out)
1479 {
1480 if (high_surrogate(cu)) {
1481 if (prev_cu)
1482 out = detail::write_cp_utf8(replacement_character, out);
1483 prev_cu = cu;
1484 } else if (low_surrogate(cu)) {
1485 if (prev_cu) {
1486 auto const cp = detail::surrogates_to_cp(prev_cu, cu);
1487 out = detail::write_cp_utf8(cp, out);
1488 } else {
1489 out = detail::write_cp_utf8(replacement_character, out);
1490 }
1491 prev_cu = 0;
1492 } else {
1493 if (prev_cu)
1494 out = detail::write_cp_utf8(replacement_character, out);
1495 out = detail::write_cp_utf8(cu, out);
1496 prev_cu = 0;
1497 }
1498 return out;
1499 }
1500 }
1501
1502
1503 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
1504 template<std::output_iterator<char8_t> Iter>
1505 #else
1506 template<typename Iter>
1507 #endif
1508 struct utf_16_to_8_out_iterator
1509 : detail::trans_ins_iter<utf_16_to_8_out_iterator<Iter>, Iter>
1510 {
1511 constexpr utf_16_to_8_out_iterator() {}
1512 explicit constexpr utf_16_to_8_out_iterator(Iter it) :
1513 detail::trans_ins_iter<utf_16_to_8_out_iterator<Iter>, Iter>(it),
1514 prev_cu_(0)
1515 {}
1516
1517 constexpr utf_16_to_8_out_iterator & operator=(char16_t cu)
1518 {
1519 auto & out = this->iter();
1520 out = detail::assign_16_to_8_insert(prev_cu_, cu, out);
1521 return *this;
1522 }
1523
1524 #ifndef BOOST_TEXT_DOXYGEN
1525 private:
1526 char16_t prev_cu_;
1527 #endif
1528 };
1529
1530
1531
1532 template<typename Cont>
1533 struct utf_16_to_8_insert_iterator : detail::trans_ins_iter<
1534 utf_16_to_8_insert_iterator<Cont>,
1535 std::insert_iterator<Cont>>
1536 {
1537 constexpr utf_16_to_8_insert_iterator() {}
1538 constexpr utf_16_to_8_insert_iterator(
1539 Cont & c, typename Cont::iterator it) :
1540 detail::trans_ins_iter<
1541 utf_16_to_8_insert_iterator<Cont>,
1542 std::insert_iterator<Cont>>(std::insert_iterator<Cont>(c, it)),
1543 prev_cu_(0)
1544 {}
1545
1546 constexpr utf_16_to_8_insert_iterator & operator=(char16_t cu)
1547 {
1548 auto & out = this->iter();
1549 out = detail::assign_16_to_8_insert(prev_cu_, cu, out);
1550 return *this;
1551 }
1552
1553 #ifndef BOOST_TEXT_DOXYGEN
1554 private:
1555 char16_t prev_cu_;
1556 #endif
1557 };
1558
1559
1560
1561 template<typename Cont>
1562 struct utf_16_to_8_front_insert_iterator
1563 : detail::trans_ins_iter<
1564 utf_16_to_8_front_insert_iterator<Cont>,
1565 std::front_insert_iterator<Cont>>
1566 {
1567 constexpr utf_16_to_8_front_insert_iterator() {}
1568 explicit constexpr utf_16_to_8_front_insert_iterator(Cont & c) :
1569 detail::trans_ins_iter<
1570 utf_16_to_8_front_insert_iterator<Cont>,
1571 std::front_insert_iterator<Cont>>(
1572 std::front_insert_iterator<Cont>(c)),
1573 prev_cu_(0)
1574 {}
1575
1576 constexpr utf_16_to_8_front_insert_iterator & operator=(char16_t cu)
1577 {
1578 auto & out = this->iter();
1579 out = detail::assign_16_to_8_insert(prev_cu_, cu, out);
1580 return *this;
1581 }
1582
1583 #ifndef BOOST_TEXT_DOXYGEN
1584 private:
1585 char16_t prev_cu_;
1586 #endif
1587 };
1588
1589
1590
1591 template<typename Cont>
1592 struct utf_16_to_8_back_insert_iterator
1593 : detail::trans_ins_iter<
1594 utf_16_to_8_back_insert_iterator<Cont>,
1595 std::back_insert_iterator<Cont>>
1596 {
1597 constexpr utf_16_to_8_back_insert_iterator() {}
1598 explicit constexpr utf_16_to_8_back_insert_iterator(Cont & c) :
1599 detail::trans_ins_iter<
1600 utf_16_to_8_back_insert_iterator<Cont>,
1601 std::back_insert_iterator<Cont>>(
1602 std::back_insert_iterator<Cont>(c)),
1603 prev_cu_(0)
1604 {}
1605
1606 constexpr utf_16_to_8_back_insert_iterator & operator=(char16_t cu)
1607 {
1608 auto & out = this->iter();
1609 out = detail::assign_16_to_8_insert(prev_cu_, cu, out);
1610 return *this;
1611 }
1612
1613 #ifndef BOOST_TEXT_DOXYGEN
1614 private:
1615 char16_t prev_cu_;
1616 #endif
1617 };
1618
1619
1620 namespace detail {
1621 template<typename OutIter>
1622 OutIter assign_8_to_16_insert(
1623 unsigned char cu, char32_t & cp, int & state, OutIter out)
1624 {
1625 auto write = [&] {
1626 out = detail::write_cp_utf16(cp, out);
1627 state = invalid_table_state;
1628 };
1629 auto start_cp = [&] {
1630 first_cu const info = first_cus[cu];
1631 state = info.next;
1632 cp = info.initial_octet;
1633 if (state == bgn)
1634 write();
1635 };
1636 if (state == invalid_table_state) {
1637 start_cp();
1638 } else {
1639 cp = (cp << 6) | (cu & 0x3f);
1640 char_class const class_ = octet_classes[cu];
1641 state = transitions[state + class_];
1642 if (state == bgn) {
1643 write();
1644 } else if (state == err) {
1645 out = detail::write_cp_utf16(replacement_character, out);
1646 start_cp();
1647 }
1648 }
1649 return out;
1650 }
1651 }
1652
1653
1654 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
1655 template<std::output_iterator<char16_t> Iter>
1656 #else
1657 template<typename Iter>
1658 #endif
1659 struct utf_8_to_16_out_iterator
1660 : detail::trans_ins_iter<utf_8_to_16_out_iterator<Iter>, Iter>
1661 {
1662 constexpr utf_8_to_16_out_iterator() {}
1663 explicit constexpr utf_8_to_16_out_iterator(Iter it) :
1664 detail::trans_ins_iter<utf_8_to_16_out_iterator<Iter>, Iter>(it),
1665 state_(detail::invalid_table_state)
1666 {}
1667
1668 constexpr utf_8_to_16_out_iterator & operator=(char8_type cu)
1669 {
1670 auto & out = this->iter();
1671 out = detail::assign_8_to_16_insert(cu, cp_, state_, out);
1672 return *this;
1673 }
1674
1675 #ifndef BOOST_TEXT_DOXYGEN
1676 private:
1677 int state_;
1678 char32_t cp_;
1679 #endif
1680 };
1681
1682
1683
1684 template<typename Cont>
1685 struct utf_8_to_16_insert_iterator : detail::trans_ins_iter<
1686 utf_8_to_16_insert_iterator<Cont>,
1687 std::insert_iterator<Cont>>
1688 {
1689 constexpr utf_8_to_16_insert_iterator() {}
1690 constexpr utf_8_to_16_insert_iterator(
1691 Cont & c, typename Cont::iterator it) :
1692 detail::trans_ins_iter<
1693 utf_8_to_16_insert_iterator<Cont>,
1694 std::insert_iterator<Cont>>(std::insert_iterator<Cont>(c, it)),
1695 state_(detail::invalid_table_state)
1696 {}
1697
1698 constexpr utf_8_to_16_insert_iterator & operator=(char16_t cu)
1699 {
1700 auto & out = this->iter();
1701 out = detail::assign_8_to_16_insert(cu, cp_, state_, out);
1702 return *this;
1703 }
1704
1705 #ifndef BOOST_TEXT_DOXYGEN
1706 private:
1707 int state_;
1708 char32_t cp_;
1709 #endif
1710 };
1711
1712
1713
1714 template<typename Cont>
1715 struct utf_8_to_16_front_insert_iterator
1716 : detail::trans_ins_iter<
1717 utf_8_to_16_front_insert_iterator<Cont>,
1718 std::front_insert_iterator<Cont>>
1719 {
1720 constexpr utf_8_to_16_front_insert_iterator() {}
1721 explicit constexpr utf_8_to_16_front_insert_iterator(Cont & c) :
1722 detail::trans_ins_iter<
1723 utf_8_to_16_front_insert_iterator<Cont>,
1724 std::front_insert_iterator<Cont>>(
1725 std::front_insert_iterator<Cont>(c)),
1726 state_(detail::invalid_table_state)
1727 {}
1728
1729 constexpr utf_8_to_16_front_insert_iterator & operator=(char16_t cu)
1730 {
1731 auto & out = this->iter();
1732 out = detail::assign_8_to_16_insert(cu, cp_, state_, out);
1733 return *this;
1734 }
1735
1736 #ifndef BOOST_TEXT_DOXYGEN
1737 private:
1738 int state_;
1739 char32_t cp_;
1740 #endif
1741 };
1742
1743
1744
1745 template<typename Cont>
1746 struct utf_8_to_16_back_insert_iterator
1747 : detail::trans_ins_iter<
1748 utf_8_to_16_back_insert_iterator<Cont>,
1749 std::back_insert_iterator<Cont>>
1750 {
1751 constexpr utf_8_to_16_back_insert_iterator() {}
1752 explicit constexpr utf_8_to_16_back_insert_iterator(Cont & c) :
1753 detail::trans_ins_iter<
1754 utf_8_to_16_back_insert_iterator<Cont>,
1755 std::back_insert_iterator<Cont>>(
1756 std::back_insert_iterator<Cont>(c)),
1757 state_(detail::invalid_table_state)
1758 {}
1759
1760 constexpr utf_8_to_16_back_insert_iterator & operator=(char16_t cu)
1761 {
1762 auto & out = this->iter();
1763 out = detail::assign_8_to_16_insert(cu, cp_, state_, out);
1764 return *this;
1765 }
1766
1767 #ifndef BOOST_TEXT_DOXYGEN
1768 private:
1769 int state_;
1770 char32_t cp_;
1771 #endif
1772 };
1773
1774 }}
1775
1776 #include <boost/parser/detail/text/unpack.hpp>
1777
1778 namespace boost::parser::detail { namespace text { namespace detail {
1779
1780 template<format Tag>
1781 struct make_utf8_dispatch;
1782
1783 template<>
1784 struct make_utf8_dispatch<format::utf8>
1785 {
1786 template<typename Iter, typename Sentinel>
1787 static constexpr Iter call(Iter first, Iter it, Sentinel last)
1788 {
1789 return it;
1790 }
1791 };
1792
1793 template<>
1794 struct make_utf8_dispatch<format::utf16>
1795 {
1796 template<typename Iter, typename Sentinel>
1797 static constexpr utf_iterator<
1798 format::utf16,
1799 format::utf8,
1800 Iter,
1801 Sentinel>
1802 call(Iter first, Iter it, Sentinel last)
1803 {
1804 return {first, it, last};
1805 }
1806 };
1807
1808 template<>
1809 struct make_utf8_dispatch<format::utf32>
1810 {
1811 template<typename Iter, typename Sentinel>
1812 static constexpr utf_iterator<
1813 format::utf32,
1814 format::utf8,
1815 Iter,
1816 Sentinel>
1817 call(Iter first, Iter it, Sentinel last)
1818 {
1819 return {first, it, last};
1820 }
1821 };
1822
1823 template<format Tag>
1824 struct make_utf16_dispatch;
1825
1826 template<>
1827 struct make_utf16_dispatch<format::utf8>
1828 {
1829 template<typename Iter, typename Sentinel>
1830 static constexpr utf_iterator<
1831 format::utf8,
1832 format::utf16,
1833 Iter,
1834 Sentinel>
1835 call(Iter first, Iter it, Sentinel last)
1836 {
1837 return {first, it, last};
1838 }
1839 };
1840
1841 template<>
1842 struct make_utf16_dispatch<format::utf16>
1843 {
1844 template<typename Iter, typename Sentinel>
1845 static constexpr Iter call(Iter first, Iter it, Sentinel last)
1846 {
1847 return it;
1848 }
1849 };
1850
1851 template<>
1852 struct make_utf16_dispatch<format::utf32>
1853 {
1854 template<typename Iter, typename Sentinel>
1855 static constexpr utf_iterator<
1856 format::utf32,
1857 format::utf16,
1858 Iter,
1859 Sentinel>
1860 call(Iter first, Iter it, Sentinel last)
1861 {
1862 return {first, it, last};
1863 }
1864 };
1865
1866 template<format Tag>
1867 struct make_utf32_dispatch;
1868
1869 template<>
1870 struct make_utf32_dispatch<format::utf8>
1871 {
1872 template<typename Iter, typename Sentinel>
1873 static constexpr utf_iterator<
1874 format::utf8,
1875 format::utf32,
1876 Iter,
1877 Sentinel>
1878 call(Iter first, Iter it, Sentinel last)
1879 {
1880 return {first, it, last};
1881 }
1882 };
1883
1884 template<>
1885 struct make_utf32_dispatch<format::utf16>
1886 {
1887 template<typename Iter, typename Sentinel>
1888 static constexpr utf_iterator<
1889 format::utf16,
1890 format::utf32,
1891 Iter,
1892 Sentinel>
1893 call(Iter first, Iter it, Sentinel last)
1894 {
1895 return {first, it, last};
1896 }
1897 };
1898
1899 template<>
1900 struct make_utf32_dispatch<format::utf32>
1901 {
1902 template<typename Iter, typename Sentinel>
1903 static constexpr Iter call(Iter first, Iter it, Sentinel last)
1904 {
1905 return it;
1906 }
1907 };
1908
1909 template<
1910 typename Cont,
1911 typename UTF8,
1912 typename UTF16,
1913 typename UTF32,
1914 int Bytes = sizeof(typename Cont::value_type)>
1915 struct from_utf8_dispatch
1916 {
1917 using type = UTF8;
1918 };
1919
1920 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1921 struct from_utf8_dispatch<Cont, UTF8, UTF16, UTF32, 2>
1922 {
1923 using type = UTF16;
1924 };
1925
1926 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1927 struct from_utf8_dispatch<Cont, UTF8, UTF16, UTF32, 4>
1928 {
1929 using type = UTF32;
1930 };
1931
1932 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1933 using from_utf8_dispatch_t =
1934 typename from_utf8_dispatch<Cont, UTF8, UTF16, UTF32>::type;
1935
1936 template<
1937 typename Cont,
1938 typename UTF8,
1939 typename UTF16,
1940 typename UTF32,
1941 int Bytes = sizeof(typename Cont::value_type)>
1942 struct from_utf16_dispatch
1943 {
1944 using type = UTF16;
1945 };
1946
1947 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1948 struct from_utf16_dispatch<Cont, UTF8, UTF16, UTF32, 1>
1949 {
1950 using type = UTF8;
1951 };
1952
1953 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1954 struct from_utf16_dispatch<Cont, UTF8, UTF16, UTF32, 4>
1955 {
1956 using type = UTF32;
1957 };
1958
1959 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1960 using from_utf16_dispatch_t =
1961 typename from_utf16_dispatch<Cont, UTF8, UTF16, UTF32>::type;
1962
1963 template<
1964 typename Cont,
1965 typename UTF8,
1966 typename UTF16,
1967 typename UTF32,
1968 int Bytes = sizeof(typename Cont::value_type)>
1969 struct from_utf32_dispatch
1970 {
1971 using type = UTF32;
1972 };
1973
1974 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1975 struct from_utf32_dispatch<Cont, UTF8, UTF16, UTF32, 1>
1976 {
1977 using type = UTF8;
1978 };
1979
1980 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1981 struct from_utf32_dispatch<Cont, UTF8, UTF16, UTF32, 2>
1982 {
1983 using type = UTF16;
1984 };
1985
1986 template<typename Cont, typename UTF8, typename UTF16, typename UTF32>
1987 using from_utf32_dispatch_t =
1988 typename from_utf32_dispatch<Cont, UTF8, UTF16, UTF32>::type;
1989
1990 }}}
1991
1992 namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V1 {
1993
1994 #if defined(BOOST_TEXT_DOXYGEN)
1995
1996
1997
1998 template<std::output_iterator<char8_t> O>
1999 utf_32_to_8_out_iterator<O> utf_32_to_8_out(O it);
2000
2001
2002
2003 template<std::output_iterator<char32_t> O>
2004 utf_8_to_32_out_iterator<O> utf_8_to_32_out(O it);
2005
2006
2007
2008 template<std::output_iterator<char16_t> O>
2009 utf_32_to_16_out_iterator<O> utf_32_to_16_out(O it);
2010
2011
2012
2013 template<std::output_iterator<char32_t> O>
2014 utf_16_to_32_out_iterator<O> utf_16_to_32_out(O it);
2015
2016
2017
2018 template<std::output_iterator<char8_t> O>
2019 utf_16_to_8_out_iterator<O> utf_16_to_8_out(O it);
2020
2021
2022
2023 template<std::output_iterator<char16_t> O>
2024 utf_8_to_16_out_iterator<O> utf_8_to_16_out(O it);
2025
2026
2027
2028 template<std::input_iterator I, std::sentinel_for<I> S>
2029 auto utf8_iterator(I first, I it, S last);
2030
2031
2032
2033 template<std::input_iterator I, std::sentinel_for<I> S>
2034 auto utf16_iterator(I first, I it, S last);
2035
2036
2037
2038 template<std::input_iterator I, std::sentinel_for<I> S>
2039 auto utf32_iterator(I first, I it, S last);
2040
2041
2042
2043
2044
2045 template<typename Cont>
2046 requires requires { typename Cont::value_type; } &&
2047 std::is_integral_v<typename Cont::value_type>
2048 auto from_utf8_inserter(Cont & c, typename Cont::iterator it);
2049
2050
2051
2052
2053
2054 template<typename Cont>
2055 requires requires { typename Cont::value_type; } &&
2056 std::is_integral_v<typename Cont::value_type>
2057 auto from_utf16_inserter(Cont & c, typename Cont::iterator it);
2058
2059
2060
2061
2062
2063 template<typename Cont>
2064 requires requires { typename Cont::value_type; } &&
2065 std::is_integral_v<typename Cont::value_type>
2066 auto from_utf32_inserter(Cont & c, typename Cont::iterator it);
2067
2068
2069
2070
2071
2072 template<typename Cont>
2073 requires requires { typename Cont::value_type; } &&
2074 std::is_integral_v<typename Cont::value_type>
2075 auto from_utf8_back_inserter(Cont & c);
2076
2077
2078
2079
2080
2081 template<typename Cont>
2082 requires requires { typename Cont::value_type; } &&
2083 std::is_integral_v<typename Cont::value_type>
2084 auto from_utf16_back_inserter(Cont & c);
2085
2086
2087
2088
2089
2090 template<typename Cont>
2091 requires requires { typename Cont::value_type; } &&
2092 std::is_integral_v<typename Cont::value_type>
2093 auto from_utf32_back_inserter(Cont & c);
2094
2095
2096
2097
2098
2099 template<typename Cont>
2100 requires requires { typename Cont::value_type; } &&
2101 std::is_integral_v<typename Cont::value_type>
2102 auto from_utf8_front_inserter(Cont & c);
2103
2104
2105
2106
2107
2108 template<typename Cont>
2109 requires requires { typename Cont::value_type; } &&
2110 std::is_integral_v<typename Cont::value_type>
2111 auto from_utf16_front_inserter(Cont & c);
2112
2113
2114
2115
2116
2117 template<typename Cont>
2118 requires requires { typename Cont::value_type; } &&
2119 std::is_integral_v<typename Cont::value_type>
2120 auto from_utf32_front_inserter(Cont & c);
2121
2122 #endif
2123
2124 template<typename Iter>
2125 utf_32_to_8_out_iterator<Iter> utf_32_to_8_out(Iter it)
2126 {
2127 return utf_32_to_8_out_iterator<Iter>(it);
2128 }
2129
2130 template<typename Iter>
2131 utf_8_to_32_out_iterator<Iter> utf_8_to_32_out(Iter it)
2132 {
2133 return utf_8_to_32_out_iterator<Iter>(it);
2134 }
2135
2136 template<typename Iter>
2137 utf_32_to_16_out_iterator<Iter> utf_32_to_16_out(Iter it)
2138 {
2139 return utf_32_to_16_out_iterator<Iter>(it);
2140 }
2141
2142 template<typename Iter>
2143 utf_16_to_32_out_iterator<Iter> utf_16_to_32_out(Iter it)
2144 {
2145 return utf_16_to_32_out_iterator<Iter>(it);
2146 }
2147
2148 template<typename Iter>
2149 utf_16_to_8_out_iterator<Iter> utf_16_to_8_out(Iter it)
2150 {
2151 return utf_16_to_8_out_iterator<Iter>(it);
2152 }
2153
2154 template<typename Iter>
2155 utf_8_to_16_out_iterator<Iter> utf_8_to_16_out(Iter it)
2156 {
2157 return utf_8_to_16_out_iterator<Iter>(it);
2158 }
2159
2160 template<typename Iter, typename Sentinel>
2161 auto utf8_iterator(Iter first, Iter it, Sentinel last)
2162 {
2163 auto const unpacked = text::unpack_iterator_and_sentinel(first, last);
2164 auto const unpacked_it =
2165 text::unpack_iterator_and_sentinel(it, last).first;
2166 constexpr format tag = unpacked.format_tag;
2167 return detail::make_utf8_dispatch<tag>::call(
2168 unpacked.first, unpacked_it, unpacked.last);
2169 }
2170
2171 template<typename Iter, typename Sentinel>
2172 auto utf16_iterator(Iter first, Iter it, Sentinel last)
2173 {
2174 auto const unpacked = text::unpack_iterator_and_sentinel(first, last);
2175 auto const unpacked_it =
2176 text::unpack_iterator_and_sentinel(it, last).first;
2177 constexpr format tag = unpacked.format_tag;
2178 return detail::make_utf16_dispatch<tag>::call(
2179 unpacked.first, unpacked_it, unpacked.last);
2180 }
2181
2182 template<typename Iter, typename Sentinel>
2183 auto utf32_iterator(Iter first, Iter it, Sentinel last)
2184 {
2185 auto const unpacked = text::unpack_iterator_and_sentinel(first, last);
2186 auto const unpacked_it =
2187 text::unpack_iterator_and_sentinel(it, last).first;
2188 constexpr format tag = unpacked.format_tag;
2189 return detail::make_utf32_dispatch<tag>::call(
2190 unpacked.first, unpacked_it, unpacked.last);
2191 }
2192
2193 template<typename Cont>
2194 auto from_utf8_inserter(Cont & c, typename Cont::iterator it)
2195 {
2196 using result_type = detail::from_utf8_dispatch_t<
2197 Cont,
2198 std::insert_iterator<Cont>,
2199 utf_8_to_16_insert_iterator<Cont>,
2200 utf_8_to_32_insert_iterator<Cont>>;
2201 return result_type(c, it);
2202 }
2203
2204 template<typename Cont>
2205 auto from_utf16_inserter(Cont & c, typename Cont::iterator it)
2206 {
2207 using result_type = detail::from_utf16_dispatch_t<
2208 Cont,
2209 utf_16_to_8_insert_iterator<Cont>,
2210 std::insert_iterator<Cont>,
2211 utf_16_to_32_insert_iterator<Cont>>;
2212 return result_type(c, it);
2213 }
2214
2215 template<typename Cont>
2216 auto from_utf32_inserter(Cont & c, typename Cont::iterator it)
2217 {
2218 using result_type = detail::from_utf32_dispatch_t<
2219 Cont,
2220 utf_32_to_8_insert_iterator<Cont>,
2221 utf_32_to_16_insert_iterator<Cont>,
2222 std::insert_iterator<Cont>>;
2223 return result_type(c, it);
2224 }
2225
2226 template<typename Cont>
2227 auto from_utf8_back_inserter(Cont & c)
2228 {
2229 using result_type = detail::from_utf8_dispatch_t<
2230 Cont,
2231 std::back_insert_iterator<Cont>,
2232 utf_8_to_16_back_insert_iterator<Cont>,
2233 utf_8_to_32_back_insert_iterator<Cont>>;
2234 return result_type(c);
2235 }
2236
2237 template<typename Cont>
2238 auto from_utf16_back_inserter(Cont & c)
2239 {
2240 using result_type = detail::from_utf16_dispatch_t<
2241 Cont,
2242 utf_16_to_8_back_insert_iterator<Cont>,
2243 std::back_insert_iterator<Cont>,
2244 utf_16_to_32_back_insert_iterator<Cont>>;
2245 return result_type(c);
2246 }
2247
2248 template<typename Cont>
2249 auto from_utf32_back_inserter(Cont & c)
2250 {
2251 using result_type = detail::from_utf32_dispatch_t<
2252 Cont,
2253 utf_32_to_8_back_insert_iterator<Cont>,
2254 utf_32_to_16_back_insert_iterator<Cont>,
2255 std::back_insert_iterator<Cont>>;
2256 return result_type(c);
2257 }
2258
2259 template<typename Cont>
2260 auto from_utf8_front_inserter(Cont & c)
2261 {
2262 using result_type = detail::from_utf8_dispatch_t<
2263 Cont,
2264 std::front_insert_iterator<Cont>,
2265 utf_8_to_16_front_insert_iterator<Cont>,
2266 utf_8_to_32_front_insert_iterator<Cont>>;
2267 return result_type(c);
2268 }
2269
2270 template<typename Cont>
2271 auto from_utf16_front_inserter(Cont & c)
2272 {
2273 using result_type = detail::from_utf16_dispatch_t<
2274 Cont,
2275 utf_16_to_8_front_insert_iterator<Cont>,
2276 std::front_insert_iterator<Cont>,
2277 utf_16_to_32_front_insert_iterator<Cont>>;
2278 return result_type(c);
2279 }
2280
2281 template<typename Cont>
2282 auto from_utf32_front_inserter(Cont & c)
2283 {
2284 using result_type = detail::from_utf32_dispatch_t<
2285 Cont,
2286 utf_32_to_8_front_insert_iterator<Cont>,
2287 utf_32_to_16_front_insert_iterator<Cont>,
2288 std::front_insert_iterator<Cont>>;
2289 return result_type(c);
2290 }
2291
2292 }}}
2293
2294 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2295
2296 namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 {
2297
2298 template<std::output_iterator<char8_t> O>
2299 constexpr utf_32_to_8_out_iterator<O> utf_32_to_8_out(O it)
2300 {
2301 return utf_32_to_8_out_iterator<O>(it);
2302 }
2303
2304 template<std::output_iterator<char32_t> O>
2305 constexpr utf_8_to_32_out_iterator<O> utf_8_to_32_out(O it)
2306 {
2307 return utf_8_to_32_out_iterator<O>(it);
2308 }
2309
2310 template<std::output_iterator<char16_t> O>
2311 constexpr utf_32_to_16_out_iterator<O> utf_32_to_16_out(O it)
2312 {
2313 return utf_32_to_16_out_iterator<O>(it);
2314 }
2315
2316 template<std::output_iterator<char32_t> O>
2317 constexpr utf_16_to_32_out_iterator<O> utf_16_to_32_out(O it)
2318 {
2319 return utf_16_to_32_out_iterator<O>(it);
2320 }
2321
2322 template<std::output_iterator<char8_t> O>
2323 constexpr utf_16_to_8_out_iterator<O> utf_16_to_8_out(O it)
2324 {
2325 return utf_16_to_8_out_iterator<O>(it);
2326 }
2327
2328 template<std::output_iterator<char16_t> O>
2329 constexpr utf_8_to_16_out_iterator<O> utf_8_to_16_out(O it)
2330 {
2331 return utf_8_to_16_out_iterator<O>(it);
2332 }
2333
2334 template<std::input_iterator I, std::sentinel_for<I> S>
2335 constexpr auto utf8_iterator(I first, I it, S last)
2336 {
2337 return v1::utf8_iterator(first, it, last);
2338 }
2339
2340 template<std::input_iterator I, std::sentinel_for<I> S>
2341 constexpr auto utf16_iterator(I first, I it, S last)
2342 {
2343 return v1::utf16_iterator(first, it, last);
2344 }
2345
2346 template<std::input_iterator I, std::sentinel_for<I> S>
2347 constexpr auto utf32_iterator(I first, I it, S last)
2348 {
2349 return v1::utf32_iterator(first, it, last);
2350 }
2351
2352 template<typename Cont>
2353 requires requires { typename Cont::value_type; } &&
2354 utf_code_unit<typename Cont::value_type>
2355 constexpr auto from_utf8_inserter(Cont & c, typename Cont::iterator it)
2356 {
2357 if constexpr (sizeof(typename Cont::value_type) == 1) {
2358 return std::insert_iterator<Cont>(c, it);
2359 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2360 return utf_8_to_16_insert_iterator<Cont>(c, it);
2361 } else {
2362 return utf_8_to_32_insert_iterator<Cont>(c, it);
2363 }
2364 }
2365
2366 template<typename Cont>
2367 requires requires { typename Cont::value_type; } &&
2368 utf_code_unit<typename Cont::value_type>
2369 constexpr auto from_utf16_inserter(Cont & c, typename Cont::iterator it)
2370 {
2371 if constexpr (sizeof(typename Cont::value_type) == 1) {
2372 return utf_16_to_8_insert_iterator<Cont>(c, it);
2373 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2374 return std::insert_iterator<Cont>(c, it);
2375 } else {
2376 return utf_16_to_32_insert_iterator<Cont>(c, it);
2377 }
2378 }
2379
2380 template<typename Cont>
2381 requires requires { typename Cont::value_type; } &&
2382 utf_code_unit<typename Cont::value_type>
2383 constexpr auto from_utf32_inserter(Cont & c, typename Cont::iterator it)
2384 {
2385 if constexpr (sizeof(typename Cont::value_type) == 1) {
2386 return utf_32_to_8_insert_iterator<Cont>(c, it);
2387 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2388 return utf_32_to_16_insert_iterator<Cont>(c, it);
2389 } else {
2390 return std::insert_iterator<Cont>(c, it);
2391 }
2392 }
2393
2394 template<typename Cont>
2395 requires requires { typename Cont::value_type; } &&
2396 utf_code_unit<typename Cont::value_type>
2397 constexpr auto from_utf8_back_inserter(Cont & c)
2398 {
2399 if constexpr (sizeof(typename Cont::value_type) == 1) {
2400 return std::back_insert_iterator<Cont>(c);
2401 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2402 return utf_8_to_16_back_insert_iterator<Cont>(c);
2403 } else {
2404 return utf_8_to_32_back_insert_iterator<Cont>(c);
2405 }
2406 }
2407
2408 template<typename Cont>
2409 requires requires { typename Cont::value_type; } &&
2410 utf_code_unit<typename Cont::value_type>
2411 constexpr auto from_utf16_back_inserter(Cont & c)
2412 {
2413 if constexpr (sizeof(typename Cont::value_type) == 1) {
2414 return utf_16_to_8_back_insert_iterator<Cont>(c);
2415 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2416 return std::back_insert_iterator<Cont>(c);
2417 } else {
2418 return utf_16_to_32_back_insert_iterator<Cont>(c);
2419 }
2420 }
2421
2422 template<typename Cont>
2423 requires requires { typename Cont::value_type; } &&
2424 utf_code_unit<typename Cont::value_type>
2425 constexpr auto from_utf32_back_inserter(Cont & c)
2426 {
2427 if constexpr (sizeof(typename Cont::value_type) == 1) {
2428 return utf_32_to_8_back_insert_iterator<Cont>(c);
2429 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2430 return utf_32_to_16_back_insert_iterator<Cont>(c);
2431 } else {
2432 return std::back_insert_iterator<Cont>(c);
2433 }
2434 }
2435
2436 template<typename Cont>
2437 requires requires { typename Cont::value_type; } &&
2438 utf_code_unit<typename Cont::value_type>
2439 constexpr auto from_utf8_front_inserter(Cont & c)
2440 {
2441 if constexpr (sizeof(typename Cont::value_type) == 1) {
2442 return std::front_insert_iterator<Cont>(c);
2443 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2444 return utf_8_to_16_front_insert_iterator<Cont>(c);
2445 } else {
2446 return utf_8_to_32_front_insert_iterator<Cont>(c);
2447 }
2448 }
2449
2450 template<typename Cont>
2451 requires requires { typename Cont::value_type; } &&
2452 utf_code_unit<typename Cont::value_type>
2453 constexpr auto from_utf16_front_inserter(Cont & c)
2454 {
2455 if constexpr (sizeof(typename Cont::value_type) == 1) {
2456 return utf_16_to_8_front_insert_iterator<Cont>(c);
2457 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2458 return std::front_insert_iterator<Cont>(c);
2459 } else {
2460 return utf_16_to_32_front_insert_iterator<Cont>(c);
2461 }
2462 }
2463
2464 template<typename Cont>
2465 requires requires { typename Cont::value_type; } &&
2466 utf_code_unit<typename Cont::value_type>
2467 constexpr auto from_utf32_front_inserter(Cont & c)
2468 {
2469 if constexpr (sizeof(typename Cont::value_type) == 1) {
2470 return utf_32_to_8_front_insert_iterator<Cont>(c);
2471 } else if constexpr (sizeof(typename Cont::value_type) == 2) {
2472 return utf_32_to_16_front_insert_iterator<Cont>(c);
2473 } else {
2474 return std::front_insert_iterator<Cont>(c);
2475 }
2476 }
2477 }}}
2478
2479 #endif
2480
2481 namespace boost::parser::detail { namespace text {
2482 namespace detail {
2483 template<format Format>
2484 constexpr auto format_to_type()
2485 {
2486 if constexpr (Format == format::utf8) {
2487 return char8_type{};
2488 } else if constexpr (Format == format::utf16) {
2489 return char16_t{};
2490 } else {
2491 return char32_t{};
2492 }
2493 }
2494
2495 template<typename I>
2496 constexpr bool is_bidi =
2497 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2498 std::bidirectional_iterator<I>
2499 #else
2500 std::is_base_of_v<
2501 std::bidirectional_iterator_tag,
2502 typename std::iterator_traits<I>::iterator_category>
2503 #endif
2504 ;
2505
2506 template<typename I, bool SupportReverse = is_bidi<I>>
2507 struct first_and_curr
2508 {
2509 first_and_curr() = default;
2510 first_and_curr(I curr) : curr{curr} {}
2511 first_and_curr(const first_and_curr & other) = default;
2512 template<
2513 class I2
2514 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2515 ,
2516 typename Enable = std::enable_if_t<std::is_convertible_v<I2, I>>
2517 #endif
2518 >
2519 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2520 requires std::convertible_to<I2, I>
2521 #endif
2522 first_and_curr(const first_and_curr<I2> & other) : curr{other.curr}
2523 {}
2524
2525 I curr;
2526 };
2527 template<typename I>
2528 struct first_and_curr<I, true>
2529 {
2530 first_and_curr() = default;
2531 first_and_curr(I first, I curr) : first{first}, curr{curr} {}
2532 first_and_curr(const first_and_curr & other) = default;
2533 template<
2534 class I2
2535 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2536 ,
2537 typename Enable = std::enable_if_t<std::is_convertible_v<I2, I>>
2538 #endif
2539 >
2540 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2541 requires std::convertible_to<I2, I>
2542 #endif
2543 first_and_curr(const first_and_curr<I2> & other) :
2544 first{other.first}, curr{other.curr}
2545 {}
2546
2547 I first;
2548 I curr;
2549 };
2550 }
2551
2552 namespace detail {
2553 struct iter_access
2554 {
2555 template<typename T>
2556 static auto & buf(T & it)
2557 {
2558 return it.buf_;
2559 }
2560 template<typename T>
2561 static auto & first_and_curr(T & it)
2562 {
2563 return it.first_and_curr_;
2564 }
2565 template<typename T>
2566 static auto & buf_index(T & it)
2567 {
2568 return it.buf_index_;
2569 }
2570 template<typename T>
2571 static auto & buf_last(T & it)
2572 {
2573 return it.buf_last_;
2574 }
2575 template<typename T>
2576 static auto & to_increment(T & it)
2577 {
2578 return it.to_increment_;
2579 }
2580 template<typename T>
2581 static auto & last(T & it)
2582 {
2583 return it.last_;
2584 }
2585 };
2586 }
2587
2588 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2589 template<
2590 format FromFormat,
2591 format ToFormat,
2592 std::input_iterator I,
2593 std::sentinel_for<I> S,
2594 transcoding_error_handler ErrorHandler>
2595 requires std::convertible_to<std::iter_value_t<I>, detail::format_to_type_t<FromFormat>>
2596 #else
2597 template<
2598 format FromFormat,
2599 format ToFormat,
2600 typename I,
2601 typename S,
2602 typename ErrorHandler>
2603 #endif
2604 class utf_iterator
2605 : public stl_interfaces::iterator_interface<
2606 utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>,
2607 detail::bidirectional_at_most_t<I>,
2608 detail::format_to_type_t<ToFormat>,
2609 detail::format_to_type_t<ToFormat>>
2610 {
2611 static_assert(
2612 FromFormat == format::utf8 || FromFormat == format::utf16 ||
2613 FromFormat == format::utf32);
2614 static_assert(
2615 ToFormat == format::utf8 || ToFormat == format::utf16 ||
2616 ToFormat == format::utf32);
2617
2618 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2619 template<typename T>
2620 constexpr static bool is_bidirectional = std::is_base_of_v<
2621 std::bidirectional_iterator_tag,
2622 detail::bidirectional_at_most_t<T>>;
2623 template<typename T>
2624 constexpr static bool is_forward = std::is_base_of_v<
2625 std::forward_iterator_tag,
2626 detail::bidirectional_at_most_t<T>>;
2627 template<typename T>
2628 constexpr static bool is_input = !is_bidirectional<T> && !is_forward<T>;
2629 #endif
2630
2631 static_assert(
2632 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2633 std::forward_iterator<I>
2634 #else
2635 is_forward<I>
2636 #endif
2637 || noexcept(ErrorHandler{}("")));
2638
2639 public:
2640 using value_type = detail::format_to_type_t<ToFormat>;
2641
2642 constexpr utf_iterator() = default;
2643
2644 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2645 template<
2646 typename J = I,
2647 typename Enable = std::enable_if_t<is_bidirectional<J>>>
2648 #endif
2649 constexpr utf_iterator(I first, I it, S last)
2650 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2651 requires std::bidirectional_iterator<I>
2652 #endif
2653 : first_and_curr_{first, it}, last_(last)
2654 {
2655 if (curr() != last_)
2656 read();
2657 }
2658 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2659 template<
2660 typename J = I,
2661 typename Enable = std::enable_if_t<!is_bidirectional<J>>>
2662 #endif
2663 constexpr utf_iterator(I it, S last)
2664 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2665 requires(!std::bidirectional_iterator<I>)
2666 #endif
2667 :
2668 first_and_curr_{it}, last_(last)
2669 {
2670 if (curr() != last_)
2671 read();
2672 }
2673
2674 template<
2675 class I2,
2676 class S2
2677 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2678 ,
2679 typename Enable = std::enable_if_t<
2680 std::is_convertible_v<I2, I> && std::is_convertible_v<S2, S>>
2681 #endif
2682 >
2683 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2684 requires std::convertible_to<I2, I> && std::convertible_to<S2, S>
2685 #endif
2686 constexpr utf_iterator(
2687 utf_iterator<FromFormat, ToFormat, I2, S2, ErrorHandler> const &
2688 other) :
2689 buf_(detail::iter_access::buf(other)),
2690 first_and_curr_(detail::iter_access::first_and_curr(other)),
2691 buf_index_(detail::iter_access::buf_index(other)),
2692 buf_last_(detail::iter_access::buf_last(other)),
2693 to_increment_(detail::iter_access::to_increment(other)),
2694 last_(detail::iter_access::last(other))
2695 {}
2696
2697 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2698 template<
2699 typename J = I,
2700 typename Enable = std::enable_if_t<is_bidirectional<J>>>
2701 #endif
2702 constexpr I begin() const
2703 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2704 requires std::bidirectional_iterator<I>
2705 #endif
2706 {
2707 return first();
2708 }
2709 constexpr S end() const { return last_; }
2710
2711 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2712 template<
2713 typename J = I,
2714 typename Enable = std::enable_if_t<is_forward<J>>>
2715 #endif
2716 constexpr I base() const
2717 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2718 requires std::forward_iterator<I>
2719 #endif
2720 {
2721 return curr();
2722 }
2723
2724 constexpr value_type operator*() const
2725 {
2726 BOOST_PARSER_DEBUG_ASSERT(buf_index_ < buf_last_);
2727 return buf_[buf_index_];
2728 }
2729
2730 constexpr utf_iterator & operator++()
2731 {
2732 BOOST_PARSER_DEBUG_ASSERT(buf_index_ != buf_last_ || curr() != last_);
2733 if (buf_index_ + 1 == buf_last_ && curr() != last_) {
2734 if constexpr (
2735 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2736 std::forward_iterator<I>
2737 #else
2738 is_forward<I>
2739 #endif
2740 ) {
2741 std::advance(curr(), to_increment_);
2742 }
2743 if (curr() == last_)
2744 buf_index_ = 0;
2745 else
2746 read();
2747 } else if (buf_index_ + 1 <= buf_last_) {
2748 ++buf_index_;
2749 }
2750 return *this;
2751 }
2752
2753 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2754 template<
2755 typename J = I,
2756 typename Enable = std::enable_if_t<is_bidirectional<J>>>
2757 #endif
2758 constexpr utf_iterator & operator--()
2759 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2760 requires std::bidirectional_iterator<I>
2761 #endif
2762 {
2763 BOOST_PARSER_DEBUG_ASSERT(buf_index_ || curr() != first());
2764 if (!buf_index_ && curr() != first())
2765 read_reverse();
2766 else if (buf_index_)
2767 --buf_index_;
2768 return *this;
2769 }
2770
2771 friend constexpr bool operator==(
2772 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2773 utf_iterator
2774 #else
2775 std::enable_if_t<is_forward<I>, utf_iterator>
2776 #endif
2777 lhs, utf_iterator rhs)
2778 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2779 requires std::forward_iterator<I> || requires(I i) { i == i; }
2780 #endif
2781 {
2782 if constexpr (
2783 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2784 std::forward_iterator<I>
2785 #else
2786 is_forward<I>
2787 #endif
2788 ) {
2789 return lhs.curr() == rhs.curr() && lhs.buf_index_ == rhs.buf_index_;
2790 } else {
2791 if (lhs.curr() != rhs.curr())
2792 return false;
2793
2794 if (lhs.buf_index_ == rhs.buf_index_ &&
2795 lhs.buf_last_ == rhs.buf_last_) {
2796 return true;
2797 }
2798
2799 return lhs.buf_index_ == lhs.buf_last_ &&
2800 rhs.buf_index_ == rhs.buf_last_;
2801 }
2802 }
2803
2804 #if !defined(__cpp_impl_three_way_comparison)
2805 friend BOOST_PARSER_CONSTEXPR bool operator!=(
2806 std::enable_if_t<is_forward<I>, utf_iterator> lhs, utf_iterator rhs)
2807 { return !(lhs == rhs); }
2808 #endif
2809
2810 friend constexpr bool operator==(utf_iterator lhs, S rhs)
2811 {
2812 if constexpr (
2813 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
2814 std::forward_iterator<I>
2815 #else
2816 is_forward<I>
2817 #endif
2818 ) {
2819 return lhs.curr() == rhs;
2820 } else {
2821 return lhs.curr() == rhs && lhs.buf_index_ == lhs.buf_last_;
2822 }
2823 }
2824
2825 #if !defined(__cpp_impl_three_way_comparison)
2826 friend BOOST_PARSER_CONSTEXPR bool operator!=(utf_iterator lhs, S rhs)
2827 { return !(lhs == rhs); }
2828 #endif
2829
2830
2831 using base_type = stl_interfaces::iterator_interface<
2832 utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>,
2833 detail::bidirectional_at_most_t<I>,
2834 value_type,
2835 value_type>;
2836 using base_type::operator++;
2837 using base_type::operator--;
2838
2839 private:
2840 constexpr char32_t decode_code_point()
2841 {
2842 if constexpr (FromFormat == format::utf8) {
2843 char32_t cp = *curr();
2844 ++curr();
2845 to_increment_ = 1;
2846 if (cp < 0x80)
2847 return cp;
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872 unsigned char curr_c = (unsigned char)cp;
2873
2874 auto error = [&]() {
2875 return ErrorHandler{}("Ill-formed UTF-8.");
2876 };
2877 auto next = [&]() {
2878 ++curr();
2879 ++to_increment_;
2880 };
2881
2882
2883
2884
2885 if (detail::in(0xc2, curr_c, 0xdf)) {
2886 cp = curr_c & 0b00011111;
2887 if (curr() == last_)
2888 return error();
2889 curr_c = *curr();
2890 if (!detail::in(0x80, curr_c, 0xbf))
2891 return error();
2892 cp = (cp << 6) + (curr_c & 0b00111111);
2893 next();
2894
2895 } else if (curr_c == 0xe0) {
2896 cp = curr_c & 0b00001111;
2897 if (curr() == last_)
2898 return error();
2899 curr_c = *curr();
2900 if (!detail::in(0xa0, curr_c, 0xbf))
2901 return error();
2902 cp = (cp << 6) + (curr_c & 0b00111111);
2903 next();
2904 if (curr() == last_)
2905 return error();
2906 curr_c = *curr();
2907 if (!detail::in(0x80, curr_c, 0xbf))
2908 return error();
2909 cp = (cp << 6) + (curr_c & 0b00111111);
2910 next();
2911 } else if (detail::in(0xe1, curr_c, 0xec)) {
2912 cp = curr_c & 0b00001111;
2913 if (curr() == last_)
2914 return error();
2915 curr_c = *curr();
2916 if (!detail::in(0x80, curr_c, 0xbf))
2917 return error();
2918 cp = (cp << 6) + (curr_c & 0b00111111);
2919 next();
2920 if (curr() == last_)
2921 return error();
2922 curr_c = *curr();
2923 if (!detail::in(0x80, curr_c, 0xbf))
2924 return error();
2925 cp = (cp << 6) + (curr_c & 0b00111111);
2926 next();
2927 } else if (curr_c == 0xed) {
2928 cp = curr_c & 0b00001111;
2929 if (curr() == last_)
2930 return error();
2931 curr_c = *curr();
2932 if (!detail::in(0x80, curr_c, 0x9f))
2933 return error();
2934 cp = (cp << 6) + (curr_c & 0b00111111);
2935 next();
2936 if (curr() == last_)
2937 return error();
2938 curr_c = *curr();
2939 if (!detail::in(0x80, curr_c, 0xbf))
2940 return error();
2941 cp = (cp << 6) + (curr_c & 0b00111111);
2942 next();
2943 } else if (detail::in(0xee, curr_c, 0xef)) {
2944 cp = curr_c & 0b00001111;
2945 if (curr() == last_)
2946 return error();
2947 curr_c = *curr();
2948 if (!detail::in(0x80, curr_c, 0xbf))
2949 return error();
2950 cp = (cp << 6) + (curr_c & 0b00111111);
2951 next();
2952 if (curr() == last_)
2953 return error();
2954 curr_c = *curr();
2955 if (!detail::in(0x80, curr_c, 0xbf))
2956 return error();
2957 cp = (cp << 6) + (curr_c & 0b00111111);
2958 next();
2959
2960 } else if (curr_c == 0xf0) {
2961 cp = curr_c & 0b00000111;
2962 if (curr() == last_)
2963 return error();
2964 curr_c = *curr();
2965 if (!detail::in(0x90, curr_c, 0xbf))
2966 return error();
2967 cp = (cp << 6) + (curr_c & 0b00111111);
2968 next();
2969 if (curr() == last_)
2970 return error();
2971 curr_c = *curr();
2972 if (!detail::in(0x80, curr_c, 0xbf))
2973 return error();
2974 cp = (cp << 6) + (curr_c & 0b00111111);
2975 next();
2976 if (curr() == last_)
2977 return error();
2978 curr_c = *curr();
2979 if (!detail::in(0x80, curr_c, 0xbf))
2980 return error();
2981 cp = (cp << 6) + (curr_c & 0b00111111);
2982 next();
2983 } else if (detail::in(0xf1, curr_c, 0xf3)) {
2984 cp = curr_c & 0b00000111;
2985 if (curr() == last_)
2986 return error();
2987 curr_c = *curr();
2988 if (!detail::in(0x80, curr_c, 0xbf))
2989 return error();
2990 cp = (cp << 6) + (curr_c & 0b00111111);
2991 next();
2992 if (curr() == last_)
2993 return error();
2994 curr_c = *curr();
2995 if (!detail::in(0x80, curr_c, 0xbf))
2996 return error();
2997 cp = (cp << 6) + (curr_c & 0b00111111);
2998 next();
2999 if (curr() == last_)
3000 return error();
3001 curr_c = *curr();
3002 if (!detail::in(0x80, curr_c, 0xbf))
3003 return error();
3004 cp = (cp << 6) + (curr_c & 0b00111111);
3005 next();
3006 } else if (curr_c == 0xf4) {
3007 cp = curr_c & 0b00000111;
3008 if (curr() == last_)
3009 return error();
3010 curr_c = *curr();
3011 if (!detail::in(0x80, curr_c, 0x8f))
3012 return error();
3013 cp = (cp << 6) + (curr_c & 0b00111111);
3014 next();
3015 if (curr() == last_)
3016 return error();
3017 curr_c = *curr();
3018 if (!detail::in(0x80, curr_c, 0xbf))
3019 return error();
3020 cp = (cp << 6) + (curr_c & 0b00111111);
3021 next();
3022 if (curr() == last_)
3023 return error();
3024 curr_c = *curr();
3025 if (!detail::in(0x80, curr_c, 0xbf))
3026 return error();
3027 cp = (cp << 6) + (curr_c & 0b00111111);
3028 next();
3029 } else {
3030 return error();
3031 }
3032 return cp;
3033 } else if constexpr (FromFormat == format::utf16) {
3034 char16_t hi = *curr();
3035 ++curr();
3036 to_increment_ = 1;
3037 if (!boost::parser::detail::text::surrogate(hi))
3038 return hi;
3039
3040 if (boost::parser::detail::text::low_surrogate(hi)) {
3041 return ErrorHandler{}(
3042 "Invalid UTF-16 sequence; lone trailing surrogate.");
3043 }
3044
3045
3046 if (curr() == last_) {
3047 return ErrorHandler{}(
3048 "Invalid UTF-16 sequence; lone leading surrogate.");
3049 }
3050
3051 char16_t lo = *curr();
3052 ++curr();
3053 ++to_increment_;
3054 if (!boost::parser::detail::text::low_surrogate(lo)) {
3055 return ErrorHandler{}(
3056 "Invalid UTF-16 sequence; lone leading surrogate.");
3057 }
3058
3059 return char32_t((hi - high_surrogate_base) << 10) +
3060 (lo - low_surrogate_base);
3061 } else {
3062 char32_t retval = *curr();
3063 ++curr();
3064 to_increment_ = 1;
3065 return retval;
3066 }
3067 }
3068
3069 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3070 template<
3071 typename J = I,
3072 typename Enable = std::enable_if_t<is_bidirectional<J>>>
3073 #endif
3074 constexpr char32_t decode_code_point_reverse()
3075 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3076 requires std::bidirectional_iterator<I>
3077 #endif
3078 {
3079 if constexpr (FromFormat == format::utf8) {
3080 curr() = detail::decrement(first(), curr());
3081 auto initial = curr();
3082 char32_t cp = decode_code_point();
3083 curr() = initial;
3084 return cp;
3085 } else if constexpr (FromFormat == format::utf16) {
3086 char16_t lo = *--curr();
3087 if (!boost::parser::detail::text::surrogate(lo))
3088 return lo;
3089
3090 if (boost::parser::detail::text::high_surrogate(lo)) {
3091 return ErrorHandler{}(
3092 "Invalid UTF-16 sequence; lone leading surrogate.");
3093 }
3094
3095
3096 if (curr() == first()) {
3097 return ErrorHandler{}(
3098 "Invalid UTF-16 sequence; lone trailing surrogate.");
3099 }
3100
3101 char16_t hi = *detail::prev(curr());
3102 if (!boost::parser::detail::text::high_surrogate(hi)) {
3103 return ErrorHandler{}(
3104 "Invalid UTF-16 sequence; lone trailing surrogate.");
3105 }
3106 --curr();
3107
3108 return char32_t((hi - high_surrogate_base) << 10) +
3109 (lo - low_surrogate_base);
3110 } else {
3111 return *--curr();
3112 }
3113 }
3114
3115 template<class Out>
3116 static constexpr Out encode_code_point(char32_t cp, Out out)
3117 {
3118 if constexpr (ToFormat == format::utf8) {
3119 if (cp < 0x80) {
3120 *out++ = static_cast<char8_type>(cp);
3121 } else if (cp < 0x800) {
3122 *out++ = static_cast<char8_type>(0xC0 + (cp >> 6));
3123 *out++ = static_cast<char8_type>(0x80 + (cp & 0x3f));
3124 } else if (cp < 0x10000) {
3125 *out++ = static_cast<char8_type>(0xe0 + (cp >> 12));
3126 *out++ = static_cast<char8_type>(0x80 + ((cp >> 6) & 0x3f));
3127 *out++ = static_cast<char8_type>(0x80 + (cp & 0x3f));
3128 } else {
3129 *out++ = static_cast<char8_type>(0xf0 + (cp >> 18));
3130 *out++ = static_cast<char8_type>(0x80 + ((cp >> 12) & 0x3f));
3131 *out++ = static_cast<char8_type>(0x80 + ((cp >> 6) & 0x3f));
3132 *out++ = static_cast<char8_type>(0x80 + (cp & 0x3f));
3133 }
3134 } else if constexpr (ToFormat == format::utf16) {
3135 if (cp < 0x10000) {
3136 *out++ = static_cast<char16_t>(cp);
3137 } else {
3138 *out++ =
3139 static_cast<char16_t>(cp >> 10) + high_surrogate_base;
3140 *out++ =
3141 static_cast<char16_t>(cp & 0x3ff) + low_surrogate_base;
3142 }
3143 } else {
3144 *out++ = cp;
3145 }
3146 return out;
3147 }
3148
3149 constexpr void read()
3150 {
3151 I initial;
3152 if constexpr (
3153 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3154 std::forward_iterator<I>
3155 #else
3156 is_forward<I>
3157 #endif
3158 ) {
3159 initial = curr();
3160 }
3161 if constexpr (noexcept(ErrorHandler{}(""))) {
3162 char32_t cp = decode_code_point();
3163 auto it = encode_code_point(cp, buf_.begin());
3164 buf_index_ = 0;
3165 buf_last_ = uint8_t(it - buf_.begin());
3166 } else {
3167 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3168 auto buf = buf_;
3169 try {
3170 #endif
3171 char32_t cp = decode_code_point();
3172 auto it = encode_code_point(cp, buf_.begin());
3173 buf_index_ = 0;
3174 buf_last_ = it - buf_.begin();
3175 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3176 } catch (...) {
3177 buf_ = buf;
3178 curr() = initial;
3179 throw;
3180 }
3181 #endif
3182 }
3183 if constexpr (
3184 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3185 std::forward_iterator<I>
3186 #else
3187 is_forward<I>
3188 #endif
3189 ) {
3190 curr() = initial;
3191 }
3192 }
3193
3194 constexpr void read_reverse()
3195 {
3196 auto initial = curr();
3197 if constexpr (noexcept(ErrorHandler{}(""))) {
3198 char32_t cp = decode_code_point_reverse();
3199 auto it = encode_code_point(cp, buf_.begin());
3200 buf_last_ = uint8_t(it - buf_.begin());
3201 buf_index_ = buf_last_ - 1;
3202 to_increment_ = (int)std::distance(curr(), initial);
3203 } else {
3204 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3205 auto buf = buf_;
3206 try {
3207 #endif
3208 char32_t cp = decode_code_point_reverse();
3209 auto it = encode_code_point(cp, buf_.begin());
3210 buf_last_ = it - buf_.begin();
3211 buf_index_ = buf_last_ - 1;
3212 to_increment_ = std::distance(curr(), initial);
3213 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3214 } catch (...) {
3215 buf_ = buf;
3216 curr() = initial;
3217 throw;
3218 }
3219 #endif
3220 }
3221 }
3222
3223 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3224 template<
3225 typename J = I,
3226 typename Enable = std::enable_if_t<is_bidirectional<J>>>
3227 #endif
3228 constexpr I first() const
3229 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3230 requires std::bidirectional_iterator<I>
3231 #endif
3232 {
3233 return first_and_curr_.first;
3234 }
3235 constexpr I & curr() { return first_and_curr_.curr; }
3236 constexpr I curr() const { return first_and_curr_.curr; }
3237
3238 std::array<value_type, 4 / static_cast<int>(ToFormat)> buf_ = {};
3239
3240 detail::first_and_curr<I> first_and_curr_ = {};
3241
3242 uint8_t buf_index_ = 0;
3243 uint8_t buf_last_ = 0;
3244 uint8_t to_increment_ = 0;
3245
3246 [[no_unique_address]] S last_ = {};
3247
3248 friend struct detail::iter_access;
3249 };
3250
3251 }}
3252
3253 namespace boost::parser::detail { namespace text { namespace detail {
3254
3255 template<class T>
3256 constexpr bool is_utf_iter = false;
3257 template<
3258 format FromFormat,
3259 format ToFormat,
3260 class I,
3261 class S,
3262 class ErrorHandler>
3263 constexpr bool
3264 is_utf_iter<utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>> =
3265 true;
3266
3267
3268
3269
3270 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3271
3272 template<typename V>
3273 constexpr bool common_range_v = std::ranges::common_range<V>;
3274 template<typename V>
3275 constexpr bool forward_range_v = std::ranges::forward_range<V>;
3276 template<typename V>
3277 constexpr bool bidirectional_range_v = std::ranges::bidirectional_range<V>;
3278 template<typename T>
3279 constexpr bool default_initializable_v = std::default_initializable<T>;
3280
3281 template<typename V>
3282 constexpr bool utf32_range_v = utf32_range<V>;
3283
3284 #else
3285
3286 template<typename T>
3287 using range_expr =
3288 decltype(detail::begin(std::declval<T &>()) == detail::end(std::declval<T &>()));
3289 template<typename T>
3290 constexpr bool is_range_v = is_detected_v<range_expr, T>;
3291
3292 template<typename V>
3293 constexpr bool common_range_v =
3294 is_range_v<V> && std::is_same_v<iterator_t<V>, sentinel_t<V>>;
3295 template<typename V>
3296 constexpr bool input_range_v = is_range_v<V> && std::is_base_of_v<
3297 std::input_iterator_tag,
3298 typename std::iterator_traits<iterator_t<V>>::iterator_category>;
3299 template<typename V>
3300 constexpr bool forward_range_v = is_range_v<V> && std::is_base_of_v<
3301 std::forward_iterator_tag,
3302 typename std::iterator_traits<iterator_t<V>>::iterator_category>;
3303 template<typename V>
3304 constexpr bool bidirectional_range_v = is_range_v<V> && std::is_base_of_v<
3305 std::bidirectional_iterator_tag,
3306 typename std::iterator_traits<iterator_t<V>>::iterator_category>;
3307 template<typename T>
3308 constexpr bool default_initializable_v = std::is_default_constructible_v<T>;
3309
3310 template<typename V>
3311 constexpr bool utf_range_v = is_range_v<V> && code_unit_v<range_value_t<V>>;
3312
3313 template<typename V>
3314 constexpr bool
3315 utf32_range_v = is_range_v<V> &&
3316 (
3317 #if !defined(_MSC_VER)
3318 std::is_same_v<range_value_t<V>, wchar_t> ||
3319 #endif
3320 std::is_same_v<range_value_t<V>, char32_t>);
3321
3322 #endif
3323
3324 template<typename I>
3325 constexpr bool random_access_iterator_v = std::is_base_of_v<
3326 std::random_access_iterator_tag,
3327 typename std::iterator_traits<I>::iterator_category>;
3328 template<typename I>
3329 constexpr bool bidirectional_iterator_v = std::is_base_of_v<
3330 std::bidirectional_iterator_tag,
3331 typename std::iterator_traits<I>::iterator_category>;
3332 template<typename I>
3333 constexpr bool forward_iterator_v = std::is_base_of_v<
3334 std::forward_iterator_tag,
3335 typename std::iterator_traits<I>::iterator_category>;
3336
3337 template<
3338 class V,
3339 bool StoreFirst = !is_utf_iter<iterator_t<V>> && common_range_v<V> &&
3340 bidirectional_range_v<V>,
3341 bool StoreLast = !is_utf_iter<iterator_t<V>>>
3342 struct first_last_storage
3343 {
3344 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3345 template<
3346 typename Enable = std::enable_if_t<
3347 default_initializable_v<iterator_t<V>> &&
3348 default_initializable_v<sentinel_t<V>>>>
3349 #endif
3350 constexpr first_last_storage()
3351 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3352 requires default_initializable_v<iterator_t<V>> &&
3353 default_initializable_v<sentinel_t<V>>
3354 #endif
3355 {}
3356 constexpr first_last_storage(V & base) :
3357 first_{detail::begin(base)}, last_{detail::end(base)}
3358 {}
3359
3360 constexpr auto begin(iterator_t<V> & it) const { return first_; }
3361 constexpr auto end(iterator_t<V> & it) const { return last_; }
3362
3363 iterator_t<V> first_;
3364 sentinel_t<V> last_;
3365 };
3366
3367 template<typename I>
3368 using trinary_iter_ctor = decltype(I(
3369 std::declval<I>().begin(),
3370 std::declval<I>().end(),
3371 std::declval<I>().end()));
3372
3373 template<class V>
3374 struct first_last_storage<V, true, false>
3375 {
3376 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3377 template<
3378 typename Enable =
3379 std::enable_if_t<default_initializable_v<iterator_t<V>>>>
3380 #endif
3381 constexpr first_last_storage()
3382 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3383 requires default_initializable_v<iterator_t<V>>
3384 #endif
3385 {}
3386 constexpr first_last_storage(V & base) : first_{detail::begin(base)} {}
3387
3388 constexpr auto begin(iterator_t<V> & it) const { return first_; }
3389 constexpr auto end(iterator_t<V> & it) const {
3390 if constexpr (
3391 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3392 requires { iterator_t<V>(it.begin(), it.end(), it.end()); }
3393 #else
3394 is_detected_v<trinary_iter_ctor, iterator_t<V>>
3395 #endif
3396 ) {
3397 return iterator_t<V>(it.begin(), it.end(), it.end());
3398 } else {
3399 return it.end();
3400 }
3401 }
3402
3403 iterator_t<V> first_;
3404 };
3405
3406 template<class V>
3407 struct first_last_storage<V, false, true>
3408 {
3409 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3410 template<
3411 typename Enable =
3412 std::enable_if_t<default_initializable_v<sentinel_t<V>>>>
3413 #endif
3414 constexpr first_last_storage()
3415 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3416 requires default_initializable_v<sentinel_t<V>>
3417 #endif
3418 {}
3419 constexpr first_last_storage(V & base) : last_{detail::end(base)} {}
3420
3421 constexpr auto begin(iterator_t<V> & it) const {
3422 if constexpr (is_utf_iter<iterator_t<V>>) {
3423 return iterator_t<V>(it.begin(), it.begin(), it.end());
3424 } else {
3425 return;
3426 }
3427 }
3428 constexpr auto end(iterator_t<V> & it) const { return last_; }
3429
3430 sentinel_t<V> last_;
3431 };
3432
3433 template<class V>
3434 struct first_last_storage<V, false, false>
3435 {
3436 constexpr first_last_storage() = default;
3437 constexpr first_last_storage(V & base) {}
3438
3439 constexpr auto begin(iterator_t<V> & it) const {
3440 if constexpr (is_utf_iter<iterator_t<V>>) {
3441 return iterator_t<V>(it.begin(), it.begin(), it.end());
3442 } else {
3443 return;
3444 }
3445 }
3446 constexpr auto end(iterator_t<V> & it) const {
3447 if constexpr (
3448 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3449 requires { iterator_t<V>(it.begin(), it.end(), it.end()); }
3450 #else
3451 is_detected_v<trinary_iter_ctor, iterator_t<V>>
3452 #endif
3453 ) {
3454 return iterator_t<V>(it.begin(), it.end(), it.end());
3455 } else {
3456 return it.end();
3457 }
3458 }
3459 };
3460
3461
3462 template<class V>
3463 constexpr auto uc_view_category() {
3464 if constexpr (common_range_v<V> && bidirectional_range_v<V>) {
3465 return std::bidirectional_iterator_tag{};
3466 } else {
3467 return std::forward_iterator_tag{};
3468 }
3469 }
3470
3471 template<class V>
3472 using uc_view_category_t = decltype(uc_view_category<V>());
3473
3474 template<bool Const, class T>
3475 using maybe_const = std::conditional_t<Const, const T, T>;
3476
3477 template<class T>
3478 constexpr bool is_empty_view = false;
3479 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
3480 template<class T>
3481 constexpr bool is_empty_view<std::ranges::empty_view<T>> = true;
3482 #endif
3483
3484 }}}
3485
3486 #endif