File indexing completed on 2025-09-17 08:40:26
0001 #ifndef BOOST_PARSER_DETAIL_CASE_FOLD_HPP
0002 #define BOOST_PARSER_DETAIL_CASE_FOLD_HPP
0003
0004 #include <boost/parser/config.hpp>
0005 #include <boost/parser/detail/text/transcode_iterator.hpp>
0006 #include <boost/parser/detail/case_fold_data_generated.hpp>
0007
0008 #include <algorithm>
0009
0010
0011 namespace boost::parser::detail {
0012
0013 template<typename I>
0014 std::optional<I> do_short_mapping(
0015 short_mapping_range const * first,
0016 short_mapping_range const * last,
0017 char32_t cp,
0018 I out)
0019 {
0020 auto it = std::lower_bound(
0021 first,
0022 last,
0023 cp,
0024 [](short_mapping_range const & range, char32_t cp) {
0025 return range.cp_first_ < cp;
0026 });
0027 if (it != first) {
0028 auto const prev = it - 1;
0029 if (prev->cp_first_ <= cp && cp < prev->cp_last_)
0030 it = prev;
0031 }
0032 if (it != last && it->cp_first_ <= cp && cp < it->cp_last_) {
0033 auto const offset = cp - it->cp_first_;
0034 if (offset % it->stride_ == 0) {
0035 *out++ =
0036 single_mapping_cps[it->first_idx_ + offset / it->stride_];
0037 return out;
0038 }
0039 }
0040
0041 return std::nullopt;
0042 }
0043
0044 template<typename I>
0045 I case_fold(char32_t cp, I out)
0046 {
0047
0048 if (cp < 0x100) {
0049
0050 if (0x41 <= cp && cp < 0x5a) {
0051 *out++ = cp + 0x20;
0052 return out;
0053 } else if (cp == 0x00DF) {
0054
0055 *out++ = 0x0073;
0056 *out++ = 0x0073;
0057 return out;
0058 } else {
0059
0060 auto const first = text::detail::begin(mapping_ranges) + 1;
0061
0062 auto const last = text::detail::begin(mapping_ranges) + 7;
0063 if (auto out_opt = do_short_mapping(first, last, cp, out))
0064 return *out_opt;
0065 }
0066 *out++ = cp;
0067 return out;
0068 }
0069
0070
0071 {
0072 auto const first = text::detail::begin(mapping_ranges);
0073 auto const last = text::detail::end(mapping_ranges);
0074 if (auto out_opt = do_short_mapping(first, last, cp, out))
0075 return *out_opt;
0076 }
0077
0078
0079 {
0080 auto const last = detail::text::detail::end(long_mappings);
0081 auto const it = std::lower_bound(
0082 detail::text::detail::begin(long_mappings),
0083 last,
0084 cp,
0085 [](long_mapping const & mapping, char32_t cp) {
0086 return mapping.cp_ < cp;
0087 });
0088 if (it != last && it->cp_ == cp) {
0089 #if BOOST_PARSER_USE_CONCEPTS
0090 return std::ranges::copy(it->mapping_, text::null_sentinel, out)
0091 .out;
0092 #else
0093 return std::copy(
0094 it->mapping_,
0095 std::find(
0096 text::detail::begin(it->mapping_),
0097 text::detail::end(it->mapping_),
0098 0),
0099 out);
0100 #endif
0101 }
0102 }
0103
0104 *out++ = cp;
0105 return out;
0106 }
0107 }
0108
0109 #endif