mirror of
https://github.com/boostorg/parser.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
93 Commits
single_hea
...
quoted_str
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3fbd6c849 | ||
|
|
2b4243151a | ||
|
|
63884d2efa | ||
|
|
3487211426 | ||
|
|
c12c512a94 | ||
|
|
8ce60a8e53 | ||
|
|
4287c9b7b3 | ||
|
|
875eb9e4aa | ||
|
|
5c7b907904 | ||
|
|
f99ae3b94a | ||
|
|
b6b77bac3c | ||
|
|
f326cd9d23 | ||
|
|
ab20bdd87f | ||
|
|
e6b59a4784 | ||
|
|
2f8270809c | ||
|
|
cdb86d8c23 | ||
|
|
150e09e309 | ||
|
|
d0208fb12c | ||
|
|
129a0ec531 | ||
|
|
95a5e088bc | ||
|
|
bb3f66db5f | ||
|
|
09322b8eb6 | ||
|
|
ae0448e321 | ||
|
|
c990799c51 | ||
|
|
7f287c5525 | ||
|
|
f9ebf50228 | ||
|
|
d0cf708ef5 | ||
|
|
47061a8716 | ||
|
|
ec5fc2ed85 | ||
|
|
4b59719e44 | ||
|
|
e06f415134 | ||
|
|
495a3fffbf | ||
|
|
3d528fa531 | ||
|
|
68c33a0181 | ||
|
|
b58b3a0779 | ||
|
|
5b7889df61 | ||
|
|
f7d26dabae | ||
|
|
935165b798 | ||
|
|
7d8f4d811a | ||
|
|
a337c16e3c | ||
|
|
2e49e5d61b | ||
|
|
df6a3db364 | ||
|
|
7d983817cc | ||
|
|
4d14fba7fd | ||
|
|
01f2f21899 | ||
|
|
473910bd52 | ||
|
|
9d1a6aeeb3 | ||
|
|
33edb6c4e8 | ||
|
|
de74eecabe | ||
|
|
91b2a36b37 | ||
|
|
ab4d708c30 | ||
|
|
e7efe90a03 | ||
|
|
4380d278aa | ||
|
|
ac84ed63b6 | ||
|
|
fc6a643a99 | ||
|
|
9fead755ca | ||
|
|
c328a18121 | ||
|
|
3549ad64a8 | ||
|
|
275874f3c6 | ||
|
|
319b39a67b | ||
|
|
edebfc3f57 | ||
|
|
385a6a4ca6 | ||
|
|
4ce4d8ba0e | ||
|
|
a68d4f61b2 | ||
|
|
d1309560df | ||
|
|
bbb1cba804 | ||
|
|
a6db478691 | ||
|
|
9bd38a51f6 | ||
|
|
8df56b083d | ||
|
|
37e56dd241 | ||
|
|
1aa95127f0 | ||
|
|
eb68bacfbb | ||
|
|
a68c1d3187 | ||
|
|
5adef16a4d | ||
|
|
aa76e9f85e | ||
|
|
52e8b187e8 | ||
|
|
591ac9921b | ||
|
|
ce7804a003 | ||
|
|
4c3e0a7448 | ||
|
|
ffdc3f967b | ||
|
|
62002e886a | ||
|
|
ee00c0393a | ||
|
|
a7384b82ad | ||
|
|
338a519bd6 | ||
|
|
7f4e8ed904 | ||
|
|
f1c77a05cd | ||
|
|
a0d18feedc | ||
|
|
22bf642024 | ||
|
|
33d0e2aef8 | ||
|
|
cfbabba598 | ||
|
|
7e2bfb691c | ||
|
|
a64d58aaff | ||
|
|
2b30e172e4 |
34
.github/workflows/deploy_unified_header.yml
vendored
Normal file
34
.github/workflows/deploy_unified_header.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Build+deploy to single_header.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup
|
||||
run: |
|
||||
mkdir ${{github.workspace}}/pcpp
|
||||
pip install -t ${{github.workspace}}/pcpp pcpp
|
||||
|
||||
- name: Build
|
||||
continue-on-error: true
|
||||
run: PYTHONPATH=${{github.workspace}}/pcpp:$PYTHONPATH python3 ${{github.workspace}}/pcpp/bin/pcpp -I ${{github.workspace}}/include --passthru-defines --passthru-comments --line-directive -o ${{github.workspace}}/onebig.hpp ${{github.workspace}}/include/boost/parser/split.hpp ${{github.workspace}}/include/boost/parser/replace.hpp ${{github.workspace}}/include/boost/parser/transcode_view.hpp
|
||||
|
||||
- name: Deploy
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
git fetch
|
||||
git switch single_header
|
||||
mv ${{github.workspace}}/onebig.hpp ${{github.workspace}}/include/boost/parser/parser_unified.hpp
|
||||
if [ `git diff` ] ; then
|
||||
git config user.name 'Zach Laine'
|
||||
git config user.email 'whatwasthataddress@gmail.com'
|
||||
git commit -am 'Generated by Github action on push to master.'
|
||||
git push
|
||||
fi
|
||||
@@ -100,22 +100,43 @@ significantly increase compile times. Also, MSVC seems to have a hard time
|
||||
with large values; I successfully set this value to `50` on MSVC, but `100`
|
||||
broke the MSVC build entirely.
|
||||
|
||||
_Parser_ uses `std::optional` internally. There is no way to change this.
|
||||
However, when _Parser_ generates values as a result of the parse (see
|
||||
_attr_gen_), it can place them into other implementations of optional, if you
|
||||
tell it to do so. You tell it a template is usable as an optional by
|
||||
specializing the `enable_optional` template. For instance, here is how you
|
||||
would tell _Parser_ that `boost::optional` is an optional-type:
|
||||
_Parser_ uses `std::optional` and `std::variant` internally. There is no way
|
||||
to change this. However, when _Parser_ generates values as a result of the
|
||||
parse (see _attr_gen_), it can place them into other implementations of
|
||||
optional and/or variant, if you tell it to do so. You tell it which templates
|
||||
are usable as an optional or variant by specializing the associated variable
|
||||
template. For instance, here is how you would tell _Parser_ that
|
||||
`boost::optional` is an optional-type:
|
||||
|
||||
template<typename T>
|
||||
constexpr bool boost::parser::enable_optional<boost::optional<T>> = true;
|
||||
|
||||
Here's how you would do the same thing for `boost::variant2::variant`:
|
||||
|
||||
template<typename... Ts>
|
||||
constexpr bool boost::parser::enable_variant<boost::variant2::variant<Ts...>> = true;
|
||||
|
||||
The requirements on a template used as an optional are pretty simple, since
|
||||
_Parser_ does almost nothing but assign to them. For a type `O` to be a
|
||||
usable optional, you must be able to assign to `O`, and `O` must have an
|
||||
`operator*` that returns the stored value, or a (possibly cv-qualified)
|
||||
reference to the stored value.
|
||||
|
||||
For variants, the requirement is even simpler; the variant type only needs to
|
||||
be assignable.
|
||||
|
||||
[note The only thing affected by `enable_variant` is printing. If your
|
||||
variant template can be printed with just `std::cout << v` (where `v` is a
|
||||
variant, obviously), then you don't need to define `enable_variant` for your
|
||||
variant template.]
|
||||
|
||||
_Parser_ uses `std::ranges::subrange` extensively. However, there is no C++17
|
||||
equivalent. So, there is a `boost::parser::subrange` for C++17 builds. To
|
||||
switch between these transparently in the code, while keeping CTAD
|
||||
operational, _Parser_ defines _SUBRNG_. This is the name of the template, so
|
||||
if you use it in your own code you would use it like `_SUBRNG_<I>` to
|
||||
instantiate it.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section This Library's Relationship to Boost.Spirit]
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
[import ../example/json.cpp]
|
||||
[import ../example/callback_json.cpp]
|
||||
[import ../example/parsing_into_a_struct.cpp]
|
||||
[import ../example/parsing_into_a_class.cpp]
|
||||
[import ../example/struct_rule.cpp]
|
||||
[import ../example/user_error_handler.cpp]
|
||||
|
||||
@@ -76,6 +77,22 @@
|
||||
[def _cb_eh_ [classref boost::parser::callback_error_handler `callback_error_handler`]]
|
||||
[def _rethrow_eh_ [classref boost::parser::rethrow_error_handler `rethrow_error_handler`]]
|
||||
|
||||
[def _trace_ [enumref boost::parser::trace `boost::parser::trace`]]
|
||||
|
||||
[def _search_ [funcref boost::parser::search `boost::parser::search()`]]
|
||||
[def _search_all_ [globalref boost::parser::search_all `boost::parser::search_all`]]
|
||||
[def _search_all_v_ [classref boost::parser::search_all_view `boost::parser::search_all_view`]]
|
||||
[def _search_all_vs_ [classref boost::parser::search_all_view `boost::parser::search_all_view`s]]
|
||||
[def _split_ [globalref boost::parser::split `boost::parser::split`]]
|
||||
[def _split_v_ [classref boost::parser::split_view `boost::parser::split_view`]]
|
||||
[def _split_vs_ [classref boost::parser::split_view `boost::parser::split_view`s]]
|
||||
[def _replace_ [globalref boost::parser::replace `boost::parser::replace`]]
|
||||
[def _replace_v_ [classref boost::parser::replace_view `boost::parser::replace_view`]]
|
||||
[def _replace_vs_ [classref boost::parser::replace_view `boost::parser::replace_view`s]]
|
||||
[def _trans_replace_ [globalref boost::parser::transform_replace `boost::parser::transform_replace`]]
|
||||
[def _trans_replace_v_ [classref boost::parser::transform_replace_view `boost::parser::transform_replace_view`]]
|
||||
[def _trans_replace_vs_ [classref boost::parser::transform_replace_view `boost::parser::transform_replace_view`s]]
|
||||
|
||||
|
||||
[def _std_str_ `std::string`]
|
||||
[def _std_vec_char_ `std::vector<char>`]
|
||||
@@ -109,9 +126,9 @@
|
||||
[def _locals_np_ [funcref boost::parser::_locals `_locals`]]
|
||||
[def _params_np_ [funcref boost::parser::_params `_params`]]
|
||||
|
||||
[def _RULE_ [macroref BOOST_PARSER_DEFINE_RULE `BOOST_PARSER_DEFINE_RULE`]]
|
||||
[def _RULES_ [macroref BOOST_PARSER_DEFINE_RULES `BOOST_PARSER_DEFINE_RULES`]]
|
||||
[def _AGGR_SIZE_ [macroref BOOST_PARSER_MAX_AGGREGATE_SIZE `BOOST_PARSER_MAX_AGGREGATE_SIZE`]]
|
||||
[def _SUBRNG_ [macroref BOOST_PARSER_SUBRANGE `BOOST_PARSER_SUBRANGE`]]
|
||||
|
||||
[def __p_ [globalref boost::parser::_p `_p`]]
|
||||
|
||||
@@ -175,18 +192,13 @@
|
||||
[def _merge_np_ [globalref boost::parser::merge `merge`]]
|
||||
[def _sep_np_ [globalref boost::parser::separate `separate`]]
|
||||
|
||||
[def _alnum_ [globalref boost::parser::ascii::alnum `ascii::alnum`]]
|
||||
[def _alpha_ [globalref boost::parser::ascii::alpha `ascii::alpha`]]
|
||||
[def _blank_ [globalref boost::parser::ascii::blank `ascii::blank`]]
|
||||
[def _cntrl_ [globalref boost::parser::ascii::cntrl `ascii::cntrl`]]
|
||||
[def _digit_ [globalref boost::parser::ascii::digit `ascii::digit`]]
|
||||
[def _graph_ [globalref boost::parser::ascii::graph `ascii::graph`]]
|
||||
[def _print_ [globalref boost::parser::ascii::print `ascii::print`]]
|
||||
[def _punct_ [globalref boost::parser::ascii::punct `ascii::punct`]]
|
||||
[def _space_ [globalref boost::parser::ascii::space `ascii::space`]]
|
||||
[def _xdigit_ [globalref boost::parser::ascii::xdigit `ascii::xdigit`]]
|
||||
[def _lower_ [globalref boost::parser::ascii::lower `ascii::lower`]]
|
||||
[def _upper_ [globalref boost::parser::ascii::upper `ascii::upper`]]
|
||||
[def _blank_ [globalref boost::parser::blank `blank`]]
|
||||
[def _control_ [globalref boost::parser::control `control`]]
|
||||
[def _digit_ [globalref boost::parser::digit `digit`]]
|
||||
[def _punct_ [globalref boost::parser::punct `punct`]]
|
||||
[def _hex_digit_ [globalref boost::parser::hex_digit `hex_digit`]]
|
||||
[def _lower_ [globalref boost::parser::lower `lower`]]
|
||||
[def _upper_ [globalref boost::parser::upper `upper`]]
|
||||
|
||||
[def _RES_ ['[^RESOLVE]]`()`]
|
||||
[def _RES_np_ ['[^RESOLVE]]]
|
||||
@@ -196,7 +208,7 @@
|
||||
[def _p_api_ [link boost_parser__proposed_.tutorial.the__parse____api The `parse()` API]]
|
||||
[def _parse_ctx_ [link boost_parser__proposed_.tutorial.the_parse_context The Parse Context]]
|
||||
[def _rule_parsers_ [link boost_parser__proposed_.tutorial.rule_parsers Rule Parsers]]
|
||||
[def _parsing_structs_ [link boost_parser__proposed_.tutorial.parsing__struct_s Parsing `struct`s]]
|
||||
[def _parsing_structs_ [link boost_parser__proposed_.tutorial.parsing_into__struct_s_and__class_es Parsing into `struct`s and `class`es]]
|
||||
[def _expect_pts_ [link boost_parser__proposed_.tutorial.backtracking.html#boost_parser__proposed_.tutorial.backtracking.expectation_points Expectation points]]
|
||||
[def _attr_gen_ [link boost_parser__proposed_.tutorial.attribute_generation Attribute Generation]]
|
||||
[def _directives_ [link boost_parser__proposed_.tutorial.directives Directives]]
|
||||
|
||||
@@ -275,4 +275,54 @@ attribute generated is different from my expressed intent, that's a problem.
|
||||
For this not to be a problem, I need to be able to understand the rules, so I
|
||||
can express my intent, and not be surprised.
|
||||
|
||||
[heading Out-parameter attributes passed to _p_ are cleared on parse failure]
|
||||
|
||||
At the end of a call to any of the _p_ overloads that takes an attribute
|
||||
out-param (including variants like _cbp_, etc.), the parse either succeeds or
|
||||
fails. If the call fails, the attribute is explicitly "cleared" by assigning
|
||||
its default-constructed value.
|
||||
|
||||
This is done because it's the less bad of two options. Consider the other
|
||||
option first.
|
||||
|
||||
// Without explicit clearing.
|
||||
namespace bp = boost::parser;
|
||||
std::vector<int> result;
|
||||
auto b = bp::parse("3 4 c", +bp::int_, bp::ws, result);
|
||||
assert(!b);
|
||||
assert(result == std::vector<int>({3, 4}));
|
||||
|
||||
This is odd _emdash_ the parse failed, but the out-param has partial results
|
||||
in it anyway. This happens because the parser `+bp::int_` only fails if it
|
||||
cannot match at `bp::int_` at least once. Above, it matches it twice, meaning
|
||||
that it succeeds (if it had failed, it would have cleared its attribute). It
|
||||
does not know that there is nothing after it that could continue the parse,
|
||||
nor that it is being used in to do a full parse. So, the over-all parse
|
||||
fails, but the part of the parse that fills in the out-param attribute does
|
||||
not know do clear its attribute.
|
||||
|
||||
This is why the explicit clearing behavior happens at the end of _p_. This is
|
||||
not without its downsides, though. Consider this.
|
||||
|
||||
// With explicit clearing.
|
||||
namespace bp = boost::parser;
|
||||
std::string str = "-42";
|
||||
int i = 3;
|
||||
bool b = parse(str, bp::uint_, i);
|
||||
assert(!b);
|
||||
assert(i == 0);
|
||||
|
||||
Here, the explicit clearing replaces the previous value of `3`, even though
|
||||
the parser never touched the value! Destroying users' variables' state
|
||||
without need may seem like a bad idea, but consider the alternative _emdash_
|
||||
In the previous example, we had spurious values left in the out-param
|
||||
attribute. Here, without clearing, we would have had a value left in the
|
||||
out-param attribute, not because it was a partial result of the parse, but
|
||||
because the parse never touched it. This is certain to be confusing, or at
|
||||
least surprising, behavior. I deemed it better to make the failed parse case
|
||||
consistent, to reduce confusion. The out-param attribute of type `A` is
|
||||
always equal to `A()` if the parser fails. It is equal to whatever the parser
|
||||
sets it to _emdash_ or its previous value, if the parser does not mutate it
|
||||
_emdash_ if the parse succeeds.
|
||||
|
||||
[endsect]
|
||||
|
||||
753
doc/tutorial.qbk
753
doc/tutorial.qbk
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ add_sample(semantic_actions)
|
||||
add_sample(rule_intro)
|
||||
add_sample(struct_rule)
|
||||
add_sample(parsing_into_a_struct)
|
||||
add_sample(parsing_into_a_class)
|
||||
add_sample(roman_numerals)
|
||||
add_sample(user_error_handler)
|
||||
|
||||
|
||||
@@ -172,13 +172,13 @@ namespace json {
|
||||
}
|
||||
};
|
||||
|
||||
auto const number_def = bp::raw
|
||||
[bp::lexeme
|
||||
[-bp::char_('-') >>
|
||||
(bp::char_('1', '9') >> *bp::ascii::digit | bp::char_('0')) >>
|
||||
-(bp::char_('.') >> +bp::ascii::digit) >>
|
||||
-(bp::char_("eE") >> -bp::char_("+-") >> +bp::ascii::digit)]]
|
||||
[parse_double];
|
||||
auto const number_def =
|
||||
bp::raw[bp::lexeme
|
||||
[-bp::char_('-') >>
|
||||
(bp::char_('1', '9') >> *bp::digit | bp::char_('0')) >>
|
||||
-(bp::char_('.') >> +bp::digit) >>
|
||||
-(bp::char_("eE") >> -bp::char_("+-") >> +bp::digit)]]
|
||||
[parse_double];
|
||||
|
||||
// The object_element_key parser is exactly the same as the string parser.
|
||||
// Note that we did *not* use string here, though; we used string_def. If
|
||||
|
||||
@@ -227,13 +227,13 @@ namespace json {
|
||||
// As indicated above, we want to match the specific formats JSON allows,
|
||||
// and then re-parse the resulting matched range within the semantic
|
||||
// action.
|
||||
auto const number_def = bp::raw
|
||||
[bp::lexeme
|
||||
[-bp::char_('-') >>
|
||||
(bp::char_('1', '9') >> *bp::ascii::digit | bp::char_('0')) >>
|
||||
-(bp::char_('.') >> +bp::ascii::digit) >>
|
||||
-(bp::char_("eE") >> -bp::char_("+-") >> +bp::ascii::digit)]]
|
||||
[parse_double];
|
||||
auto const number_def =
|
||||
bp::raw[bp::lexeme
|
||||
[-bp::char_('-') >>
|
||||
(bp::char_('1', '9') >> *bp::digit | bp::char_('0')) >>
|
||||
-(bp::char_('.') >> +bp::digit) >>
|
||||
-(bp::char_("eE") >> -bp::char_("+-") >> +bp::digit)]]
|
||||
[parse_double];
|
||||
|
||||
// Note how, in the next three parsers, we turn off backtracking by using
|
||||
// > instead of >>, once we know that there is no backtracking alternative
|
||||
|
||||
48
example/parsing_into_a_class.cpp
Normal file
48
example/parsing_into_a_class.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2024 T. Zachary Laine
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//[ parsing_into_a_class_example
|
||||
#include <boost/parser/parser.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "Enter a string followed by two unsigned integers. ";
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
|
||||
//[ parsing_into_a_class_str
|
||||
constexpr auto string_uint_uint =
|
||||
bp::lexeme[+(bp::char_ - ' ')] >> bp::uint_ >> bp::uint_;
|
||||
std::string string_from_parse;
|
||||
if (parse(input, string_uint_uint, bp::ws, string_from_parse))
|
||||
std::cout << "That yields this string: " << string_from_parse << "\n";
|
||||
else
|
||||
std::cout << "Parse failure.\n";
|
||||
//]
|
||||
|
||||
std::cout << "Enter an unsigned integer followed by a string. ";
|
||||
std::getline(std::cin, input);
|
||||
std::cout << input << "\n";
|
||||
|
||||
//[ parsing_into_a_class_vec_of_strs
|
||||
constexpr auto uint_string = bp::uint_ >> bp::char_ >> bp::char_;
|
||||
std::vector<std::string> vector_from_parse;
|
||||
if (parse(input, uint_string, bp::ws, vector_from_parse)) {
|
||||
std::cout << "That yields this vector of strings:\n";
|
||||
for (auto && str : vector_from_parse) {
|
||||
std::cout << " '" << str << "'\n";
|
||||
}
|
||||
} else {
|
||||
std::cout << "Parse failure.\n";
|
||||
}
|
||||
//]
|
||||
}
|
||||
//]
|
||||
@@ -22,7 +22,7 @@ bp::rule<struct doubles, std::vector<double>> doubles = "doubles";
|
||||
auto const doubles_def = bp::double_ % ',';
|
||||
//]
|
||||
//[ rule_intro_rule_definition_macro
|
||||
BOOST_PARSER_DEFINE_RULE(doubles);
|
||||
BOOST_PARSER_DEFINE_RULES(doubles);
|
||||
//]
|
||||
//]
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace boost { namespace parser {
|
||||
|
||||
//[ all_concepts
|
||||
template<typename T>
|
||||
concept parsable_code_unit =
|
||||
concept code_unit =
|
||||
std::same_as<std::remove_cv_t<T>, char> ||
|
||||
std::same_as<std::remove_cv_t<T>, wchar_t> ||
|
||||
std::same_as<std::remove_cv_t<T>, char8_t> ||
|
||||
@@ -28,21 +28,24 @@ namespace boost { namespace parser {
|
||||
|
||||
template<typename T>
|
||||
concept parsable_iter =
|
||||
std::forward_iterator<T> && parsable_code_unit<std::iter_value_t<T>>;
|
||||
std::forward_iterator<T> && code_unit<std::iter_value_t<T>>;
|
||||
|
||||
//[ parsable_range_like_concept
|
||||
template<typename T>
|
||||
concept parsable_range = std::ranges::forward_range<T> &&
|
||||
parsable_code_unit<std::ranges::range_value_t<T>>;
|
||||
code_unit<std::ranges::range_value_t<T>>;
|
||||
|
||||
template<typename T>
|
||||
concept parsable_pointer = std::is_pointer_v<std::remove_cvref_t<T>> &&
|
||||
parsable_code_unit<std::remove_pointer_t<std::remove_cvref_t<T>>>;
|
||||
code_unit<std::remove_pointer_t<std::remove_cvref_t<T>>>;
|
||||
|
||||
template<typename T>
|
||||
concept parsable_range_like = parsable_range<T> || parsable_pointer<T>;
|
||||
//]
|
||||
|
||||
template<typename T>
|
||||
concept range_like = std::ranges::range<T> || parsable_pointer<T>;
|
||||
|
||||
template<
|
||||
typename I,
|
||||
typename S,
|
||||
|
||||
@@ -62,6 +62,12 @@
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_constexpr_algorithms)
|
||||
# define BOOST_PARSER_ALGO_CONSTEXPR constexpr
|
||||
#else
|
||||
# define BOOST_PARSER_ALGO_CONSTEXPR
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_concepts) && !defined(BOOST_PARSER_DISABLE_CONCEPTS)
|
||||
# define BOOST_PARSER_USE_CONCEPTS 1
|
||||
#else
|
||||
|
||||
@@ -201,6 +201,48 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
digit_parser const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_subrange_parser<hex_digit_subranges> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_subrange_parser<control_subranges> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_set_parser<punct_chars> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_set_parser<lower_case_chars> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_set_parser<upper_case_chars> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context, typename Expected, typename AttributeType>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
@@ -222,17 +264,17 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
template<typename Context, typename I, typename S>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
ws_parser<true> const & parser,
|
||||
quoted_string_parser<I, S> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
template<typename Context>
|
||||
template<typename Context, bool NewlinesOnly, bool NoNewlines>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
ws_parser<false> const & parser,
|
||||
ws_parser<NewlinesOnly, NoNewlines> const & parser,
|
||||
std::ostream & os,
|
||||
int components = 0);
|
||||
|
||||
@@ -467,9 +509,7 @@ namespace boost { namespace parser { namespace detail {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_variant_v = false;
|
||||
template<typename... Ts>
|
||||
constexpr bool is_variant_v<std::variant<Ts...>> = true;
|
||||
constexpr bool is_variant_v = enable_variant<T>;
|
||||
|
||||
template<typename Attribute>
|
||||
inline void print(std::ostream & os, Attribute const & attr)
|
||||
|
||||
@@ -372,7 +372,7 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << parser.name_;
|
||||
os << parser.diagnostic_text_;
|
||||
if constexpr (!is_nope_v<ParamsTuple>) {
|
||||
os << ".with(";
|
||||
int i = 0;
|
||||
@@ -439,8 +439,7 @@ namespace boost { namespace parser { namespace detail {
|
||||
template<
|
||||
typename Context,
|
||||
typename ResolvedExpected,
|
||||
bool Integral = std::is_integral<ResolvedExpected>{},
|
||||
int SizeofExpected = sizeof(ResolvedExpected)>
|
||||
bool Integral = std::is_integral<ResolvedExpected>{}>
|
||||
struct print_expected_char_impl
|
||||
{
|
||||
static void call(
|
||||
@@ -452,13 +451,17 @@ namespace boost { namespace parser { namespace detail {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Context, typename Expected>
|
||||
struct print_expected_char_impl<Context, Expected, true, 4>
|
||||
template<typename Context>
|
||||
struct print_expected_char_impl<Context, char32_t, true>
|
||||
{
|
||||
static void
|
||||
call(Context const & context, std::ostream & os, Expected expected)
|
||||
call(Context const & context, std::ostream & os, char32_t expected)
|
||||
{
|
||||
std::array<char32_t, 1> cps = {{(char32_t)expected}};
|
||||
if (expected == '\'') {
|
||||
os << "'\\''";
|
||||
return;
|
||||
}
|
||||
std::array<char32_t, 1> cps = {{expected}};
|
||||
auto const r = cps | text::as_utf8;
|
||||
os << "'";
|
||||
for (auto c : r) {
|
||||
@@ -500,13 +503,13 @@ namespace boost { namespace parser { namespace detail {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Context, typename Iter, typename Sentinel>
|
||||
struct char_print_parser_impl<Context, char_range<Iter, Sentinel>>
|
||||
template<typename Context, typename Iter, typename Sentinel, bool B>
|
||||
struct char_print_parser_impl<Context, char_range<Iter, Sentinel, B>>
|
||||
{
|
||||
static void call(
|
||||
Context const & context,
|
||||
std::ostream & os,
|
||||
char_range<Iter, Sentinel> expected)
|
||||
char_range<Iter, Sentinel, B> expected)
|
||||
{
|
||||
os << "\"";
|
||||
auto const r = expected.chars_ | text::as_utf8;
|
||||
@@ -524,70 +527,80 @@ namespace boost { namespace parser { namespace detail {
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::alnum>>) {
|
||||
os << "ascii::alnum";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::alpha>>) {
|
||||
os << "ascii::alpha";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::blank>>) {
|
||||
os << "ascii::blank";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::cntrl>>) {
|
||||
os << "ascii::cntrl";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::digit>>) {
|
||||
os << "ascii::digit";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::graph>>) {
|
||||
os << "ascii::graph";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::print>>) {
|
||||
os << "ascii::print";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::punct>>) {
|
||||
os << "ascii::punct";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::space>>) {
|
||||
os << "ascii::space";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::xdigit>>) {
|
||||
os << "ascii::xdigit";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::lower>>) {
|
||||
os << "ascii::lower";
|
||||
} else if (std::is_same_v<
|
||||
Expected,
|
||||
ascii_char_class<ascii_char_class_t::upper>>) {
|
||||
os << "ascii::upper";
|
||||
} else {
|
||||
if (std::is_same_v<AttributeType, uint32_t>)
|
||||
os << "cp";
|
||||
else if (std::is_same_v<AttributeType, char>)
|
||||
os << "cu";
|
||||
else
|
||||
os << "char_";
|
||||
if constexpr (!is_nope_v<Expected>) {
|
||||
os << "(";
|
||||
char_print_parser_impl<Context, Expected>::call(
|
||||
context, os, parser.expected_);
|
||||
os << ")";
|
||||
}
|
||||
if (std::is_same_v<AttributeType, uint32_t>)
|
||||
os << "cp";
|
||||
else if (std::is_same_v<AttributeType, char>)
|
||||
os << "cu";
|
||||
else
|
||||
os << "char_";
|
||||
if constexpr (!is_nope_v<Expected>) {
|
||||
os << "(";
|
||||
char_print_parser_impl<Context, Expected>::call(
|
||||
context, os, parser.expected_);
|
||||
os << ")";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
digit_parser const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "digit";
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_subrange_parser<hex_digit_subranges> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "hex_digit";
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_subrange_parser<control_subranges> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "control";
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_set_parser<punct_chars> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "punct";
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_set_parser<lower_case_chars> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "lower";
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
char_set_parser<upper_case_chars> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "upper";
|
||||
}
|
||||
|
||||
template<typename Context, typename Expected, typename AttributeType>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
@@ -636,24 +649,40 @@ namespace boost { namespace parser { namespace detail {
|
||||
os << "\"";
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
template<typename Context, typename I, typename S>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
ws_parser<true> const & parser,
|
||||
quoted_string_parser<I, S> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "eol";
|
||||
os << "quoted_string(";
|
||||
if (parser.chs_.empty()) {
|
||||
detail::print_expected_char_impl<Context, char32_t>::call(
|
||||
context, os, parser.ch_);
|
||||
} else {
|
||||
os << '"';
|
||||
for (auto c : parser.chs_ | text::as_utf8) {
|
||||
detail::print_char(os, c);
|
||||
}
|
||||
os << '"';
|
||||
}
|
||||
os << ')';
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
template<typename Context, bool NewlinesOnly, bool NoNewlines>
|
||||
void print_parser(
|
||||
Context const & context,
|
||||
ws_parser<false> const & parser,
|
||||
ws_parser<NewlinesOnly, NoNewlines> const & parser,
|
||||
std::ostream & os,
|
||||
int components)
|
||||
{
|
||||
os << "ws";
|
||||
if constexpr (NoNewlines)
|
||||
os << "blank";
|
||||
else if constexpr (NewlinesOnly)
|
||||
os << "eol";
|
||||
else
|
||||
os << "ws";
|
||||
}
|
||||
|
||||
template<typename Context>
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
#else
|
||||
// This is now hard-coded to use the pre-C++20 code path. There are a bunch
|
||||
// of really odd compile errorswith Clang+libstdc++ I can't be bothered to
|
||||
// address right now. (The latest version of Boost.Text might fix these
|
||||
// errors, but there's also no pre-C++20 code path in that version of Text.)
|
||||
// address right now.
|
||||
# define BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS 0
|
||||
#endif
|
||||
|
||||
|
||||
@@ -242,11 +242,24 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
||||
typename Enable =
|
||||
std::enable_if_t<detail::is_invocable_v<F const &, T>>>
|
||||
#endif
|
||||
constexpr decltype(auto) operator()(T && t) const
|
||||
constexpr decltype(auto) operator()(T && t) const &
|
||||
{
|
||||
return f_((T &&) t);
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
|
||||
template<typename T>
|
||||
requires std::invocable<F &&, T>
|
||||
#else
|
||||
template<
|
||||
typename T,
|
||||
typename Enable = std::enable_if_t<detail::is_invocable_v<F &&, T>>>
|
||||
#endif
|
||||
constexpr decltype(auto) operator()(T && t) &&
|
||||
{
|
||||
return std::move(f_)((T &&) t);
|
||||
}
|
||||
|
||||
private:
|
||||
F f_;
|
||||
};
|
||||
@@ -295,7 +308,7 @@ namespace boost::parser::detail { namespace stl_interfaces {
|
||||
{
|
||||
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
|
||||
if constexpr (std::is_invocable_v<F const &, Args...>) {
|
||||
return f((Args &&) args...);
|
||||
return f_((Args &&) args...);
|
||||
} else {
|
||||
return closure(
|
||||
stl_interfaces::bind_back(f_, (Args &&) args...));
|
||||
|
||||
@@ -325,6 +325,8 @@ namespace boost::parser::detail { namespace text {
|
||||
|
||||
if (detail::next(first2) == last2) {
|
||||
auto const it = parser::detail::text::find(first1, last1, *first2);
|
||||
if (it == last1)
|
||||
return {it, it};
|
||||
return {it, detail::next(it)};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <iterator>
|
||||
|
||||
|
||||
#if !BOOST_PARSER_USE_CONCEPTS || defined(_MSC_VER)
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
# define BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS 0
|
||||
#else
|
||||
# define BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS 1
|
||||
@@ -20,7 +20,8 @@
|
||||
|
||||
// GCC 12 claims to support 201907L <= __cpp_deduction_guides, but does not.
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS && defined(__cpp_deduction_guides) && \
|
||||
201907L <= __cpp_deduction_guides && (!defined(__GNUC__) || 13 <= __GNUC__)
|
||||
201907L <= __cpp_deduction_guides && (!defined(__GNUC__) || 13 <= __GNUC__) && \
|
||||
!defined(_MSC_VER)
|
||||
#define BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD 1
|
||||
#else
|
||||
#define BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD 0
|
||||
|
||||
145
include/boost/parser/detail/text/detail/all_t.hpp
Normal file
145
include/boost/parser/detail/text/detail/all_t.hpp
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright (C) 2024 T. Zachary Laine
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
#ifndef BOOST_PARSER_DETAIL_TEXT_DETAIL_ALL_T_HPP
|
||||
#define BOOST_PARSER_DETAIL_TEXT_DETAIL_ALL_T_HPP
|
||||
|
||||
#include <boost/parser/detail/stl_interfaces/view_interface.hpp>
|
||||
#include <boost/parser/detail/text/detail/begin_end.hpp>
|
||||
#include <boost/parser/detail/detection.hpp>
|
||||
|
||||
#include <array>
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
#include <ranges>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost::parser::detail::text::detail {
|
||||
|
||||
template<typename T>
|
||||
using iterator_ = decltype(text::detail::begin(std::declval<T &>()));
|
||||
template<typename T>
|
||||
using sentinel_ = decltype(text::detail::end(std::declval<T &>()));
|
||||
|
||||
template<typename T>
|
||||
constexpr bool range_ =
|
||||
is_detected_v<iterator_, T> && is_detected_v<sentinel_, T>;
|
||||
|
||||
template<typename T>
|
||||
using has_insert_ = decltype(std::declval<T &>().insert(
|
||||
std::declval<T>().begin(), *std::declval<T>().begin()));
|
||||
|
||||
template<typename T>
|
||||
constexpr bool container_ = is_detected_v<has_insert_, T>;
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_std_array_v = false;
|
||||
template<typename T, size_t N>
|
||||
constexpr bool is_std_array_v<std::array<T, N>> = false;
|
||||
|
||||
template<typename R>
|
||||
constexpr bool view =
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || \
|
||||
(defined(__cpp_lib_concepts) && (!defined(__GNUC__) || 12 <= __GNUC__))
|
||||
std::ranges::view<R>
|
||||
#else
|
||||
range_<R> && !container_<R> &&
|
||||
!std::is_array_v<std::remove_reference_t<R>> &&
|
||||
!is_std_array_v<std::remove_reference_t<R>>
|
||||
#endif
|
||||
;
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Enable = std::enable_if_t<range_<R> && std::is_object_v<R>>>
|
||||
struct ref_view : stl_interfaces::view_interface<ref_view<R>>
|
||||
{
|
||||
private:
|
||||
static void rvalue_poison(R &);
|
||||
static void rvalue_poison(R &&) = delete;
|
||||
|
||||
public:
|
||||
template<
|
||||
typename T,
|
||||
typename Enable2 = std::enable_if_t<
|
||||
!std::
|
||||
is_same_v<remove_cv_ref_t<T>, remove_cv_ref_t<ref_view>> &&
|
||||
std::is_convertible_v<T, R &>>,
|
||||
typename Enable3 = decltype(rvalue_poison(std::declval<T>()))>
|
||||
constexpr ref_view(T && t) :
|
||||
r_(std::addressof(static_cast<R &>((T &&) t)))
|
||||
{}
|
||||
constexpr R & base() const { return *r_; }
|
||||
constexpr iterator_<R> begin() const
|
||||
{
|
||||
return text::detail::begin(*r_);
|
||||
}
|
||||
constexpr sentinel_<R> end() const { return text::detail::end(*r_); }
|
||||
|
||||
private:
|
||||
R * r_;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
ref_view(R &) -> ref_view<R>;
|
||||
|
||||
template<typename R>
|
||||
struct owning_view : stl_interfaces::view_interface<owning_view<R>>
|
||||
{
|
||||
owning_view() = default;
|
||||
constexpr owning_view(R && t) : r_(std::move(t)) {}
|
||||
|
||||
owning_view(owning_view &&) = default;
|
||||
owning_view & operator=(owning_view &&) = default;
|
||||
|
||||
constexpr R & base() & noexcept { return r_; }
|
||||
constexpr const R & base() const & noexcept { return r_; }
|
||||
constexpr R && base() && noexcept { return std::move(r_); }
|
||||
constexpr const R && base() const && noexcept { return std::move(r_); }
|
||||
|
||||
constexpr iterator_<R> begin() { return text::detail::begin(r_); }
|
||||
constexpr sentinel_<R> end() { return text::detail::end(r_); }
|
||||
|
||||
constexpr auto begin() const { return text::detail::begin(r_); }
|
||||
constexpr auto end() const { return text::detail::end(r_); }
|
||||
|
||||
private:
|
||||
R r_ = R();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using can_ref_view_expr = decltype(ref_view(std::declval<T>()));
|
||||
template<typename T>
|
||||
constexpr bool can_ref_view = is_detected_v<can_ref_view_expr, T>;
|
||||
|
||||
struct all_impl
|
||||
{
|
||||
template<typename R, typename Enable = std::enable_if_t<range_<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(R && r) const
|
||||
{
|
||||
using T = remove_cv_ref_t<R>;
|
||||
if constexpr (view<T>)
|
||||
return (R &&) r;
|
||||
else if constexpr (can_ref_view<R>)
|
||||
return ref_view(r);
|
||||
else
|
||||
return owning_view<T>(std::move(r));
|
||||
}
|
||||
};
|
||||
|
||||
constexpr all_impl all;
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS && \
|
||||
(!defined(__GNUC__) || 12 <= __GNUC__)
|
||||
template<typename R>
|
||||
using all_t = std::views::all_t<R>;
|
||||
#else
|
||||
template<typename R>
|
||||
using all_t = decltype(all(std::declval<R>()));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -943,23 +943,23 @@ namespace boost::parser::detail { namespace text {
|
||||
#else
|
||||
template<typename I>
|
||||
#endif
|
||||
friend constexpr auto operator==(I it, null_sentinel_t)
|
||||
friend constexpr bool operator==(I it, null_sentinel_t)
|
||||
{
|
||||
return *it == detail::iter_value_t<I>{};
|
||||
}
|
||||
#if !defined(__cpp_impl_three_way_comparison)
|
||||
template<typename I>
|
||||
friend constexpr auto operator==(null_sentinel_t, I it)
|
||||
friend constexpr bool operator==(null_sentinel_t, I it)
|
||||
{
|
||||
return *it == detail::iter_value_t<I>{};
|
||||
}
|
||||
template<typename I>
|
||||
friend constexpr auto operator!=(I it, null_sentinel_t)
|
||||
friend constexpr bool operator!=(I it, null_sentinel_t)
|
||||
{
|
||||
return *it != detail::iter_value_t<I>{};
|
||||
}
|
||||
template<typename I>
|
||||
friend constexpr auto operator!=(null_sentinel_t, I it)
|
||||
friend constexpr bool operator!=(null_sentinel_t, I it)
|
||||
{
|
||||
return *it != detail::iter_value_t<I>{};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <boost/parser/detail/text/transcode_algorithm.hpp>
|
||||
#include <boost/parser/detail/text/transcode_iterator.hpp>
|
||||
#include <boost/parser/detail/text/detail/all_t.hpp>
|
||||
|
||||
#include <boost/parser/detail/stl_interfaces/view_interface.hpp>
|
||||
#include <boost/parser/detail/stl_interfaces/view_adaptor.hpp>
|
||||
@@ -43,13 +44,27 @@ namespace boost::parser::detail { namespace text {
|
||||
using iterator_to_tag_t = decltype(iterator_to_tag<I>());
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
#if defined(__GNUC__) && __GNUC__ < 12
|
||||
// This uses the final version of viewable_range. Older GCCs use a
|
||||
// different one that breaks, so we use this on instead of the one
|
||||
// from std::ranges::. It's missing the !initializer_list part.
|
||||
template<typename T>
|
||||
concept viewable_range = std::ranges::range<T> &&
|
||||
((std::ranges::view<std::remove_cvref_t<T>> &&
|
||||
std::constructible_from<std::remove_cvref_t<T>, T>) ||
|
||||
(!std::ranges::view<std::remove_cvref_t<T>> &&
|
||||
(std::is_lvalue_reference_v<T> ||
|
||||
std::movable<std::remove_reference_t<T>>)));
|
||||
#else
|
||||
template<typename T>
|
||||
concept viewable_range = std::ranges::viewable_range<T>;
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
using with_reference = T &;
|
||||
template<typename T>
|
||||
concept can_reference = requires { typename with_reference<T>; };
|
||||
#endif
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class Char>
|
||||
struct cast_to_charn {
|
||||
constexpr Char operator()(Char c) const { return c; }
|
||||
@@ -264,7 +279,7 @@ namespace boost::parser::detail { namespace text {
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
template<class R, auto F>
|
||||
project_view(R &&) -> project_view<std::views::all_t<R>, F>;
|
||||
project_view(R &&) -> project_view<detail::all_t<R>, F>;
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
@@ -280,7 +295,7 @@ namespace boost::parser::detail { namespace text {
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class R>
|
||||
requires std::ranges::viewable_range<R> &&
|
||||
requires viewable_range<R> &&
|
||||
std::ranges::input_range<R> &&
|
||||
std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<R>> &&
|
||||
detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<R>>>
|
||||
@@ -386,11 +401,11 @@ namespace boost::parser::detail { namespace text {
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class R>
|
||||
char8_view(R &&) -> char8_view<std::views::all_t<R>>;
|
||||
char8_view(R &&) -> char8_view<detail::all_t<R>>;
|
||||
template<class R>
|
||||
char16_view(R &&) -> char16_view<std::views::all_t<R>>;
|
||||
char16_view(R &&) -> char16_view<detail::all_t<R>>;
|
||||
template<class R>
|
||||
char32_view(R &&) -> char32_view<std::views::all_t<R>>;
|
||||
char32_view(R &&) -> char32_view<detail::all_t<R>>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -401,7 +416,7 @@ namespace boost::parser::detail { namespace text {
|
||||
{
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class R>
|
||||
requires (std::ranges::viewable_range<R> &&
|
||||
requires (viewable_range<R> &&
|
||||
std::ranges::input_range<R> &&
|
||||
std::convertible_to<std::ranges::range_reference_t<R>, format_to_type_t<Format>>) ||
|
||||
utf_pointer<std::remove_cvref_t<R>>
|
||||
@@ -481,10 +496,8 @@ namespace boost::parser::detail { namespace text {
|
||||
constexpr auto end() const { return code_units().end(); }
|
||||
};
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class R>
|
||||
unpacking_view(R &&) -> unpacking_view<std::views::all_t<R>>;
|
||||
#endif
|
||||
unpacking_view(R &&) -> unpacking_view<detail::all_t<R>>;
|
||||
// clang-format on
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
@@ -519,11 +532,9 @@ namespace boost::parser::detail { namespace text {
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr utf_view()
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
requires std::default_initializable<V>
|
||||
constexpr utf_view() requires std::default_initializable<V> = default;
|
||||
#endif
|
||||
= default;
|
||||
constexpr utf_view(V base) : base_{std::move(base)} {}
|
||||
|
||||
constexpr V base() const &
|
||||
@@ -609,7 +620,7 @@ namespace boost::parser::detail { namespace text {
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
|
||||
template<format Format, class R>
|
||||
utf_view(R &&) -> utf_view<Format, std::views::all_t<R>>;
|
||||
utf_view(R &&) -> utf_view<Format, detail::all_t<R>>;
|
||||
|
||||
template<class V>
|
||||
using utf8_view = utf_view<format::utf8, V>;
|
||||
@@ -675,13 +686,13 @@ namespace boost::parser::detail { namespace text {
|
||||
{}
|
||||
};
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
#if !BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
template<class R>
|
||||
utf8_view(R &&) -> utf8_view<std::views::all_t<R>>;
|
||||
utf8_view(R &&) -> utf8_view<detail::all_t<R>>;
|
||||
template<class R>
|
||||
utf16_view(R &&) -> utf16_view<std::views::all_t<R>>;
|
||||
utf16_view(R &&) -> utf16_view<detail::all_t<R>>;
|
||||
template<class R>
|
||||
utf32_view(R &&) -> utf32_view<std::views::all_t<R>>;
|
||||
utf32_view(R &&) -> utf32_view<detail::all_t<R>>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -702,7 +713,7 @@ namespace boost::parser::detail { namespace text {
|
||||
namespace detail {
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class R, template<class> class View>
|
||||
concept can_utf_view = requires { View(std::declval<R>()); };
|
||||
concept can_utf_view = requires(R && r) { View((R &&)r); };
|
||||
#else
|
||||
template<class R, class View>
|
||||
using can_utf_view_expr = decltype(View(std::declval<R>()));
|
||||
@@ -760,7 +771,7 @@ namespace boost::parser::detail { namespace text {
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class R>
|
||||
requires is_utf_view<std::remove_cvref_t<R>> ||
|
||||
(std::ranges::viewable_range<R> &&
|
||||
(viewable_range<R> &&
|
||||
can_utf_view<unpacked_range<R>, View>) ||
|
||||
utf_pointer<std::remove_cvref_t<R>>
|
||||
#else
|
||||
@@ -800,12 +811,14 @@ namespace boost::parser::detail { namespace text {
|
||||
|
||||
}}
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
#if defined(__cpp_lib_ranges)
|
||||
|
||||
namespace std::ranges {
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
|
||||
template<class V, auto F>
|
||||
inline constexpr bool enable_borrowed_range<boost::parser::detail::text::project_view<V, F>> =
|
||||
enable_borrowed_range<V>;
|
||||
#endif
|
||||
|
||||
template<class V>
|
||||
inline constexpr bool enable_borrowed_range<boost::parser::detail::text::unpacking_view<V>> =
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
namespace boost::parser::detail { namespace text {
|
||||
|
||||
/** The Unicode Transformation Formats. */
|
||||
enum class format { utf8 = 1, utf16 = 2, utf32 = 4 };
|
||||
enum class format { none = 0, utf8 = 1, utf16 = 2, utf32 = 4 };
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
|
||||
706
include/boost/parser/detail/unicode_char_sets.hpp
Normal file
706
include/boost/parser/detail/unicode_char_sets.hpp
Normal file
@@ -0,0 +1,706 @@
|
||||
// Copyright (C) 2024 T. Zachary Laine
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
#ifndef BOOST_PARSER_UNICODE_CHAR_SETS_HPP
|
||||
#define BOOST_PARSER_UNICODE_CHAR_SETS_HPP
|
||||
|
||||
#include <boost/parser/parser_fwd.hpp>
|
||||
|
||||
|
||||
namespace boost::parser::detail {
|
||||
|
||||
// Produced from https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp,
|
||||
// using "[:Pc:][:Pd:][:Pe:][:Pf:][:Pi:][:Ps:][:Po:]" for the Input field,
|
||||
// using the categories found at
|
||||
// https://www.fileformat.info/info/unicode/category/index.htm
|
||||
template<>
|
||||
struct char_set<punct_chars>
|
||||
{
|
||||
static constexpr uint32_t chars[] = {
|
||||
0x21, 0x22, 0x23, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2A, 0x5B, 0x5C, 0x5D, 0x5F, 0x7B,
|
||||
0x7D, 0x2C, 0x2D, 0x2E, 0x2F, 0x3A, 0x3B,
|
||||
0x3F, 0x40, 0xA1, 0xA7, 0xAB, 0xB6, 0xB7,
|
||||
0xBB, 0xBF, 0x37E, 0x387, 0x55A, 0x55B, 0x55C,
|
||||
0x55D, 0x55E, 0x55F, 0x589, 0x58A, 0x5BE, 0x5C0,
|
||||
0x5C3, 0x5C6, 0x5F3, 0x5F4, 0x609, 0x60A, 0x60C,
|
||||
0x60D, 0x61B, 0x61D, 0x61E, 0x61F, 0x66A, 0x66B,
|
||||
0x66C, 0x66D, 0x6D4, 0x700, 0x701, 0x702, 0x703,
|
||||
0x704, 0x705, 0x706, 0x707, 0x708, 0x709, 0x70A,
|
||||
0x70B, 0x70C, 0x70D, 0x7F7, 0x7F8, 0x7F9, 0x830,
|
||||
0x831, 0x832, 0x833, 0x834, 0x835, 0x836, 0x837,
|
||||
0x838, 0x839, 0x83A, 0x83B, 0x83C, 0x83D, 0x83E,
|
||||
0x85E, 0x964, 0x965, 0x970, 0x9FD, 0xA76, 0xAF0,
|
||||
0xC77, 0xC84, 0xDF4, 0xE4F, 0xE5A, 0xE5B, 0xF04,
|
||||
0xF05, 0xF06, 0xF07, 0xFD3, 0xFD4, 0xF08, 0xF09,
|
||||
0xF0A, 0xF0B, 0xF0C, 0xF0D, 0xF0E, 0xF0F, 0xF10,
|
||||
0xF11, 0xF12, 0xF14, 0xF85, 0xFD0, 0xFD1, 0xFD2,
|
||||
0xF3A, 0xF3B, 0xF3C, 0xF3D, 0xFD9, 0xFDA, 0x104A,
|
||||
0x104B, 0x104C, 0x104D, 0x104E, 0x104F, 0x10FB, 0x1360,
|
||||
0x1361, 0x1362, 0x1363, 0x1364, 0x1365, 0x1366, 0x1367,
|
||||
0x1368, 0x1400, 0x166E, 0x169B, 0x169C, 0x16EB, 0x16EC,
|
||||
0x16ED, 0x1735, 0x1736, 0x17D4, 0x17D5, 0x17D6, 0x17D8,
|
||||
0x17D9, 0x17DA, 0x1800, 0x1801, 0x1802, 0x1803, 0x1804,
|
||||
0x1805, 0x1806, 0x1807, 0x1808, 0x1809, 0x180A, 0x1944,
|
||||
0x1945, 0x1A1E, 0x1A1F, 0x1AA0, 0x1AA1, 0x1AA2, 0x1AA3,
|
||||
0x1AA4, 0x1AA5, 0x1AA6, 0x1AA8, 0x1AA9, 0x1AAA, 0x1AAB,
|
||||
0x1AAC, 0x1AAD, 0x1B5A, 0x1B5B, 0x1B5C, 0x1B5D, 0x1B5E,
|
||||
0x1B5F, 0x1B60, 0x1B7D, 0x1B7E, 0x1BFC, 0x1BFD, 0x1BFE,
|
||||
0x1BFF, 0x1C3B, 0x1C3C, 0x1C3D, 0x1C3E, 0x1C3F, 0x1C7E,
|
||||
0x1C7F, 0x1CC0, 0x1CC1, 0x1CC2, 0x1CC3, 0x1CC4, 0x1CC5,
|
||||
0x1CC6, 0x1CC7, 0x1CD3, 0x2010, 0x2011, 0x2012, 0x2013,
|
||||
0x2014, 0x2015, 0x2016, 0x2017, 0x2020, 0x2021, 0x2022,
|
||||
0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2030, 0x2031,
|
||||
0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038,
|
||||
0x203B, 0x203D, 0x203E, 0x203F, 0x2040, 0x2041, 0x2042,
|
||||
0x2043, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
|
||||
0x2050, 0x2051, 0x2053, 0x2054, 0x2055, 0x2057, 0x2018,
|
||||
0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
|
||||
0x2039, 0x203A, 0x203C, 0x2047, 0x2048, 0x2049, 0x2045,
|
||||
0x2046, 0x2056, 0x2058, 0x2059, 0x205A, 0x205B, 0x205C,
|
||||
0x205D, 0x205E, 0x207D, 0x207E, 0x208D, 0x208E, 0x2308,
|
||||
0x2309, 0x230A, 0x230B, 0x2329, 0x232A, 0x2768, 0x2769,
|
||||
0x276A, 0x276B, 0x276C, 0x276D, 0x276E, 0x276F, 0x2770,
|
||||
0x2771, 0x2772, 0x2773, 0x2774, 0x2775, 0x27C5, 0x27C6,
|
||||
0x27E6, 0x27E7, 0x27E8, 0x27E9, 0x27EA, 0x27EB, 0x27EC,
|
||||
0x27ED, 0x27EE, 0x27EF, 0x2983, 0x2984, 0x2985, 0x2986,
|
||||
0x2987, 0x2988, 0x2989, 0x298A, 0x298B, 0x298C, 0x2991,
|
||||
0x2992, 0x2993, 0x2994, 0x2995, 0x2996, 0x2997, 0x2998,
|
||||
0x29FC, 0x29FD, 0x298D, 0x298E, 0x298F, 0x2990, 0x29D8,
|
||||
0x29D9, 0x29DA, 0x29DB, 0x2CF9, 0x2CFA, 0x2CFB, 0x2CFC,
|
||||
0x2CFE, 0x2CFF, 0x2D70, 0x2E00, 0x2E01, 0x2E02, 0x2E03,
|
||||
0x2E04, 0x2E05, 0x2E06, 0x2E07, 0x2E08, 0x2E09, 0x2E0A,
|
||||
0x2E0B, 0x2E0C, 0x2E0D, 0x2E0E, 0x2E0F, 0x2E10, 0x2E11,
|
||||
0x2E12, 0x2E13, 0x2E14, 0x2E15, 0x2E16, 0x2E17, 0x2E18,
|
||||
0x2E19, 0x2E1A, 0x2E1B, 0x2E1E, 0x2E1F, 0x2E1C, 0x2E1D,
|
||||
0x2E20, 0x2E21, 0x2E26, 0x2E27, 0x2E28, 0x2E29, 0x2E55,
|
||||
0x2E56, 0x2E57, 0x2E58, 0x2E22, 0x2E23, 0x2E24, 0x2E25,
|
||||
0x2E2A, 0x2E2B, 0x2E2C, 0x2E2D, 0x2E2E, 0x2E30, 0x2E31,
|
||||
0x2E33, 0x2E34, 0x2E3F, 0x2E4A, 0x2E4B, 0x2E4C, 0x2E4D,
|
||||
0x2E4E, 0x2E4F, 0x2E52, 0x2E53, 0x2E54, 0x2E32, 0x2E35,
|
||||
0x2E36, 0x2E37, 0x2E38, 0x2E39, 0x2E3A, 0x2E3B, 0x2E3C,
|
||||
0x2E3D, 0x2E3E, 0x2E40, 0x2E41, 0x2E42, 0x2E43, 0x2E44,
|
||||
0x2E45, 0x2E46, 0x2E47, 0x2E48, 0x2E49, 0x2E59, 0x2E5A,
|
||||
0x2E5B, 0x2E5C, 0x2E5D, 0x3001, 0x3002, 0x3003, 0x3008,
|
||||
0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, 0x300F,
|
||||
0x3010, 0x3011, 0x3014, 0x3015, 0x3016, 0x3017, 0x3018,
|
||||
0x3019, 0x301A, 0x301B, 0x301C, 0x301D, 0x301E, 0x301F,
|
||||
0x3030, 0x303D, 0x30A0, 0x30FB, 0xA4FE, 0xA4FF, 0xA60D,
|
||||
0xA60E, 0xA60F, 0xA673, 0xA67E, 0xA6F2, 0xA6F3, 0xA6F4,
|
||||
0xA6F5, 0xA6F6, 0xA6F7, 0xA874, 0xA875, 0xA876, 0xA877,
|
||||
0xA8CE, 0xA8CF, 0xA8F8, 0xA8F9, 0xA8FA, 0xA8FC, 0xA92E,
|
||||
0xA92F, 0xA95F, 0xA9C1, 0xA9C2, 0xA9C3, 0xA9C4, 0xA9C5,
|
||||
0xA9C6, 0xA9C7, 0xA9C8, 0xA9C9, 0xA9CA, 0xA9CB, 0xA9CC,
|
||||
0xA9CD, 0xA9DE, 0xA9DF, 0xAA5C, 0xAA5D, 0xAA5E, 0xAA5F,
|
||||
0xAADE, 0xAADF, 0xAAF0, 0xAAF1, 0xABEB, 0xFD3E, 0xFD3F,
|
||||
0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16,
|
||||
0xFE17, 0xFE18, 0xFE19, 0xFE30, 0xFE31, 0xFE32, 0xFE33,
|
||||
0xFE34, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A,
|
||||
0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F, 0xFE40, 0xFE41,
|
||||
0xFE42, 0xFE43, 0xFE44, 0xFE47, 0xFE48, 0xFE45, 0xFE46,
|
||||
0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
|
||||
0xFE50, 0xFE51, 0xFE52, 0xFE54, 0xFE55, 0xFE56, 0xFE57,
|
||||
0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E,
|
||||
0xFE5F, 0xFE60, 0xFE61, 0xFE63, 0xFE68, 0xFE6A, 0xFE6B,
|
||||
0xFF01, 0xFF02, 0xFF03, 0xFF05, 0xFF06, 0xFF07, 0xFF08,
|
||||
0xFF09, 0xFF0A, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F, 0xFF1A,
|
||||
0xFF1B, 0xFF1F, 0xFF20, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3F,
|
||||
0xFF5B, 0xFF5D, 0xFF5F, 0xFF60, 0xFF61, 0xFF62, 0xFF63,
|
||||
0xFF64, 0xFF65, 0x10100, 0x10101, 0x10102, 0x1039F, 0x103D0,
|
||||
0x1056F, 0x10857, 0x1091F, 0x1093F, 0x10A50, 0x10A51, 0x10A52,
|
||||
0x10A53, 0x10A54, 0x10A55, 0x10A56, 0x10A57, 0x10A58, 0x10A7F,
|
||||
0x10AF0, 0x10AF1, 0x10AF2, 0x10AF3, 0x10AF4, 0x10AF5, 0x10AF6,
|
||||
0x10B39, 0x10B3A, 0x10B3B, 0x10B3C, 0x10B3D, 0x10B3E, 0x10B3F,
|
||||
0x10B99, 0x10B9A, 0x10B9B, 0x10B9C, 0x10EAD, 0x10F55, 0x10F56,
|
||||
0x10F57, 0x10F58, 0x10F59, 0x10F86, 0x10F87, 0x10F88, 0x10F89,
|
||||
0x11047, 0x11048, 0x11049, 0x1104A, 0x1104B, 0x1104C, 0x1104D,
|
||||
0x110BB, 0x110BC, 0x110BE, 0x110BF, 0x110C0, 0x110C1, 0x11140,
|
||||
0x11141, 0x11142, 0x11143, 0x11174, 0x11175, 0x111C5, 0x111C6,
|
||||
0x111C7, 0x111C8, 0x111CD, 0x111DB, 0x111DD, 0x111DE, 0x111DF,
|
||||
0x11238, 0x11239, 0x1123A, 0x1123B, 0x1123C, 0x1123D, 0x112A9,
|
||||
0x1144B, 0x1144C, 0x1144D, 0x1144E, 0x1144F, 0x1145A, 0x1145B,
|
||||
0x1145D, 0x114C6, 0x115C1, 0x115C2, 0x115C3, 0x115C4, 0x115C5,
|
||||
0x115C6, 0x115C7, 0x115C8, 0x115C9, 0x115CA, 0x115CB, 0x115CC,
|
||||
0x115CD, 0x115CE, 0x115CF, 0x115D0, 0x115D1, 0x115D2, 0x115D3,
|
||||
0x115D4, 0x115D5, 0x115D6, 0x115D7, 0x11641, 0x11642, 0x11643,
|
||||
0x11660, 0x11661, 0x11662, 0x11663, 0x11664, 0x11665, 0x11666,
|
||||
0x11667, 0x11668, 0x11669, 0x1166A, 0x1166B, 0x1166C, 0x116B9,
|
||||
0x1173C, 0x1173D, 0x1173E, 0x1183B, 0x11944, 0x11945, 0x11946,
|
||||
0x119E2, 0x11A3F, 0x11A40, 0x11A45, 0x11A46, 0x11A41, 0x11A42,
|
||||
0x11A43, 0x11A44, 0x11A9A, 0x11A9B, 0x11A9C, 0x11A9E, 0x11A9F,
|
||||
0x11AA0, 0x11AA1, 0x11AA2, 0x11B00, 0x11B01, 0x11B02, 0x11B03,
|
||||
0x11B04, 0x11B05, 0x11B06, 0x11B07, 0x11B08, 0x11B09, 0x11C41,
|
||||
0x11C42, 0x11C43, 0x11C44, 0x11C45, 0x11C70, 0x11C71, 0x11EF7,
|
||||
0x11EF8, 0x11F43, 0x11F44, 0x11F45, 0x11F46, 0x11F47, 0x11F48,
|
||||
0x11F49, 0x11F4A, 0x11F4B, 0x11F4C, 0x11F4D, 0x11F4E, 0x11F4F,
|
||||
0x11FFF, 0x12470, 0x12471, 0x12472, 0x12473, 0x12474, 0x12FF1,
|
||||
0x12FF2, 0x16A6E, 0x16A6F, 0x16AF5, 0x16B37, 0x16B38, 0x16B39,
|
||||
0x16B3A, 0x16B3B, 0x16B44, 0x16E97, 0x16E98, 0x16E99, 0x16E9A,
|
||||
0x16FE2, 0x1BC9F, 0x1DA87, 0x1DA88, 0x1DA89, 0x1DA8A, 0x1DA8B,
|
||||
0x1E95E, 0x1E95F};
|
||||
};
|
||||
|
||||
// Produced from https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp,
|
||||
// using "[:Ll:]" for the Input field, using the categories found at
|
||||
// https://www.fileformat.info/info/unicode/category/index.htm
|
||||
template<>
|
||||
struct char_set<lower_case_chars>
|
||||
{
|
||||
static constexpr uint32_t chars[] = {
|
||||
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||
0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
0x79, 0x7A, 0xB5, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3,
|
||||
0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
|
||||
0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3,
|
||||
0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC,
|
||||
0xFD, 0xFE, 0xFF, 0x101, 0x103, 0x105, 0x107, 0x109,
|
||||
0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119,
|
||||
0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129,
|
||||
0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x138,
|
||||
0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148,
|
||||
0x149, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157,
|
||||
0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167,
|
||||
0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177,
|
||||
0x17A, 0x17C, 0x17E, 0x17F, 0x180, 0x183, 0x185, 0x188,
|
||||
0x18C, 0x18D, 0x192, 0x195, 0x199, 0x19A, 0x19B, 0x19E,
|
||||
0x1A1, 0x1A3, 0x1A5, 0x1A8, 0x1AA, 0x1AB, 0x1AD, 0x1B0,
|
||||
0x1B4, 0x1B6, 0x1B9, 0x1BA, 0x1BD, 0x1BE, 0x1BF, 0x1C6,
|
||||
0x1C9, 0x1CC, 0x1CE, 0x1D0, 0x1D2, 0x1D4, 0x1D6, 0x1D8,
|
||||
0x1DA, 0x1DC, 0x1DD, 0x1DF, 0x1E1, 0x1E3, 0x1E5, 0x1E7,
|
||||
0x1E9, 0x1EB, 0x1ED, 0x1EF, 0x1F0, 0x1F3, 0x1F5, 0x1F9,
|
||||
0x1FB, 0x1FD, 0x1FF, 0x201, 0x203, 0x205, 0x207, 0x209,
|
||||
0x20B, 0x20D, 0x20F, 0x211, 0x213, 0x215, 0x217, 0x219,
|
||||
0x21B, 0x21D, 0x21F, 0x221, 0x223, 0x225, 0x227, 0x229,
|
||||
0x22B, 0x22D, 0x22F, 0x231, 0x233, 0x234, 0x235, 0x236,
|
||||
0x237, 0x238, 0x239, 0x23C, 0x23F, 0x240, 0x242, 0x247,
|
||||
0x249, 0x24B, 0x24D, 0x24F, 0x250, 0x251, 0x252, 0x253,
|
||||
0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B,
|
||||
0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263,
|
||||
0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x26B,
|
||||
0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273,
|
||||
0x274, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27A, 0x27B,
|
||||
0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283,
|
||||
0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B,
|
||||
0x28C, 0x28D, 0x28E, 0x28F, 0x290, 0x291, 0x292, 0x293,
|
||||
0x295, 0x296, 0x297, 0x298, 0x299, 0x29A, 0x29B, 0x29C,
|
||||
0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, 0x2A2, 0x2A3, 0x2A4,
|
||||
0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, 0x2AA, 0x2AB, 0x2AC,
|
||||
0x2AD, 0x2AE, 0x2AF, 0x371, 0x373, 0x377, 0x37B, 0x37C,
|
||||
0x37D, 0x390, 0x3AC, 0x3AD, 0x3AE, 0x3AF, 0x3B0, 0x3B1,
|
||||
0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9,
|
||||
0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1,
|
||||
0x3C2, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9,
|
||||
0x3CA, 0x3CB, 0x3CC, 0x3CD, 0x3CE, 0x3D0, 0x3D1, 0x3D5,
|
||||
0x3D6, 0x3D7, 0x3D9, 0x3DB, 0x3DD, 0x3DF, 0x3E1, 0x3E3,
|
||||
0x3E5, 0x3E7, 0x3E9, 0x3EB, 0x3ED, 0x3EF, 0x3F0, 0x3F1,
|
||||
0x3F2, 0x3F3, 0x3F5, 0x3F8, 0x3FB, 0x3FC, 0x430, 0x431,
|
||||
0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439,
|
||||
0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441,
|
||||
0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449,
|
||||
0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x450, 0x451,
|
||||
0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459,
|
||||
0x45A, 0x45B, 0x45C, 0x45D, 0x45E, 0x45F, 0x461, 0x463,
|
||||
0x465, 0x467, 0x469, 0x46B, 0x46D, 0x46F, 0x471, 0x473,
|
||||
0x475, 0x477, 0x479, 0x47B, 0x47D, 0x47F, 0x481, 0x48B,
|
||||
0x48D, 0x48F, 0x491, 0x493, 0x495, 0x497, 0x499, 0x49B,
|
||||
0x49D, 0x49F, 0x4A1, 0x4A3, 0x4A5, 0x4A7, 0x4A9, 0x4AB,
|
||||
0x4AD, 0x4AF, 0x4B1, 0x4B3, 0x4B5, 0x4B7, 0x4B9, 0x4BB,
|
||||
0x4BD, 0x4BF, 0x4C2, 0x4C4, 0x4C6, 0x4C8, 0x4CA, 0x4CC,
|
||||
0x4CE, 0x4CF, 0x4D1, 0x4D3, 0x4D5, 0x4D7, 0x4D9, 0x4DB,
|
||||
0x4DD, 0x4DF, 0x4E1, 0x4E3, 0x4E5, 0x4E7, 0x4E9, 0x4EB,
|
||||
0x4ED, 0x4EF, 0x4F1, 0x4F3, 0x4F5, 0x4F7, 0x4F9, 0x4FB,
|
||||
0x4FD, 0x4FF, 0x501, 0x503, 0x505, 0x507, 0x509, 0x50B,
|
||||
0x50D, 0x50F, 0x511, 0x513, 0x515, 0x517, 0x519, 0x51B,
|
||||
0x51D, 0x51F, 0x521, 0x523, 0x525, 0x527, 0x529, 0x52B,
|
||||
0x52D, 0x52F, 0x560, 0x561, 0x562, 0x563, 0x564, 0x565,
|
||||
0x566, 0x567, 0x568, 0x569, 0x56A, 0x56B, 0x56C, 0x56D,
|
||||
0x56E, 0x56F, 0x570, 0x571, 0x572, 0x573, 0x574, 0x575,
|
||||
0x576, 0x577, 0x578, 0x579, 0x57A, 0x57B, 0x57C, 0x57D,
|
||||
0x57E, 0x57F, 0x580, 0x581, 0x582, 0x583, 0x584, 0x585,
|
||||
0x586, 0x587, 0x588, 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4,
|
||||
0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC,
|
||||
0x10DD, 0x10DE, 0x10DF, 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4,
|
||||
0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC,
|
||||
0x10ED, 0x10EE, 0x10EF, 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4,
|
||||
0x10F5, 0x10F6, 0x10F7, 0x10F8, 0x10F9, 0x10FA, 0x10FD, 0x10FE,
|
||||
0x10FF, 0x13F8, 0x13F9, 0x13FA, 0x13FB, 0x13FC, 0x13FD, 0x1C80,
|
||||
0x1C81, 0x1C82, 0x1C83, 0x1C84, 0x1C85, 0x1C86, 0x1C87, 0x1C88,
|
||||
0x1D00, 0x1D01, 0x1D02, 0x1D03, 0x1D04, 0x1D05, 0x1D06, 0x1D07,
|
||||
0x1D08, 0x1D09, 0x1D0A, 0x1D0B, 0x1D0C, 0x1D0D, 0x1D0E, 0x1D0F,
|
||||
0x1D10, 0x1D11, 0x1D12, 0x1D13, 0x1D14, 0x1D15, 0x1D16, 0x1D17,
|
||||
0x1D18, 0x1D19, 0x1D1A, 0x1D1B, 0x1D1C, 0x1D1D, 0x1D1E, 0x1D1F,
|
||||
0x1D20, 0x1D21, 0x1D22, 0x1D23, 0x1D24, 0x1D25, 0x1D26, 0x1D27,
|
||||
0x1D28, 0x1D29, 0x1D2A, 0x1D2B, 0x1D6B, 0x1D6C, 0x1D6D, 0x1D6E,
|
||||
0x1D6F, 0x1D70, 0x1D71, 0x1D72, 0x1D73, 0x1D74, 0x1D75, 0x1D76,
|
||||
0x1D77, 0x1D79, 0x1D7A, 0x1D7B, 0x1D7C, 0x1D7D, 0x1D7E, 0x1D7F,
|
||||
0x1D80, 0x1D81, 0x1D82, 0x1D83, 0x1D84, 0x1D85, 0x1D86, 0x1D87,
|
||||
0x1D88, 0x1D89, 0x1D8A, 0x1D8B, 0x1D8C, 0x1D8D, 0x1D8E, 0x1D8F,
|
||||
0x1D90, 0x1D91, 0x1D92, 0x1D93, 0x1D94, 0x1D95, 0x1D96, 0x1D97,
|
||||
0x1D98, 0x1D99, 0x1D9A, 0x1E01, 0x1E03, 0x1E05, 0x1E07, 0x1E09,
|
||||
0x1E0B, 0x1E0D, 0x1E0F, 0x1E11, 0x1E13, 0x1E15, 0x1E17, 0x1E19,
|
||||
0x1E1B, 0x1E1D, 0x1E1F, 0x1E21, 0x1E23, 0x1E25, 0x1E27, 0x1E29,
|
||||
0x1E2B, 0x1E2D, 0x1E2F, 0x1E31, 0x1E33, 0x1E35, 0x1E37, 0x1E39,
|
||||
0x1E3B, 0x1E3D, 0x1E3F, 0x1E41, 0x1E43, 0x1E45, 0x1E47, 0x1E49,
|
||||
0x1E4B, 0x1E4D, 0x1E4F, 0x1E51, 0x1E53, 0x1E55, 0x1E57, 0x1E59,
|
||||
0x1E5B, 0x1E5D, 0x1E5F, 0x1E61, 0x1E63, 0x1E65, 0x1E67, 0x1E69,
|
||||
0x1E6B, 0x1E6D, 0x1E6F, 0x1E71, 0x1E73, 0x1E75, 0x1E77, 0x1E79,
|
||||
0x1E7B, 0x1E7D, 0x1E7F, 0x1E81, 0x1E83, 0x1E85, 0x1E87, 0x1E89,
|
||||
0x1E8B, 0x1E8D, 0x1E8F, 0x1E91, 0x1E93, 0x1E95, 0x1E96, 0x1E97,
|
||||
0x1E98, 0x1E99, 0x1E9A, 0x1E9B, 0x1E9C, 0x1E9D, 0x1E9F, 0x1EA1,
|
||||
0x1EA3, 0x1EA5, 0x1EA7, 0x1EA9, 0x1EAB, 0x1EAD, 0x1EAF, 0x1EB1,
|
||||
0x1EB3, 0x1EB5, 0x1EB7, 0x1EB9, 0x1EBB, 0x1EBD, 0x1EBF, 0x1EC1,
|
||||
0x1EC3, 0x1EC5, 0x1EC7, 0x1EC9, 0x1ECB, 0x1ECD, 0x1ECF, 0x1ED1,
|
||||
0x1ED3, 0x1ED5, 0x1ED7, 0x1ED9, 0x1EDB, 0x1EDD, 0x1EDF, 0x1EE1,
|
||||
0x1EE3, 0x1EE5, 0x1EE7, 0x1EE9, 0x1EEB, 0x1EED, 0x1EEF, 0x1EF1,
|
||||
0x1EF3, 0x1EF5, 0x1EF7, 0x1EF9, 0x1EFB, 0x1EFD, 0x1EFF, 0x1F00,
|
||||
0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07, 0x1F10,
|
||||
0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x1F20, 0x1F21, 0x1F22,
|
||||
0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27, 0x1F30, 0x1F31, 0x1F32,
|
||||
0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37, 0x1F40, 0x1F41, 0x1F42,
|
||||
0x1F43, 0x1F44, 0x1F45, 0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54,
|
||||
0x1F55, 0x1F56, 0x1F57, 0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64,
|
||||
0x1F65, 0x1F66, 0x1F67, 0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74,
|
||||
0x1F75, 0x1F76, 0x1F77, 0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C,
|
||||
0x1F7D, 0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86,
|
||||
0x1F87, 0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96,
|
||||
0x1F97, 0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6,
|
||||
0x1FA7, 0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, 0x1FB6, 0x1FB7,
|
||||
0x1FBE, 0x1FC2, 0x1FC3, 0x1FC4, 0x1FC6, 0x1FC7, 0x1FD0, 0x1FD1,
|
||||
0x1FD2, 0x1FD3, 0x1FD6, 0x1FD7, 0x1FE0, 0x1FE1, 0x1FE2, 0x1FE3,
|
||||
0x1FE4, 0x1FE5, 0x1FE6, 0x1FE7, 0x1FF2, 0x1FF3, 0x1FF4, 0x1FF6,
|
||||
0x1FF7, 0x210A, 0x210E, 0x210F, 0x2113, 0x212F, 0x2134, 0x2139,
|
||||
0x213C, 0x213D, 0x2146, 0x2147, 0x2148, 0x2149, 0x214E, 0x2184,
|
||||
0x2C30, 0x2C31, 0x2C32, 0x2C33, 0x2C34, 0x2C35, 0x2C36, 0x2C37,
|
||||
0x2C38, 0x2C39, 0x2C3A, 0x2C3B, 0x2C3C, 0x2C3D, 0x2C3E, 0x2C3F,
|
||||
0x2C40, 0x2C41, 0x2C42, 0x2C43, 0x2C44, 0x2C45, 0x2C46, 0x2C47,
|
||||
0x2C48, 0x2C49, 0x2C4A, 0x2C4B, 0x2C4C, 0x2C4D, 0x2C4E, 0x2C4F,
|
||||
0x2C50, 0x2C51, 0x2C52, 0x2C53, 0x2C54, 0x2C55, 0x2C56, 0x2C57,
|
||||
0x2C58, 0x2C59, 0x2C5A, 0x2C5B, 0x2C5C, 0x2C5D, 0x2C5E, 0x2C5F,
|
||||
0x2C61, 0x2C65, 0x2C66, 0x2C68, 0x2C6A, 0x2C6C, 0x2C71, 0x2C73,
|
||||
0x2C74, 0x2C76, 0x2C77, 0x2C78, 0x2C79, 0x2C7A, 0x2C7B, 0x2C81,
|
||||
0x2C83, 0x2C85, 0x2C87, 0x2C89, 0x2C8B, 0x2C8D, 0x2C8F, 0x2C91,
|
||||
0x2C93, 0x2C95, 0x2C97, 0x2C99, 0x2C9B, 0x2C9D, 0x2C9F, 0x2CA1,
|
||||
0x2CA3, 0x2CA5, 0x2CA7, 0x2CA9, 0x2CAB, 0x2CAD, 0x2CAF, 0x2CB1,
|
||||
0x2CB3, 0x2CB5, 0x2CB7, 0x2CB9, 0x2CBB, 0x2CBD, 0x2CBF, 0x2CC1,
|
||||
0x2CC3, 0x2CC5, 0x2CC7, 0x2CC9, 0x2CCB, 0x2CCD, 0x2CCF, 0x2CD1,
|
||||
0x2CD3, 0x2CD5, 0x2CD7, 0x2CD9, 0x2CDB, 0x2CDD, 0x2CDF, 0x2CE1,
|
||||
0x2CE3, 0x2CE4, 0x2CEC, 0x2CEE, 0x2CF3, 0x2D00, 0x2D01, 0x2D02,
|
||||
0x2D03, 0x2D04, 0x2D05, 0x2D06, 0x2D07, 0x2D08, 0x2D09, 0x2D0A,
|
||||
0x2D0B, 0x2D0C, 0x2D0D, 0x2D0E, 0x2D0F, 0x2D10, 0x2D11, 0x2D12,
|
||||
0x2D13, 0x2D14, 0x2D15, 0x2D16, 0x2D17, 0x2D18, 0x2D19, 0x2D1A,
|
||||
0x2D1B, 0x2D1C, 0x2D1D, 0x2D1E, 0x2D1F, 0x2D20, 0x2D21, 0x2D22,
|
||||
0x2D23, 0x2D24, 0x2D25, 0x2D27, 0x2D2D, 0xA641, 0xA643, 0xA645,
|
||||
0xA647, 0xA649, 0xA64B, 0xA64D, 0xA64F, 0xA651, 0xA653, 0xA655,
|
||||
0xA657, 0xA659, 0xA65B, 0xA65D, 0xA65F, 0xA661, 0xA663, 0xA665,
|
||||
0xA667, 0xA669, 0xA66B, 0xA66D, 0xA681, 0xA683, 0xA685, 0xA687,
|
||||
0xA689, 0xA68B, 0xA68D, 0xA68F, 0xA691, 0xA693, 0xA695, 0xA697,
|
||||
0xA699, 0xA69B, 0xA723, 0xA725, 0xA727, 0xA729, 0xA72B, 0xA72D,
|
||||
0xA72F, 0xA730, 0xA731, 0xA733, 0xA735, 0xA737, 0xA739, 0xA73B,
|
||||
0xA73D, 0xA73F, 0xA741, 0xA743, 0xA745, 0xA747, 0xA749, 0xA74B,
|
||||
0xA74D, 0xA74F, 0xA751, 0xA753, 0xA755, 0xA757, 0xA759, 0xA75B,
|
||||
0xA75D, 0xA75F, 0xA761, 0xA763, 0xA765, 0xA767, 0xA769, 0xA76B,
|
||||
0xA76D, 0xA76F, 0xA771, 0xA772, 0xA773, 0xA774, 0xA775, 0xA776,
|
||||
0xA777, 0xA778, 0xA77A, 0xA77C, 0xA77F, 0xA781, 0xA783, 0xA785,
|
||||
0xA787, 0xA78C, 0xA78E, 0xA791, 0xA793, 0xA794, 0xA795, 0xA797,
|
||||
0xA799, 0xA79B, 0xA79D, 0xA79F, 0xA7A1, 0xA7A3, 0xA7A5, 0xA7A7,
|
||||
0xA7A9, 0xA7AF, 0xA7B5, 0xA7B7, 0xA7B9, 0xA7BB, 0xA7BD, 0xA7BF,
|
||||
0xA7C1, 0xA7C3, 0xA7C8, 0xA7CA, 0xA7D1, 0xA7D3, 0xA7D5, 0xA7D7,
|
||||
0xA7D9, 0xA7F6, 0xA7FA, 0xAB30, 0xAB31, 0xAB32, 0xAB33, 0xAB34,
|
||||
0xAB35, 0xAB36, 0xAB37, 0xAB38, 0xAB39, 0xAB3A, 0xAB3B, 0xAB3C,
|
||||
0xAB3D, 0xAB3E, 0xAB3F, 0xAB40, 0xAB41, 0xAB42, 0xAB43, 0xAB44,
|
||||
0xAB45, 0xAB46, 0xAB47, 0xAB48, 0xAB49, 0xAB4A, 0xAB4B, 0xAB4C,
|
||||
0xAB4D, 0xAB4E, 0xAB4F, 0xAB50, 0xAB51, 0xAB52, 0xAB53, 0xAB54,
|
||||
0xAB55, 0xAB56, 0xAB57, 0xAB58, 0xAB59, 0xAB5A, 0xAB60, 0xAB61,
|
||||
0xAB62, 0xAB63, 0xAB64, 0xAB65, 0xAB66, 0xAB67, 0xAB68, 0xAB70,
|
||||
0xAB71, 0xAB72, 0xAB73, 0xAB74, 0xAB75, 0xAB76, 0xAB77, 0xAB78,
|
||||
0xAB79, 0xAB7A, 0xAB7B, 0xAB7C, 0xAB7D, 0xAB7E, 0xAB7F, 0xAB80,
|
||||
0xAB81, 0xAB82, 0xAB83, 0xAB84, 0xAB85, 0xAB86, 0xAB87, 0xAB88,
|
||||
0xAB89, 0xAB8A, 0xAB8B, 0xAB8C, 0xAB8D, 0xAB8E, 0xAB8F, 0xAB90,
|
||||
0xAB91, 0xAB92, 0xAB93, 0xAB94, 0xAB95, 0xAB96, 0xAB97, 0xAB98,
|
||||
0xAB99, 0xAB9A, 0xAB9B, 0xAB9C, 0xAB9D, 0xAB9E, 0xAB9F, 0xABA0,
|
||||
0xABA1, 0xABA2, 0xABA3, 0xABA4, 0xABA5, 0xABA6, 0xABA7, 0xABA8,
|
||||
0xABA9, 0xABAA, 0xABAB, 0xABAC, 0xABAD, 0xABAE, 0xABAF, 0xABB0,
|
||||
0xABB1, 0xABB2, 0xABB3, 0xABB4, 0xABB5, 0xABB6, 0xABB7, 0xABB8,
|
||||
0xABB9, 0xABBA, 0xABBB, 0xABBC, 0xABBD, 0xABBE, 0xABBF, 0xFB00,
|
||||
0xFB01, 0xFB02, 0xFB03, 0xFB04, 0xFB05, 0xFB06, 0xFB13, 0xFB14,
|
||||
0xFB15, 0xFB16, 0xFB17, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45,
|
||||
0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D,
|
||||
0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55,
|
||||
0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0x10428, 0x10429, 0x1042A,
|
||||
0x1042B, 0x1042C, 0x1042D, 0x1042E, 0x1042F, 0x10430, 0x10431, 0x10432,
|
||||
0x10433, 0x10434, 0x10435, 0x10436, 0x10437, 0x10438, 0x10439, 0x1043A,
|
||||
0x1043B, 0x1043C, 0x1043D, 0x1043E, 0x1043F, 0x10440, 0x10441, 0x10442,
|
||||
0x10443, 0x10444, 0x10445, 0x10446, 0x10447, 0x10448, 0x10449, 0x1044A,
|
||||
0x1044B, 0x1044C, 0x1044D, 0x1044E, 0x1044F, 0x104D8, 0x104D9, 0x104DA,
|
||||
0x104DB, 0x104DC, 0x104DD, 0x104DE, 0x104DF, 0x104E0, 0x104E1, 0x104E2,
|
||||
0x104E3, 0x104E4, 0x104E5, 0x104E6, 0x104E7, 0x104E8, 0x104E9, 0x104EA,
|
||||
0x104EB, 0x104EC, 0x104ED, 0x104EE, 0x104EF, 0x104F0, 0x104F1, 0x104F2,
|
||||
0x104F3, 0x104F4, 0x104F5, 0x104F6, 0x104F7, 0x104F8, 0x104F9, 0x104FA,
|
||||
0x104FB, 0x10597, 0x10598, 0x10599, 0x1059A, 0x1059B, 0x1059C, 0x1059D,
|
||||
0x1059E, 0x1059F, 0x105A0, 0x105A1, 0x105A3, 0x105A4, 0x105A5, 0x105A6,
|
||||
0x105A7, 0x105A8, 0x105A9, 0x105AA, 0x105AB, 0x105AC, 0x105AD, 0x105AE,
|
||||
0x105AF, 0x105B0, 0x105B1, 0x105B3, 0x105B4, 0x105B5, 0x105B6, 0x105B7,
|
||||
0x105B8, 0x105B9, 0x105BB, 0x105BC, 0x10CC0, 0x10CC1, 0x10CC2, 0x10CC3,
|
||||
0x10CC4, 0x10CC5, 0x10CC6, 0x10CC7, 0x10CC8, 0x10CC9, 0x10CCA, 0x10CCB,
|
||||
0x10CCC, 0x10CCD, 0x10CCE, 0x10CCF, 0x10CD0, 0x10CD1, 0x10CD2, 0x10CD3,
|
||||
0x10CD4, 0x10CD5, 0x10CD6, 0x10CD7, 0x10CD8, 0x10CD9, 0x10CDA, 0x10CDB,
|
||||
0x10CDC, 0x10CDD, 0x10CDE, 0x10CDF, 0x10CE0, 0x10CE1, 0x10CE2, 0x10CE3,
|
||||
0x10CE4, 0x10CE5, 0x10CE6, 0x10CE7, 0x10CE8, 0x10CE9, 0x10CEA, 0x10CEB,
|
||||
0x10CEC, 0x10CED, 0x10CEE, 0x10CEF, 0x10CF0, 0x10CF1, 0x10CF2, 0x118C0,
|
||||
0x118C1, 0x118C2, 0x118C3, 0x118C4, 0x118C5, 0x118C6, 0x118C7, 0x118C8,
|
||||
0x118C9, 0x118CA, 0x118CB, 0x118CC, 0x118CD, 0x118CE, 0x118CF, 0x118D0,
|
||||
0x118D1, 0x118D2, 0x118D3, 0x118D4, 0x118D5, 0x118D6, 0x118D7, 0x118D8,
|
||||
0x118D9, 0x118DA, 0x118DB, 0x118DC, 0x118DD, 0x118DE, 0x118DF, 0x16E60,
|
||||
0x16E61, 0x16E62, 0x16E63, 0x16E64, 0x16E65, 0x16E66, 0x16E67, 0x16E68,
|
||||
0x16E69, 0x16E6A, 0x16E6B, 0x16E6C, 0x16E6D, 0x16E6E, 0x16E6F, 0x16E70,
|
||||
0x16E71, 0x16E72, 0x16E73, 0x16E74, 0x16E75, 0x16E76, 0x16E77, 0x16E78,
|
||||
0x16E79, 0x16E7A, 0x16E7B, 0x16E7C, 0x16E7D, 0x16E7E, 0x16E7F, 0x1D41A,
|
||||
0x1D41B, 0x1D41C, 0x1D41D, 0x1D41E, 0x1D41F, 0x1D420, 0x1D421, 0x1D422,
|
||||
0x1D423, 0x1D424, 0x1D425, 0x1D426, 0x1D427, 0x1D428, 0x1D429, 0x1D42A,
|
||||
0x1D42B, 0x1D42C, 0x1D42D, 0x1D42E, 0x1D42F, 0x1D430, 0x1D431, 0x1D432,
|
||||
0x1D433, 0x1D44E, 0x1D44F, 0x1D450, 0x1D451, 0x1D452, 0x1D453, 0x1D454,
|
||||
0x1D456, 0x1D457, 0x1D458, 0x1D459, 0x1D45A, 0x1D45B, 0x1D45C, 0x1D45D,
|
||||
0x1D45E, 0x1D45F, 0x1D460, 0x1D461, 0x1D462, 0x1D463, 0x1D464, 0x1D465,
|
||||
0x1D466, 0x1D467, 0x1D482, 0x1D483, 0x1D484, 0x1D485, 0x1D486, 0x1D487,
|
||||
0x1D488, 0x1D489, 0x1D48A, 0x1D48B, 0x1D48C, 0x1D48D, 0x1D48E, 0x1D48F,
|
||||
0x1D490, 0x1D491, 0x1D492, 0x1D493, 0x1D494, 0x1D495, 0x1D496, 0x1D497,
|
||||
0x1D498, 0x1D499, 0x1D49A, 0x1D49B, 0x1D4B6, 0x1D4B7, 0x1D4B8, 0x1D4B9,
|
||||
0x1D4BB, 0x1D4BD, 0x1D4BE, 0x1D4BF, 0x1D4C0, 0x1D4C1, 0x1D4C2, 0x1D4C3,
|
||||
0x1D4C5, 0x1D4C6, 0x1D4C7, 0x1D4C8, 0x1D4C9, 0x1D4CA, 0x1D4CB, 0x1D4CC,
|
||||
0x1D4CD, 0x1D4CE, 0x1D4CF, 0x1D4EA, 0x1D4EB, 0x1D4EC, 0x1D4ED, 0x1D4EE,
|
||||
0x1D4EF, 0x1D4F0, 0x1D4F1, 0x1D4F2, 0x1D4F3, 0x1D4F4, 0x1D4F5, 0x1D4F6,
|
||||
0x1D4F7, 0x1D4F8, 0x1D4F9, 0x1D4FA, 0x1D4FB, 0x1D4FC, 0x1D4FD, 0x1D4FE,
|
||||
0x1D4FF, 0x1D500, 0x1D501, 0x1D502, 0x1D503, 0x1D51E, 0x1D51F, 0x1D520,
|
||||
0x1D521, 0x1D522, 0x1D523, 0x1D524, 0x1D525, 0x1D526, 0x1D527, 0x1D528,
|
||||
0x1D529, 0x1D52A, 0x1D52B, 0x1D52C, 0x1D52D, 0x1D52E, 0x1D52F, 0x1D530,
|
||||
0x1D531, 0x1D532, 0x1D533, 0x1D534, 0x1D535, 0x1D536, 0x1D537, 0x1D552,
|
||||
0x1D553, 0x1D554, 0x1D555, 0x1D556, 0x1D557, 0x1D558, 0x1D559, 0x1D55A,
|
||||
0x1D55B, 0x1D55C, 0x1D55D, 0x1D55E, 0x1D55F, 0x1D560, 0x1D561, 0x1D562,
|
||||
0x1D563, 0x1D564, 0x1D565, 0x1D566, 0x1D567, 0x1D568, 0x1D569, 0x1D56A,
|
||||
0x1D56B, 0x1D586, 0x1D587, 0x1D588, 0x1D589, 0x1D58A, 0x1D58B, 0x1D58C,
|
||||
0x1D58D, 0x1D58E, 0x1D58F, 0x1D590, 0x1D591, 0x1D592, 0x1D593, 0x1D594,
|
||||
0x1D595, 0x1D596, 0x1D597, 0x1D598, 0x1D599, 0x1D59A, 0x1D59B, 0x1D59C,
|
||||
0x1D59D, 0x1D59E, 0x1D59F, 0x1D5BA, 0x1D5BB, 0x1D5BC, 0x1D5BD, 0x1D5BE,
|
||||
0x1D5BF, 0x1D5C0, 0x1D5C1, 0x1D5C2, 0x1D5C3, 0x1D5C4, 0x1D5C5, 0x1D5C6,
|
||||
0x1D5C7, 0x1D5C8, 0x1D5C9, 0x1D5CA, 0x1D5CB, 0x1D5CC, 0x1D5CD, 0x1D5CE,
|
||||
0x1D5CF, 0x1D5D0, 0x1D5D1, 0x1D5D2, 0x1D5D3, 0x1D5EE, 0x1D5EF, 0x1D5F0,
|
||||
0x1D5F1, 0x1D5F2, 0x1D5F3, 0x1D5F4, 0x1D5F5, 0x1D5F6, 0x1D5F7, 0x1D5F8,
|
||||
0x1D5F9, 0x1D5FA, 0x1D5FB, 0x1D5FC, 0x1D5FD, 0x1D5FE, 0x1D5FF, 0x1D600,
|
||||
0x1D601, 0x1D602, 0x1D603, 0x1D604, 0x1D605, 0x1D606, 0x1D607, 0x1D622,
|
||||
0x1D623, 0x1D624, 0x1D625, 0x1D626, 0x1D627, 0x1D628, 0x1D629, 0x1D62A,
|
||||
0x1D62B, 0x1D62C, 0x1D62D, 0x1D62E, 0x1D62F, 0x1D630, 0x1D631, 0x1D632,
|
||||
0x1D633, 0x1D634, 0x1D635, 0x1D636, 0x1D637, 0x1D638, 0x1D639, 0x1D63A,
|
||||
0x1D63B, 0x1D656, 0x1D657, 0x1D658, 0x1D659, 0x1D65A, 0x1D65B, 0x1D65C,
|
||||
0x1D65D, 0x1D65E, 0x1D65F, 0x1D660, 0x1D661, 0x1D662, 0x1D663, 0x1D664,
|
||||
0x1D665, 0x1D666, 0x1D667, 0x1D668, 0x1D669, 0x1D66A, 0x1D66B, 0x1D66C,
|
||||
0x1D66D, 0x1D66E, 0x1D66F, 0x1D68A, 0x1D68B, 0x1D68C, 0x1D68D, 0x1D68E,
|
||||
0x1D68F, 0x1D690, 0x1D691, 0x1D692, 0x1D693, 0x1D694, 0x1D695, 0x1D696,
|
||||
0x1D697, 0x1D698, 0x1D699, 0x1D69A, 0x1D69B, 0x1D69C, 0x1D69D, 0x1D69E,
|
||||
0x1D69F, 0x1D6A0, 0x1D6A1, 0x1D6A2, 0x1D6A3, 0x1D6A4, 0x1D6A5, 0x1D6C2,
|
||||
0x1D6C3, 0x1D6C4, 0x1D6C5, 0x1D6C6, 0x1D6C7, 0x1D6C8, 0x1D6C9, 0x1D6CA,
|
||||
0x1D6CB, 0x1D6CC, 0x1D6CD, 0x1D6CE, 0x1D6CF, 0x1D6D0, 0x1D6D1, 0x1D6D2,
|
||||
0x1D6D3, 0x1D6D4, 0x1D6D5, 0x1D6D6, 0x1D6D7, 0x1D6D8, 0x1D6D9, 0x1D6DA,
|
||||
0x1D6DC, 0x1D6DD, 0x1D6DE, 0x1D6DF, 0x1D6E0, 0x1D6E1, 0x1D6FC, 0x1D6FD,
|
||||
0x1D6FE, 0x1D6FF, 0x1D700, 0x1D701, 0x1D702, 0x1D703, 0x1D704, 0x1D705,
|
||||
0x1D706, 0x1D707, 0x1D708, 0x1D709, 0x1D70A, 0x1D70B, 0x1D70C, 0x1D70D,
|
||||
0x1D70E, 0x1D70F, 0x1D710, 0x1D711, 0x1D712, 0x1D713, 0x1D714, 0x1D716,
|
||||
0x1D717, 0x1D718, 0x1D719, 0x1D71A, 0x1D71B, 0x1D736, 0x1D737, 0x1D738,
|
||||
0x1D739, 0x1D73A, 0x1D73B, 0x1D73C, 0x1D73D, 0x1D73E, 0x1D73F, 0x1D740,
|
||||
0x1D741, 0x1D742, 0x1D743, 0x1D744, 0x1D745, 0x1D746, 0x1D747, 0x1D748,
|
||||
0x1D749, 0x1D74A, 0x1D74B, 0x1D74C, 0x1D74D, 0x1D74E, 0x1D750, 0x1D751,
|
||||
0x1D752, 0x1D753, 0x1D754, 0x1D755, 0x1D770, 0x1D771, 0x1D772, 0x1D773,
|
||||
0x1D774, 0x1D775, 0x1D776, 0x1D777, 0x1D778, 0x1D779, 0x1D77A, 0x1D77B,
|
||||
0x1D77C, 0x1D77D, 0x1D77E, 0x1D77F, 0x1D780, 0x1D781, 0x1D782, 0x1D783,
|
||||
0x1D784, 0x1D785, 0x1D786, 0x1D787, 0x1D788, 0x1D78A, 0x1D78B, 0x1D78C,
|
||||
0x1D78D, 0x1D78E, 0x1D78F, 0x1D7AA, 0x1D7AB, 0x1D7AC, 0x1D7AD, 0x1D7AE,
|
||||
0x1D7AF, 0x1D7B0, 0x1D7B1, 0x1D7B2, 0x1D7B3, 0x1D7B4, 0x1D7B5, 0x1D7B6,
|
||||
0x1D7B7, 0x1D7B8, 0x1D7B9, 0x1D7BA, 0x1D7BB, 0x1D7BC, 0x1D7BD, 0x1D7BE,
|
||||
0x1D7BF, 0x1D7C0, 0x1D7C1, 0x1D7C2, 0x1D7C4, 0x1D7C5, 0x1D7C6, 0x1D7C7,
|
||||
0x1D7C8, 0x1D7C9, 0x1D7CB, 0x1DF00, 0x1DF01, 0x1DF02, 0x1DF03, 0x1DF04,
|
||||
0x1DF05, 0x1DF06, 0x1DF07, 0x1DF08, 0x1DF09, 0x1DF0B, 0x1DF0C, 0x1DF0D,
|
||||
0x1DF0E, 0x1DF0F, 0x1DF10, 0x1DF11, 0x1DF12, 0x1DF13, 0x1DF14, 0x1DF15,
|
||||
0x1DF16, 0x1DF17, 0x1DF18, 0x1DF19, 0x1DF1A, 0x1DF1B, 0x1DF1C, 0x1DF1D,
|
||||
0x1DF1E, 0x1DF25, 0x1DF26, 0x1DF27, 0x1DF28, 0x1DF29, 0x1DF2A, 0x1E922,
|
||||
0x1E923, 0x1E924, 0x1E925, 0x1E926, 0x1E927, 0x1E928, 0x1E929, 0x1E92A,
|
||||
0x1E92B, 0x1E92C, 0x1E92D, 0x1E92E, 0x1E92F, 0x1E930, 0x1E931, 0x1E932,
|
||||
0x1E933, 0x1E934, 0x1E935, 0x1E936, 0x1E937, 0x1E938, 0x1E939, 0x1E93A,
|
||||
0x1E93B, 0x1E93C, 0x1E93D, 0x1E93E, 0x1E93F, 0x1E940, 0x1E941, 0x1E942,
|
||||
0x1E943};
|
||||
};
|
||||
|
||||
// Produced from https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp,
|
||||
// using "[:Lu:]" for the Input field, using the categories found at
|
||||
// https://www.fileformat.info/info/unicode/category/index.htm
|
||||
template<>
|
||||
struct char_set<upper_case_chars>
|
||||
{
|
||||
static constexpr uint32_t chars[] = {
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E,
|
||||
0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
|
||||
0x56, 0x57, 0x58, 0x59, 0x5A, 0xC0, 0xC1,
|
||||
0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
|
||||
0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
|
||||
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE,
|
||||
0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C,
|
||||
0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A,
|
||||
0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128,
|
||||
0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136,
|
||||
0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145,
|
||||
0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154,
|
||||
0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162,
|
||||
0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170,
|
||||
0x172, 0x174, 0x176, 0x178, 0x179, 0x17B, 0x17D,
|
||||
0x181, 0x182, 0x184, 0x186, 0x187, 0x189, 0x18A,
|
||||
0x18B, 0x18E, 0x18F, 0x190, 0x191, 0x193, 0x194,
|
||||
0x196, 0x197, 0x198, 0x19C, 0x19D, 0x19F, 0x1A0,
|
||||
0x1A2, 0x1A4, 0x1A6, 0x1A7, 0x1A9, 0x1AC, 0x1AE,
|
||||
0x1AF, 0x1B1, 0x1B2, 0x1B3, 0x1B5, 0x1B7, 0x1B8,
|
||||
0x1BC, 0x1C4, 0x1C7, 0x1CA, 0x1CD, 0x1CF, 0x1D1,
|
||||
0x1D3, 0x1D5, 0x1D7, 0x1D9, 0x1DB, 0x1DE, 0x1E0,
|
||||
0x1E2, 0x1E4, 0x1E6, 0x1E8, 0x1EA, 0x1EC, 0x1EE,
|
||||
0x1F1, 0x1F4, 0x1F6, 0x1F7, 0x1F8, 0x1FA, 0x1FC,
|
||||
0x1FE, 0x200, 0x202, 0x204, 0x206, 0x208, 0x20A,
|
||||
0x20C, 0x20E, 0x210, 0x212, 0x214, 0x216, 0x218,
|
||||
0x21A, 0x21C, 0x21E, 0x220, 0x222, 0x224, 0x226,
|
||||
0x228, 0x22A, 0x22C, 0x22E, 0x230, 0x232, 0x23A,
|
||||
0x23B, 0x23D, 0x23E, 0x241, 0x243, 0x244, 0x245,
|
||||
0x246, 0x248, 0x24A, 0x24C, 0x24E, 0x370, 0x372,
|
||||
0x376, 0x37F, 0x386, 0x388, 0x389, 0x38A, 0x38C,
|
||||
0x38E, 0x38F, 0x391, 0x392, 0x393, 0x394, 0x395,
|
||||
0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C,
|
||||
0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4,
|
||||
0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x3AB,
|
||||
0x3CF, 0x3D2, 0x3D3, 0x3D4, 0x3D8, 0x3DA, 0x3DC,
|
||||
0x3DE, 0x3E0, 0x3E2, 0x3E4, 0x3E6, 0x3E8, 0x3EA,
|
||||
0x3EC, 0x3EE, 0x3F4, 0x3F7, 0x3F9, 0x3FA, 0x3FD,
|
||||
0x3FE, 0x3FF, 0x400, 0x401, 0x402, 0x403, 0x404,
|
||||
0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B,
|
||||
0x40C, 0x40D, 0x40E, 0x40F, 0x410, 0x411, 0x412,
|
||||
0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419,
|
||||
0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420,
|
||||
0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427,
|
||||
0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E,
|
||||
0x42F, 0x460, 0x462, 0x464, 0x466, 0x468, 0x46A,
|
||||
0x46C, 0x46E, 0x470, 0x472, 0x474, 0x476, 0x478,
|
||||
0x47A, 0x47C, 0x47E, 0x480, 0x48A, 0x48C, 0x48E,
|
||||
0x490, 0x492, 0x494, 0x496, 0x498, 0x49A, 0x49C,
|
||||
0x49E, 0x4A0, 0x4A2, 0x4A4, 0x4A6, 0x4A8, 0x4AA,
|
||||
0x4AC, 0x4AE, 0x4B0, 0x4B2, 0x4B4, 0x4B6, 0x4B8,
|
||||
0x4BA, 0x4BC, 0x4BE, 0x4C0, 0x4C1, 0x4C3, 0x4C5,
|
||||
0x4C7, 0x4C9, 0x4CB, 0x4CD, 0x4D0, 0x4D2, 0x4D4,
|
||||
0x4D6, 0x4D8, 0x4DA, 0x4DC, 0x4DE, 0x4E0, 0x4E2,
|
||||
0x4E4, 0x4E6, 0x4E8, 0x4EA, 0x4EC, 0x4EE, 0x4F0,
|
||||
0x4F2, 0x4F4, 0x4F6, 0x4F8, 0x4FA, 0x4FC, 0x4FE,
|
||||
0x500, 0x502, 0x504, 0x506, 0x508, 0x50A, 0x50C,
|
||||
0x50E, 0x510, 0x512, 0x514, 0x516, 0x518, 0x51A,
|
||||
0x51C, 0x51E, 0x520, 0x522, 0x524, 0x526, 0x528,
|
||||
0x52A, 0x52C, 0x52E, 0x531, 0x532, 0x533, 0x534,
|
||||
0x535, 0x536, 0x537, 0x538, 0x539, 0x53A, 0x53B,
|
||||
0x53C, 0x53D, 0x53E, 0x53F, 0x540, 0x541, 0x542,
|
||||
0x543, 0x544, 0x545, 0x546, 0x547, 0x548, 0x549,
|
||||
0x54A, 0x54B, 0x54C, 0x54D, 0x54E, 0x54F, 0x550,
|
||||
0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0x10A0,
|
||||
0x10A1, 0x10A2, 0x10A3, 0x10A4, 0x10A5, 0x10A6, 0x10A7,
|
||||
0x10A8, 0x10A9, 0x10AA, 0x10AB, 0x10AC, 0x10AD, 0x10AE,
|
||||
0x10AF, 0x10B0, 0x10B1, 0x10B2, 0x10B3, 0x10B4, 0x10B5,
|
||||
0x10B6, 0x10B7, 0x10B8, 0x10B9, 0x10BA, 0x10BB, 0x10BC,
|
||||
0x10BD, 0x10BE, 0x10BF, 0x10C0, 0x10C1, 0x10C2, 0x10C3,
|
||||
0x10C4, 0x10C5, 0x10C7, 0x10CD, 0x13A0, 0x13A1, 0x13A2,
|
||||
0x13A3, 0x13A4, 0x13A5, 0x13A6, 0x13A7, 0x13A8, 0x13A9,
|
||||
0x13AA, 0x13AB, 0x13AC, 0x13AD, 0x13AE, 0x13AF, 0x13B0,
|
||||
0x13B1, 0x13B2, 0x13B3, 0x13B4, 0x13B5, 0x13B6, 0x13B7,
|
||||
0x13B8, 0x13B9, 0x13BA, 0x13BB, 0x13BC, 0x13BD, 0x13BE,
|
||||
0x13BF, 0x13C0, 0x13C1, 0x13C2, 0x13C3, 0x13C4, 0x13C5,
|
||||
0x13C6, 0x13C7, 0x13C8, 0x13C9, 0x13CA, 0x13CB, 0x13CC,
|
||||
0x13CD, 0x13CE, 0x13CF, 0x13D0, 0x13D1, 0x13D2, 0x13D3,
|
||||
0x13D4, 0x13D5, 0x13D6, 0x13D7, 0x13D8, 0x13D9, 0x13DA,
|
||||
0x13DB, 0x13DC, 0x13DD, 0x13DE, 0x13DF, 0x13E0, 0x13E1,
|
||||
0x13E2, 0x13E3, 0x13E4, 0x13E5, 0x13E6, 0x13E7, 0x13E8,
|
||||
0x13E9, 0x13EA, 0x13EB, 0x13EC, 0x13ED, 0x13EE, 0x13EF,
|
||||
0x13F0, 0x13F1, 0x13F2, 0x13F3, 0x13F4, 0x13F5, 0x1C90,
|
||||
0x1C91, 0x1C92, 0x1C93, 0x1C94, 0x1C95, 0x1C96, 0x1C97,
|
||||
0x1C98, 0x1C99, 0x1C9A, 0x1C9B, 0x1C9C, 0x1C9D, 0x1C9E,
|
||||
0x1C9F, 0x1CA0, 0x1CA1, 0x1CA2, 0x1CA3, 0x1CA4, 0x1CA5,
|
||||
0x1CA6, 0x1CA7, 0x1CA8, 0x1CA9, 0x1CAA, 0x1CAB, 0x1CAC,
|
||||
0x1CAD, 0x1CAE, 0x1CAF, 0x1CB0, 0x1CB1, 0x1CB2, 0x1CB3,
|
||||
0x1CB4, 0x1CB5, 0x1CB6, 0x1CB7, 0x1CB8, 0x1CB9, 0x1CBA,
|
||||
0x1CBD, 0x1CBE, 0x1CBF, 0x1E00, 0x1E02, 0x1E04, 0x1E06,
|
||||
0x1E08, 0x1E0A, 0x1E0C, 0x1E0E, 0x1E10, 0x1E12, 0x1E14,
|
||||
0x1E16, 0x1E18, 0x1E1A, 0x1E1C, 0x1E1E, 0x1E20, 0x1E22,
|
||||
0x1E24, 0x1E26, 0x1E28, 0x1E2A, 0x1E2C, 0x1E2E, 0x1E30,
|
||||
0x1E32, 0x1E34, 0x1E36, 0x1E38, 0x1E3A, 0x1E3C, 0x1E3E,
|
||||
0x1E40, 0x1E42, 0x1E44, 0x1E46, 0x1E48, 0x1E4A, 0x1E4C,
|
||||
0x1E4E, 0x1E50, 0x1E52, 0x1E54, 0x1E56, 0x1E58, 0x1E5A,
|
||||
0x1E5C, 0x1E5E, 0x1E60, 0x1E62, 0x1E64, 0x1E66, 0x1E68,
|
||||
0x1E6A, 0x1E6C, 0x1E6E, 0x1E70, 0x1E72, 0x1E74, 0x1E76,
|
||||
0x1E78, 0x1E7A, 0x1E7C, 0x1E7E, 0x1E80, 0x1E82, 0x1E84,
|
||||
0x1E86, 0x1E88, 0x1E8A, 0x1E8C, 0x1E8E, 0x1E90, 0x1E92,
|
||||
0x1E94, 0x1E9E, 0x1EA0, 0x1EA2, 0x1EA4, 0x1EA6, 0x1EA8,
|
||||
0x1EAA, 0x1EAC, 0x1EAE, 0x1EB0, 0x1EB2, 0x1EB4, 0x1EB6,
|
||||
0x1EB8, 0x1EBA, 0x1EBC, 0x1EBE, 0x1EC0, 0x1EC2, 0x1EC4,
|
||||
0x1EC6, 0x1EC8, 0x1ECA, 0x1ECC, 0x1ECE, 0x1ED0, 0x1ED2,
|
||||
0x1ED4, 0x1ED6, 0x1ED8, 0x1EDA, 0x1EDC, 0x1EDE, 0x1EE0,
|
||||
0x1EE2, 0x1EE4, 0x1EE6, 0x1EE8, 0x1EEA, 0x1EEC, 0x1EEE,
|
||||
0x1EF0, 0x1EF2, 0x1EF4, 0x1EF6, 0x1EF8, 0x1EFA, 0x1EFC,
|
||||
0x1EFE, 0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D,
|
||||
0x1F0E, 0x1F0F, 0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C,
|
||||
0x1F1D, 0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D,
|
||||
0x1F2E, 0x1F2F, 0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C,
|
||||
0x1F3D, 0x1F3E, 0x1F3F, 0x1F48, 0x1F49, 0x1F4A, 0x1F4B,
|
||||
0x1F4C, 0x1F4D, 0x1F59, 0x1F5B, 0x1F5D, 0x1F5F, 0x1F68,
|
||||
0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
|
||||
0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA,
|
||||
0x1FCB, 0x1FD8, 0x1FD9, 0x1FDA, 0x1FDB, 0x1FE8, 0x1FE9,
|
||||
0x1FEA, 0x1FEB, 0x1FEC, 0x1FF8, 0x1FF9, 0x1FFA, 0x1FFB,
|
||||
0x2102, 0x2107, 0x210B, 0x210C, 0x210D, 0x2110, 0x2111,
|
||||
0x2112, 0x2115, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D,
|
||||
0x2124, 0x2126, 0x2128, 0x212A, 0x212B, 0x212C, 0x212D,
|
||||
0x2130, 0x2131, 0x2132, 0x2133, 0x213E, 0x213F, 0x2145,
|
||||
0x2183, 0x2C00, 0x2C01, 0x2C02, 0x2C03, 0x2C04, 0x2C05,
|
||||
0x2C06, 0x2C07, 0x2C08, 0x2C09, 0x2C0A, 0x2C0B, 0x2C0C,
|
||||
0x2C0D, 0x2C0E, 0x2C0F, 0x2C10, 0x2C11, 0x2C12, 0x2C13,
|
||||
0x2C14, 0x2C15, 0x2C16, 0x2C17, 0x2C18, 0x2C19, 0x2C1A,
|
||||
0x2C1B, 0x2C1C, 0x2C1D, 0x2C1E, 0x2C1F, 0x2C20, 0x2C21,
|
||||
0x2C22, 0x2C23, 0x2C24, 0x2C25, 0x2C26, 0x2C27, 0x2C28,
|
||||
0x2C29, 0x2C2A, 0x2C2B, 0x2C2C, 0x2C2D, 0x2C2E, 0x2C2F,
|
||||
0x2C60, 0x2C62, 0x2C63, 0x2C64, 0x2C67, 0x2C69, 0x2C6B,
|
||||
0x2C6D, 0x2C6E, 0x2C6F, 0x2C70, 0x2C72, 0x2C75, 0x2C7E,
|
||||
0x2C7F, 0x2C80, 0x2C82, 0x2C84, 0x2C86, 0x2C88, 0x2C8A,
|
||||
0x2C8C, 0x2C8E, 0x2C90, 0x2C92, 0x2C94, 0x2C96, 0x2C98,
|
||||
0x2C9A, 0x2C9C, 0x2C9E, 0x2CA0, 0x2CA2, 0x2CA4, 0x2CA6,
|
||||
0x2CA8, 0x2CAA, 0x2CAC, 0x2CAE, 0x2CB0, 0x2CB2, 0x2CB4,
|
||||
0x2CB6, 0x2CB8, 0x2CBA, 0x2CBC, 0x2CBE, 0x2CC0, 0x2CC2,
|
||||
0x2CC4, 0x2CC6, 0x2CC8, 0x2CCA, 0x2CCC, 0x2CCE, 0x2CD0,
|
||||
0x2CD2, 0x2CD4, 0x2CD6, 0x2CD8, 0x2CDA, 0x2CDC, 0x2CDE,
|
||||
0x2CE0, 0x2CE2, 0x2CEB, 0x2CED, 0x2CF2, 0xA640, 0xA642,
|
||||
0xA644, 0xA646, 0xA648, 0xA64A, 0xA64C, 0xA64E, 0xA650,
|
||||
0xA652, 0xA654, 0xA656, 0xA658, 0xA65A, 0xA65C, 0xA65E,
|
||||
0xA660, 0xA662, 0xA664, 0xA666, 0xA668, 0xA66A, 0xA66C,
|
||||
0xA680, 0xA682, 0xA684, 0xA686, 0xA688, 0xA68A, 0xA68C,
|
||||
0xA68E, 0xA690, 0xA692, 0xA694, 0xA696, 0xA698, 0xA69A,
|
||||
0xA722, 0xA724, 0xA726, 0xA728, 0xA72A, 0xA72C, 0xA72E,
|
||||
0xA732, 0xA734, 0xA736, 0xA738, 0xA73A, 0xA73C, 0xA73E,
|
||||
0xA740, 0xA742, 0xA744, 0xA746, 0xA748, 0xA74A, 0xA74C,
|
||||
0xA74E, 0xA750, 0xA752, 0xA754, 0xA756, 0xA758, 0xA75A,
|
||||
0xA75C, 0xA75E, 0xA760, 0xA762, 0xA764, 0xA766, 0xA768,
|
||||
0xA76A, 0xA76C, 0xA76E, 0xA779, 0xA77B, 0xA77D, 0xA77E,
|
||||
0xA780, 0xA782, 0xA784, 0xA786, 0xA78B, 0xA78D, 0xA790,
|
||||
0xA792, 0xA796, 0xA798, 0xA79A, 0xA79C, 0xA79E, 0xA7A0,
|
||||
0xA7A2, 0xA7A4, 0xA7A6, 0xA7A8, 0xA7AA, 0xA7AB, 0xA7AC,
|
||||
0xA7AD, 0xA7AE, 0xA7B0, 0xA7B1, 0xA7B2, 0xA7B3, 0xA7B4,
|
||||
0xA7B6, 0xA7B8, 0xA7BA, 0xA7BC, 0xA7BE, 0xA7C0, 0xA7C2,
|
||||
0xA7C4, 0xA7C5, 0xA7C6, 0xA7C7, 0xA7C9, 0xA7D0, 0xA7D6,
|
||||
0xA7D8, 0xA7F5, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25,
|
||||
0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C,
|
||||
0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33,
|
||||
0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A,
|
||||
0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406,
|
||||
0x10407, 0x10408, 0x10409, 0x1040A, 0x1040B, 0x1040C, 0x1040D,
|
||||
0x1040E, 0x1040F, 0x10410, 0x10411, 0x10412, 0x10413, 0x10414,
|
||||
0x10415, 0x10416, 0x10417, 0x10418, 0x10419, 0x1041A, 0x1041B,
|
||||
0x1041C, 0x1041D, 0x1041E, 0x1041F, 0x10420, 0x10421, 0x10422,
|
||||
0x10423, 0x10424, 0x10425, 0x10426, 0x10427, 0x104B0, 0x104B1,
|
||||
0x104B2, 0x104B3, 0x104B4, 0x104B5, 0x104B6, 0x104B7, 0x104B8,
|
||||
0x104B9, 0x104BA, 0x104BB, 0x104BC, 0x104BD, 0x104BE, 0x104BF,
|
||||
0x104C0, 0x104C1, 0x104C2, 0x104C3, 0x104C4, 0x104C5, 0x104C6,
|
||||
0x104C7, 0x104C8, 0x104C9, 0x104CA, 0x104CB, 0x104CC, 0x104CD,
|
||||
0x104CE, 0x104CF, 0x104D0, 0x104D1, 0x104D2, 0x104D3, 0x10570,
|
||||
0x10571, 0x10572, 0x10573, 0x10574, 0x10575, 0x10576, 0x10577,
|
||||
0x10578, 0x10579, 0x1057A, 0x1057C, 0x1057D, 0x1057E, 0x1057F,
|
||||
0x10580, 0x10581, 0x10582, 0x10583, 0x10584, 0x10585, 0x10586,
|
||||
0x10587, 0x10588, 0x10589, 0x1058A, 0x1058C, 0x1058D, 0x1058E,
|
||||
0x1058F, 0x10590, 0x10591, 0x10592, 0x10594, 0x10595, 0x10C80,
|
||||
0x10C81, 0x10C82, 0x10C83, 0x10C84, 0x10C85, 0x10C86, 0x10C87,
|
||||
0x10C88, 0x10C89, 0x10C8A, 0x10C8B, 0x10C8C, 0x10C8D, 0x10C8E,
|
||||
0x10C8F, 0x10C90, 0x10C91, 0x10C92, 0x10C93, 0x10C94, 0x10C95,
|
||||
0x10C96, 0x10C97, 0x10C98, 0x10C99, 0x10C9A, 0x10C9B, 0x10C9C,
|
||||
0x10C9D, 0x10C9E, 0x10C9F, 0x10CA0, 0x10CA1, 0x10CA2, 0x10CA3,
|
||||
0x10CA4, 0x10CA5, 0x10CA6, 0x10CA7, 0x10CA8, 0x10CA9, 0x10CAA,
|
||||
0x10CAB, 0x10CAC, 0x10CAD, 0x10CAE, 0x10CAF, 0x10CB0, 0x10CB1,
|
||||
0x10CB2, 0x118A0, 0x118A1, 0x118A2, 0x118A3, 0x118A4, 0x118A5,
|
||||
0x118A6, 0x118A7, 0x118A8, 0x118A9, 0x118AA, 0x118AB, 0x118AC,
|
||||
0x118AD, 0x118AE, 0x118AF, 0x118B0, 0x118B1, 0x118B2, 0x118B3,
|
||||
0x118B4, 0x118B5, 0x118B6, 0x118B7, 0x118B8, 0x118B9, 0x118BA,
|
||||
0x118BB, 0x118BC, 0x118BD, 0x118BE, 0x118BF, 0x16E40, 0x16E41,
|
||||
0x16E42, 0x16E43, 0x16E44, 0x16E45, 0x16E46, 0x16E47, 0x16E48,
|
||||
0x16E49, 0x16E4A, 0x16E4B, 0x16E4C, 0x16E4D, 0x16E4E, 0x16E4F,
|
||||
0x16E50, 0x16E51, 0x16E52, 0x16E53, 0x16E54, 0x16E55, 0x16E56,
|
||||
0x16E57, 0x16E58, 0x16E59, 0x16E5A, 0x16E5B, 0x16E5C, 0x16E5D,
|
||||
0x16E5E, 0x16E5F, 0x1D400, 0x1D401, 0x1D402, 0x1D403, 0x1D404,
|
||||
0x1D405, 0x1D406, 0x1D407, 0x1D408, 0x1D409, 0x1D40A, 0x1D40B,
|
||||
0x1D40C, 0x1D40D, 0x1D40E, 0x1D40F, 0x1D410, 0x1D411, 0x1D412,
|
||||
0x1D413, 0x1D414, 0x1D415, 0x1D416, 0x1D417, 0x1D418, 0x1D419,
|
||||
0x1D434, 0x1D435, 0x1D436, 0x1D437, 0x1D438, 0x1D439, 0x1D43A,
|
||||
0x1D43B, 0x1D43C, 0x1D43D, 0x1D43E, 0x1D43F, 0x1D440, 0x1D441,
|
||||
0x1D442, 0x1D443, 0x1D444, 0x1D445, 0x1D446, 0x1D447, 0x1D448,
|
||||
0x1D449, 0x1D44A, 0x1D44B, 0x1D44C, 0x1D44D, 0x1D468, 0x1D469,
|
||||
0x1D46A, 0x1D46B, 0x1D46C, 0x1D46D, 0x1D46E, 0x1D46F, 0x1D470,
|
||||
0x1D471, 0x1D472, 0x1D473, 0x1D474, 0x1D475, 0x1D476, 0x1D477,
|
||||
0x1D478, 0x1D479, 0x1D47A, 0x1D47B, 0x1D47C, 0x1D47D, 0x1D47E,
|
||||
0x1D47F, 0x1D480, 0x1D481, 0x1D49C, 0x1D49E, 0x1D49F, 0x1D4A2,
|
||||
0x1D4A5, 0x1D4A6, 0x1D4A9, 0x1D4AA, 0x1D4AB, 0x1D4AC, 0x1D4AE,
|
||||
0x1D4AF, 0x1D4B0, 0x1D4B1, 0x1D4B2, 0x1D4B3, 0x1D4B4, 0x1D4B5,
|
||||
0x1D4D0, 0x1D4D1, 0x1D4D2, 0x1D4D3, 0x1D4D4, 0x1D4D5, 0x1D4D6,
|
||||
0x1D4D7, 0x1D4D8, 0x1D4D9, 0x1D4DA, 0x1D4DB, 0x1D4DC, 0x1D4DD,
|
||||
0x1D4DE, 0x1D4DF, 0x1D4E0, 0x1D4E1, 0x1D4E2, 0x1D4E3, 0x1D4E4,
|
||||
0x1D4E5, 0x1D4E6, 0x1D4E7, 0x1D4E8, 0x1D4E9, 0x1D504, 0x1D505,
|
||||
0x1D507, 0x1D508, 0x1D509, 0x1D50A, 0x1D50D, 0x1D50E, 0x1D50F,
|
||||
0x1D510, 0x1D511, 0x1D512, 0x1D513, 0x1D514, 0x1D516, 0x1D517,
|
||||
0x1D518, 0x1D519, 0x1D51A, 0x1D51B, 0x1D51C, 0x1D538, 0x1D539,
|
||||
0x1D53B, 0x1D53C, 0x1D53D, 0x1D53E, 0x1D540, 0x1D541, 0x1D542,
|
||||
0x1D543, 0x1D544, 0x1D546, 0x1D54A, 0x1D54B, 0x1D54C, 0x1D54D,
|
||||
0x1D54E, 0x1D54F, 0x1D550, 0x1D56C, 0x1D56D, 0x1D56E, 0x1D56F,
|
||||
0x1D570, 0x1D571, 0x1D572, 0x1D573, 0x1D574, 0x1D575, 0x1D576,
|
||||
0x1D577, 0x1D578, 0x1D579, 0x1D57A, 0x1D57B, 0x1D57C, 0x1D57D,
|
||||
0x1D57E, 0x1D57F, 0x1D580, 0x1D581, 0x1D582, 0x1D583, 0x1D584,
|
||||
0x1D585, 0x1D5A0, 0x1D5A1, 0x1D5A2, 0x1D5A3, 0x1D5A4, 0x1D5A5,
|
||||
0x1D5A6, 0x1D5A7, 0x1D5A8, 0x1D5A9, 0x1D5AA, 0x1D5AB, 0x1D5AC,
|
||||
0x1D5AD, 0x1D5AE, 0x1D5AF, 0x1D5B0, 0x1D5B1, 0x1D5B2, 0x1D5B3,
|
||||
0x1D5B4, 0x1D5B5, 0x1D5B6, 0x1D5B7, 0x1D5B8, 0x1D5B9, 0x1D5D4,
|
||||
0x1D5D5, 0x1D5D6, 0x1D5D7, 0x1D5D8, 0x1D5D9, 0x1D5DA, 0x1D5DB,
|
||||
0x1D5DC, 0x1D5DD, 0x1D5DE, 0x1D5DF, 0x1D5E0, 0x1D5E1, 0x1D5E2,
|
||||
0x1D5E3, 0x1D5E4, 0x1D5E5, 0x1D5E6, 0x1D5E7, 0x1D5E8, 0x1D5E9,
|
||||
0x1D5EA, 0x1D5EB, 0x1D5EC, 0x1D5ED, 0x1D608, 0x1D609, 0x1D60A,
|
||||
0x1D60B, 0x1D60C, 0x1D60D, 0x1D60E, 0x1D60F, 0x1D610, 0x1D611,
|
||||
0x1D612, 0x1D613, 0x1D614, 0x1D615, 0x1D616, 0x1D617, 0x1D618,
|
||||
0x1D619, 0x1D61A, 0x1D61B, 0x1D61C, 0x1D61D, 0x1D61E, 0x1D61F,
|
||||
0x1D620, 0x1D621, 0x1D63C, 0x1D63D, 0x1D63E, 0x1D63F, 0x1D640,
|
||||
0x1D641, 0x1D642, 0x1D643, 0x1D644, 0x1D645, 0x1D646, 0x1D647,
|
||||
0x1D648, 0x1D649, 0x1D64A, 0x1D64B, 0x1D64C, 0x1D64D, 0x1D64E,
|
||||
0x1D64F, 0x1D650, 0x1D651, 0x1D652, 0x1D653, 0x1D654, 0x1D655,
|
||||
0x1D670, 0x1D671, 0x1D672, 0x1D673, 0x1D674, 0x1D675, 0x1D676,
|
||||
0x1D677, 0x1D678, 0x1D679, 0x1D67A, 0x1D67B, 0x1D67C, 0x1D67D,
|
||||
0x1D67E, 0x1D67F, 0x1D680, 0x1D681, 0x1D682, 0x1D683, 0x1D684,
|
||||
0x1D685, 0x1D686, 0x1D687, 0x1D688, 0x1D689, 0x1D6A8, 0x1D6A9,
|
||||
0x1D6AA, 0x1D6AB, 0x1D6AC, 0x1D6AD, 0x1D6AE, 0x1D6AF, 0x1D6B0,
|
||||
0x1D6B1, 0x1D6B2, 0x1D6B3, 0x1D6B4, 0x1D6B5, 0x1D6B6, 0x1D6B7,
|
||||
0x1D6B8, 0x1D6B9, 0x1D6BA, 0x1D6BB, 0x1D6BC, 0x1D6BD, 0x1D6BE,
|
||||
0x1D6BF, 0x1D6C0, 0x1D6E2, 0x1D6E3, 0x1D6E4, 0x1D6E5, 0x1D6E6,
|
||||
0x1D6E7, 0x1D6E8, 0x1D6E9, 0x1D6EA, 0x1D6EB, 0x1D6EC, 0x1D6ED,
|
||||
0x1D6EE, 0x1D6EF, 0x1D6F0, 0x1D6F1, 0x1D6F2, 0x1D6F3, 0x1D6F4,
|
||||
0x1D6F5, 0x1D6F6, 0x1D6F7, 0x1D6F8, 0x1D6F9, 0x1D6FA, 0x1D71C,
|
||||
0x1D71D, 0x1D71E, 0x1D71F, 0x1D720, 0x1D721, 0x1D722, 0x1D723,
|
||||
0x1D724, 0x1D725, 0x1D726, 0x1D727, 0x1D728, 0x1D729, 0x1D72A,
|
||||
0x1D72B, 0x1D72C, 0x1D72D, 0x1D72E, 0x1D72F, 0x1D730, 0x1D731,
|
||||
0x1D732, 0x1D733, 0x1D734, 0x1D756, 0x1D757, 0x1D758, 0x1D759,
|
||||
0x1D75A, 0x1D75B, 0x1D75C, 0x1D75D, 0x1D75E, 0x1D75F, 0x1D760,
|
||||
0x1D761, 0x1D762, 0x1D763, 0x1D764, 0x1D765, 0x1D766, 0x1D767,
|
||||
0x1D768, 0x1D769, 0x1D76A, 0x1D76B, 0x1D76C, 0x1D76D, 0x1D76E,
|
||||
0x1D790, 0x1D791, 0x1D792, 0x1D793, 0x1D794, 0x1D795, 0x1D796,
|
||||
0x1D797, 0x1D798, 0x1D799, 0x1D79A, 0x1D79B, 0x1D79C, 0x1D79D,
|
||||
0x1D79E, 0x1D79F, 0x1D7A0, 0x1D7A1, 0x1D7A2, 0x1D7A3, 0x1D7A4,
|
||||
0x1D7A5, 0x1D7A6, 0x1D7A7, 0x1D7A8, 0x1D7CA, 0x1E900, 0x1E901,
|
||||
0x1E902, 0x1E903, 0x1E904, 0x1E905, 0x1E906, 0x1E907, 0x1E908,
|
||||
0x1E909, 0x1E90A, 0x1E90B, 0x1E90C, 0x1E90D, 0x1E90E, 0x1E90F,
|
||||
0x1E910, 0x1E911, 0x1E912, 0x1E913, 0x1E914, 0x1E915, 0x1E916,
|
||||
0x1E917, 0x1E918, 0x1E919, 0x1E91A, 0x1E91B, 0x1E91C, 0x1E91D,
|
||||
0x1E91E, 0x1E91F, 0x1E920, 0x1E921};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,9 +31,16 @@ namespace boost { namespace parser {
|
||||
template<typename T>
|
||||
constexpr bool enable_optional = false;
|
||||
|
||||
/** A variable template that indicates that type `T` is an variant-like
|
||||
type. */
|
||||
template<typename T>
|
||||
constexpr bool enable_variant = false;
|
||||
|
||||
#ifndef BOOST_PARSER_DOXYGEN
|
||||
template<typename T>
|
||||
constexpr bool enable_optional<std::optional<T>> = true;
|
||||
template<typename... Ts>
|
||||
constexpr bool enable_variant<std::variant<Ts...>> = true;
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
@@ -124,6 +131,32 @@ namespace boost { namespace parser {
|
||||
symbol_table_tries_t & symbol_table_tries) noexcept;
|
||||
|
||||
struct skip_skipper;
|
||||
|
||||
struct char_subrange
|
||||
{
|
||||
char32_t lo_;
|
||||
char32_t hi_;
|
||||
};
|
||||
|
||||
template<typename Tag>
|
||||
struct char_subranges
|
||||
{};
|
||||
|
||||
struct hex_digit_subranges
|
||||
{};
|
||||
struct control_subranges
|
||||
{};
|
||||
|
||||
template<typename Tag>
|
||||
struct char_set
|
||||
{};
|
||||
|
||||
struct punct_chars
|
||||
{};
|
||||
struct lower_case_chars
|
||||
{};
|
||||
struct upper_case_chars
|
||||
{};
|
||||
}
|
||||
|
||||
/** Repeats the application of another parser `p` of type `Parser`,
|
||||
@@ -267,9 +300,9 @@ namespace boost { namespace parser {
|
||||
`CanUseCallbacks` is `true`, and if this parser is used within a call
|
||||
to `callback_parse()`, the attribute is produced via callback;
|
||||
otherwise, the attribute is produced as normal (as a return value, or
|
||||
as an out-param). The rule may be constructed with a user-friendly
|
||||
name that will appear if the top-level parse is executed with
|
||||
`trace_mode == boost::parser::trace::on`. */
|
||||
as an out-param). The rule may be constructed with user-friendly
|
||||
diagnostic text that will appear if the top-level parse is executed
|
||||
with `trace_mode == boost::parser::trace::on`. */
|
||||
template<
|
||||
bool CanUseCallbacks,
|
||||
typename TagType,
|
||||
@@ -293,6 +326,14 @@ namespace boost { namespace parser {
|
||||
template<typename Attribute>
|
||||
struct attr_parser;
|
||||
|
||||
/** A tag type that can be passed as the first parameter to `char_()` when
|
||||
the second parameter is a sorted, random access sequence that can be
|
||||
matched using a binary search.*/
|
||||
struct sorted_t
|
||||
{};
|
||||
|
||||
inline constexpr sorted_t sorted;
|
||||
|
||||
/** Matches a single code point. If `AttributeType` is not `void`,
|
||||
`AttributeType` is the attribute type produced; otherwise, the
|
||||
attribute type is the decayed type of the matched code point. The
|
||||
@@ -302,19 +343,46 @@ namespace boost { namespace parser {
|
||||
template<typename Expected, typename AttributeType = void>
|
||||
struct char_parser;
|
||||
|
||||
/** Maches a particular string, delimited by an iterator sentinel pair;
|
||||
/** Matches a single code point that is equal to one of the code points
|
||||
associated with tag type `Tag`. This is used to create sets of
|
||||
characters for matching Unicode character classes like punctuation or
|
||||
lower case. Attribute type is the attribute type of the character
|
||||
being matched. */
|
||||
template<typename Tag>
|
||||
struct char_set_parser;
|
||||
|
||||
/** Matches a single code point that falls into one of the subranges of
|
||||
code points associated with tag type `Tag`. This is used to create
|
||||
sets of characters for matching Unicode character classes like hex
|
||||
digits or control characters. Attribute type is the attribute type of
|
||||
the character being matched. */
|
||||
template<typename Tag>
|
||||
struct char_subrange_parser;
|
||||
|
||||
/** Matches a single decimal digit code point, using the Unicode character
|
||||
class Hex_Digit. Attribute type is the attribute type of the
|
||||
character being matched. */
|
||||
struct digit_parser;
|
||||
|
||||
/** Matches a particular string, delimited by an iterator sentinel pair;
|
||||
produces no attribute. */
|
||||
template<typename StrIter, typename StrSentinel>
|
||||
struct string_parser;
|
||||
|
||||
/** Maches an end-of-line (`NewlinesOnly == true`) or whitespace
|
||||
(`NewlinesOnly == false`) code point, based on the Unicode definitions
|
||||
of each (also matches the two code points `"\r\n"`). Produces no
|
||||
/** Matches a string delimited by quotation marks; produces a
|
||||
`std::string` attribute. */
|
||||
template<typename I, typename S>
|
||||
struct quoted_string_parser;
|
||||
|
||||
/** Matches an end-of-line (`NewlinesOnly == true`), whitespace
|
||||
(`NewlinesOnly == false`), or (`NoNewlines == true`) blank (whitespace
|
||||
but not newline) code point, based on the Unicode definitions of each
|
||||
(also matches the two code points `"\r\n"`). Produces no
|
||||
attribute. */
|
||||
template<bool NewlinesOnly>
|
||||
template<bool NewlinesOnly, bool NoNewlines>
|
||||
struct ws_parser;
|
||||
|
||||
/** Maches the strings "true" and "false", producing an attribute of
|
||||
/** Matches the strings "true" and "false", producing an attribute of
|
||||
`true` or `false`, respectively, and fails on any other input. */
|
||||
struct bool_parser;
|
||||
|
||||
|
||||
720
include/boost/parser/replace.hpp
Normal file
720
include/boost/parser/replace.hpp
Normal file
@@ -0,0 +1,720 @@
|
||||
#ifndef BOOST_PARSER_REPLACE_HPP
|
||||
#define BOOST_PARSER_REPLACE_HPP
|
||||
|
||||
#include <boost/parser/search.hpp>
|
||||
|
||||
#if !defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS
|
||||
|
||||
|
||||
namespace boost::parser {
|
||||
|
||||
namespace detail {
|
||||
template<typename T, bool = std::is_pointer_v<remove_cv_ref_t<T>>>
|
||||
constexpr auto range_value_type =
|
||||
wrapper<remove_cv_ref_t<range_value_t<T>>>{};
|
||||
template<typename T>
|
||||
constexpr auto range_value_type<T, true> = wrapper<
|
||||
remove_cv_ref_t<std::remove_pointer_t<remove_cv_ref_t<T>>>>{};
|
||||
|
||||
template<typename T>
|
||||
constexpr text::format range_utf_format()
|
||||
{
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
// Special case: the metafunctions above will not detect char8_t
|
||||
// in C++17 mode, since it does not exit yet! So, we need to
|
||||
// detect utf8_view in particular, and know that its use implies
|
||||
// format::utf8.
|
||||
if constexpr (is_utf8_view<T>{}) {
|
||||
return format::utf8;
|
||||
} else {
|
||||
#endif
|
||||
using value_t = typename decltype(range_value_type<T>)::type;
|
||||
if constexpr (std::is_same_v<value_t, char>) {
|
||||
return no_format;
|
||||
#if defined(__cpp_char8_t)
|
||||
} else if constexpr (std::is_same_v<value_t, char8_t>) {
|
||||
return format::utf8;
|
||||
#endif
|
||||
} else if constexpr (
|
||||
std::is_same_v<value_t, char16_t>
|
||||
#ifdef _MSC_VER
|
||||
|| std::is_same_v<T, wchar_t>
|
||||
#endif
|
||||
) {
|
||||
return format::utf16;
|
||||
} else if constexpr (
|
||||
std::is_same_v<value_t, char32_t>
|
||||
#ifndef _MSC_VER
|
||||
|| std::is_same_v<T, wchar_t>
|
||||
#endif
|
||||
) {
|
||||
return format::utf32;
|
||||
} else {
|
||||
static_assert(
|
||||
sizeof(T) && false,
|
||||
"Looks like you're trying to pass a range to replace "
|
||||
"or transform_replace that has a non-character type "
|
||||
"for its value type. This is not supported.");
|
||||
}
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr text::format
|
||||
range_utf_format_v = detail::range_utf_format<remove_cv_ref_t<T>>();
|
||||
|
||||
template<typename V1, typename V2>
|
||||
using concat_reference_t =
|
||||
std::common_type_t<range_reference_t<V1>, range_reference_t<V2>>;
|
||||
template<typename V1, typename V2>
|
||||
using concat_value_t =
|
||||
std::common_type_t<range_value_t<V1>, range_value_t<V2>>;
|
||||
template<typename V1, typename V2>
|
||||
using concat_rvalue_reference_t = std::common_type_t<
|
||||
range_rvalue_reference_t<V1>,
|
||||
range_rvalue_reference_t<V2>>;
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
// clang-format off
|
||||
template<typename ReplacementV, typename V>
|
||||
concept concatable = requires {
|
||||
typename detail::concat_reference_t<ReplacementV, V>;
|
||||
typename detail::concat_value_t<ReplacementV, V>;
|
||||
typename detail::concat_rvalue_reference_t<ReplacementV, V>;
|
||||
};
|
||||
// clang-format on
|
||||
#else
|
||||
template<typename ReplacementV, typename V>
|
||||
// clang-format off
|
||||
using concatable_expr = decltype(
|
||||
std::declval<concat_reference_t<ReplacementV, V>>(),
|
||||
std::declval<concat_value_t<ReplacementV, V>>(),
|
||||
std::declval<concat_rvalue_reference_t<ReplacementV, V>>());
|
||||
// clang-format on
|
||||
template<typename ReplacementV, typename V>
|
||||
constexpr bool concatable =
|
||||
is_detected_v<concatable_expr, ReplacementV, V>;
|
||||
#endif
|
||||
|
||||
template<
|
||||
typename V1,
|
||||
typename V2
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
typename Enable = std::enable_if_t<concatable<V1, V2>>
|
||||
#endif
|
||||
>
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires concatable<V1, V2>
|
||||
#endif
|
||||
struct either_iterator_impl
|
||||
: detail::stl_interfaces::iterator_interface<
|
||||
either_iterator_impl<V1, V2>,
|
||||
std::forward_iterator_tag,
|
||||
concat_value_t<V1, V2>,
|
||||
concat_reference_t<V1, V2>>
|
||||
{
|
||||
constexpr either_iterator_impl() = default;
|
||||
constexpr either_iterator_impl(iterator_t<V1> it) : it_(it) {}
|
||||
template<typename V = V2>
|
||||
constexpr either_iterator_impl(iterator_t<V> it) : it_(it)
|
||||
{}
|
||||
|
||||
constexpr concat_reference_t<V1, V2> operator*() const
|
||||
{
|
||||
if (it_.index() == 0) {
|
||||
return *std::get<0>(it_);
|
||||
} else {
|
||||
return *std::get<1>(it_);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr either_iterator_impl & operator++()
|
||||
{
|
||||
if (it_.index() == 0)
|
||||
++std::get<0>(it_);
|
||||
else
|
||||
++std::get<1>(it_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator==(either_iterator_impl lhs, either_iterator_impl rhs)
|
||||
{
|
||||
if (lhs.it_.index() != rhs.it_.index())
|
||||
return false;
|
||||
if (lhs.it_.index() == 0)
|
||||
return std::get<0>(lhs.it_) == std::get<0>(rhs.it_);
|
||||
else
|
||||
return std::get<1>(lhs.it_) == std::get<1>(rhs.it_);
|
||||
}
|
||||
|
||||
using base_type = detail::stl_interfaces::iterator_interface<
|
||||
either_iterator_impl<V1, V2>,
|
||||
std::forward_iterator_tag,
|
||||
concat_value_t<V1, V2>,
|
||||
concat_reference_t<V1, V2>>;
|
||||
using base_type::operator++;
|
||||
|
||||
private:
|
||||
std::variant<iterator_t<V1>, iterator_t<V2>> it_;
|
||||
};
|
||||
|
||||
template<typename V1, typename V2>
|
||||
using either_iterator = std::conditional_t<
|
||||
std::is_same_v<iterator_t<V1>, iterator_t<V2>>,
|
||||
iterator_t<V1>,
|
||||
either_iterator_impl<V1, V2>>;
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
// clang-format off
|
||||
template<typename ReplacementV, typename V>
|
||||
concept replacement_for = requires (ReplacementV replacement, V base) {
|
||||
{ either_iterator<V, ReplacementV>(replacement.begin()) };
|
||||
{ either_iterator<V, ReplacementV>(replacement.end()) };
|
||||
{ either_iterator<V, ReplacementV>(base.begin()) };
|
||||
};
|
||||
// clang-format on
|
||||
#else
|
||||
template<typename ReplacementV, typename V>
|
||||
using replacement_for_expr = decltype(
|
||||
either_iterator<V, ReplacementV>(
|
||||
std::declval<ReplacementV&>().begin()),
|
||||
either_iterator<V, ReplacementV>(
|
||||
std::declval<ReplacementV&>().end()),
|
||||
either_iterator<V, ReplacementV>(std::declval<V&>().begin()));
|
||||
template<typename ReplacementV, typename V>
|
||||
constexpr bool replacement_for =
|
||||
is_detected_v<replacement_for_expr, ReplacementV, V>;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Produces a range of subranges of a given range `base`. Each subrange
|
||||
is either a subrange of `base` that does not match the given parser
|
||||
`parser`, or is the given replacement for a match, `replacement`. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
std::ranges::viewable_range V,
|
||||
std::ranges::viewable_range ReplacementV,
|
||||
#else
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
typename Enable = std::enable_if_t<
|
||||
detail::replacement_for<ReplacementV, V> &&
|
||||
(detail::range_utf_format_v<V> ==
|
||||
detail::range_utf_format_v<ReplacementV>)>
|
||||
#endif
|
||||
>
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires detail::replacement_for<ReplacementV, V> &&
|
||||
(detail::range_utf_format_v<V> ==
|
||||
detail::range_utf_format_v<ReplacementV>)
|
||||
#endif
|
||||
struct replace_view
|
||||
: detail::stl_interfaces::view_interface<replace_view<
|
||||
V,
|
||||
ReplacementV,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>>
|
||||
{
|
||||
constexpr replace_view() = default;
|
||||
constexpr replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementV replacement,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
replacement_(std::move(replacement)),
|
||||
parser_(parser),
|
||||
skip_(skip),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
constexpr replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
ReplacementV replacement,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
replacement_(std::move(replacement)),
|
||||
parser_(parser),
|
||||
skip_(),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
|
||||
constexpr V base() const &
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::copy_constructible<V>
|
||||
#endif
|
||||
{
|
||||
return base_;
|
||||
}
|
||||
constexpr V base() && { return std::move(base_); }
|
||||
|
||||
constexpr V replacement() const &
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::copy_constructible<V>
|
||||
#endif
|
||||
{
|
||||
return replacement_;
|
||||
}
|
||||
constexpr V replacement() && { return std::move(replacement_); }
|
||||
|
||||
constexpr auto begin() { return iterator<false>{this}; }
|
||||
constexpr auto end() { return sentinel<false>{}; }
|
||||
|
||||
constexpr auto begin() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return iterator<true>{this};
|
||||
}
|
||||
constexpr auto end() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return sentinel<true>{};
|
||||
}
|
||||
|
||||
template<bool Const>
|
||||
struct sentinel
|
||||
{};
|
||||
|
||||
template<bool Const>
|
||||
struct iterator : detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator<Const>,
|
||||
std::forward_iterator_tag,
|
||||
BOOST_PARSER_SUBRANGE<detail::either_iterator<
|
||||
detail::maybe_const<Const, V>,
|
||||
detail::maybe_const<Const, ReplacementV>>>>
|
||||
{
|
||||
using I = detail::iterator_t<detail::maybe_const<Const, V>>;
|
||||
using S = detail::sentinel_t<detail::maybe_const<Const, V>>;
|
||||
|
||||
using ref_t_iter = detail::either_iterator<
|
||||
detail::maybe_const<Const, V>,
|
||||
detail::maybe_const<Const, ReplacementV>>;
|
||||
using reference_type = BOOST_PARSER_SUBRANGE<ref_t_iter>;
|
||||
|
||||
constexpr iterator() = default;
|
||||
constexpr iterator(
|
||||
detail::maybe_const<Const, replace_view> * parent) :
|
||||
parent_(parent),
|
||||
r_(parent_->base_.begin(), parent_->base_.end()),
|
||||
curr_(r_.begin(), r_.begin()),
|
||||
next_it_(r_.begin()),
|
||||
in_match_(true)
|
||||
{
|
||||
++*this;
|
||||
}
|
||||
|
||||
constexpr iterator & operator++()
|
||||
{
|
||||
if (in_match_) {
|
||||
r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
|
||||
auto const new_match = parser::search(
|
||||
r_,
|
||||
parent_->parser_,
|
||||
parent_->skip_,
|
||||
parent_->trace_mode_);
|
||||
if (new_match.begin() == curr_.end()) {
|
||||
curr_ = new_match;
|
||||
} else {
|
||||
curr_ =
|
||||
BOOST_PARSER_SUBRANGE(next_it_, new_match.begin());
|
||||
in_match_ = false;
|
||||
}
|
||||
next_it_ = new_match.end();
|
||||
} else {
|
||||
if (!curr_.empty()) {
|
||||
curr_ = BOOST_PARSER_SUBRANGE(curr_.end(), next_it_);
|
||||
in_match_ = true;
|
||||
}
|
||||
if (curr_.empty())
|
||||
r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reference_type operator*() const
|
||||
{
|
||||
if (in_match_) {
|
||||
return reference_type(
|
||||
ref_t_iter(parent_->replacement_.begin()),
|
||||
ref_t_iter(parent_->replacement_.end()));
|
||||
} else {
|
||||
return reference_type(
|
||||
ref_t_iter(curr_.begin()), ref_t_iter(curr_.end()));
|
||||
}
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(iterator lhs, iterator rhs)
|
||||
{
|
||||
return lhs.r_.begin() == rhs.r_.begin();
|
||||
}
|
||||
friend constexpr bool operator==(iterator it, sentinel<Const>)
|
||||
{
|
||||
return it.r_.begin() == it.r_.end();
|
||||
}
|
||||
|
||||
using base_type = detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator,
|
||||
std::forward_iterator_tag,
|
||||
reference_type>;
|
||||
using base_type::operator++;
|
||||
|
||||
private:
|
||||
detail::maybe_const<Const, replace_view> * parent_;
|
||||
BOOST_PARSER_SUBRANGE<I, S> r_;
|
||||
BOOST_PARSER_SUBRANGE<I> curr_;
|
||||
I next_it_;
|
||||
bool in_match_;
|
||||
};
|
||||
|
||||
template<bool Const>
|
||||
friend struct iterator;
|
||||
|
||||
private:
|
||||
V base_;
|
||||
ReplacementV replacement_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
|
||||
// deduction guides
|
||||
template<
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>,
|
||||
ReplacementV &&,
|
||||
trace)
|
||||
-> replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::text::detail::all_t<ReplacementV>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>,
|
||||
ReplacementV &&)
|
||||
-> replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::text::detail::all_t<ReplacementV>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
ReplacementV &&,
|
||||
trace)
|
||||
-> replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::text::detail::all_t<ReplacementV>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
ReplacementV &&)
|
||||
-> replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::text::detail::all_t<ReplacementV>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
template<
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
using replace_view_expr = decltype(replace_view<
|
||||
V,
|
||||
ReplacementV,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
std::declval<ReplacementV>(),
|
||||
trace::on));
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool can_replace_view = is_detected_v<
|
||||
replace_view_expr,
|
||||
V,
|
||||
ReplacementV,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
struct replace_impl
|
||||
{
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
range_like ReplacementR,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
(std::is_pointer_v<std::remove_cvref_t<ReplacementR>> ||
|
||||
std::ranges::viewable_range<ReplacementR>) &&
|
||||
// clang-format on
|
||||
can_replace_view<
|
||||
to_range_t<R>,
|
||||
decltype(to_range<
|
||||
ReplacementR,
|
||||
true,
|
||||
detail::range_utf_format_v<R>>::
|
||||
call(std::declval<ReplacementR>())),
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementR && replacement,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return replace_view(
|
||||
to_range<R>::call((R &&) r),
|
||||
parser,
|
||||
skip,
|
||||
to_range<
|
||||
ReplacementR,
|
||||
true,
|
||||
detail::range_utf_format_v<R>>::call((ReplacementR &&)
|
||||
replacement),
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
range_like ReplacementR,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
(std::is_pointer_v<std::remove_cvref_t<ReplacementR>> ||
|
||||
std::ranges::viewable_range<ReplacementR>) &&
|
||||
// clang-format on
|
||||
can_replace_view<
|
||||
to_range_t<R>,
|
||||
decltype(to_range<
|
||||
ReplacementR,
|
||||
true,
|
||||
detail::range_utf_format_v<R>>::
|
||||
call(std::declval<ReplacementR>())),
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
ReplacementR && replacement,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return (*this)(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
(ReplacementR &&) replacement,
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser,
|
||||
typename ReplacementR = trace,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
SkipParser && skip,
|
||||
ReplacementR && replacement = ReplacementR{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
if constexpr (
|
||||
is_parser_iface<remove_cv_ref_t<SkipParser>> &&
|
||||
is_range_like<remove_cv_ref_t<ReplacementR>> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, skip, replacement, trace) case
|
||||
return impl(
|
||||
(R &&) r,
|
||||
parser,
|
||||
skip,
|
||||
(ReplacementR &&) replacement,
|
||||
trace_mode);
|
||||
} else if constexpr (
|
||||
is_range_like<remove_cv_ref_t<SkipParser>> &&
|
||||
std::is_same_v<remove_cv_ref_t<ReplacementR>, trace> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, replacement, trace) case
|
||||
return impl(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
(SkipParser &&) skip,
|
||||
replacement);
|
||||
} else {
|
||||
static_assert(
|
||||
sizeof(R) == 1 && false,
|
||||
"Only the signatures replace(R, parser, skip, "
|
||||
"replcement trace = trace::off) and replace(R, parser, "
|
||||
"replacement, trace = trace::off) are supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<
|
||||
typename R,
|
||||
typename ReplacementR,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
ReplacementR && replacement,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
return replace_view(
|
||||
to_range<R>::call((R &&) r),
|
||||
parser,
|
||||
skip,
|
||||
to_range<
|
||||
ReplacementR,
|
||||
true,
|
||||
detail::range_utf_format_v<R>>::call((ReplacementR &&)
|
||||
replacement),
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
/** A range adaptor object ([range.adaptor.object]). Given subexpressions
|
||||
`E` and `P`, `Q`, `R`, and 'S', each of the expressions `replace(E,
|
||||
P)`, `replace(E, P, Q)`. `replace(E, P, Q, R)`, and `replace(E, P, Q,
|
||||
R, S)` are expression-equivalent to `replace_view(E, P)`,
|
||||
`replace_view(E, P, Q)`, `replace_view(E, P, Q, R)`, `replace_view(E,
|
||||
P, Q, R, S)`, respectively. */
|
||||
inline constexpr detail::stl_interfaces::adaptor<detail::replace_impl>
|
||||
replace = detail::replace_impl{};
|
||||
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
template<
|
||||
typename V,
|
||||
typename ReplacementV,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool std::ranges::enable_borrowed_range<boost::parser::replace_view<
|
||||
V,
|
||||
ReplacementV,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
|
||||
std::ranges::enable_borrowed_range<ReplacementV>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
673
include/boost/parser/search.hpp
Normal file
673
include/boost/parser/search.hpp
Normal file
@@ -0,0 +1,673 @@
|
||||
#ifndef BOOST_PARSER_SEARCH_HPP
|
||||
#define BOOST_PARSER_SEARCH_HPP
|
||||
|
||||
#include <boost/parser/parser.hpp>
|
||||
#include <boost/parser/transcode_view.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace boost::parser {
|
||||
|
||||
namespace detail {
|
||||
template<bool Const, typename T>
|
||||
using maybe_const = std::conditional_t<Const, const T, T>;
|
||||
|
||||
inline constexpr text::format no_format = text::format::none;
|
||||
|
||||
template<text::format Format = text::format::utf8>
|
||||
constexpr auto as_utf =
|
||||
text::detail::as_utf_impl<text::utf8_view, text::format::utf8>{};
|
||||
template<>
|
||||
constexpr auto as_utf<text::format::utf16> =
|
||||
text::detail::as_utf_impl<text::utf16_view, text::format::utf16>{};
|
||||
template<>
|
||||
constexpr auto as_utf<text::format::utf32> =
|
||||
text::detail::as_utf_impl<text::utf32_view, text::format::utf32>{};
|
||||
|
||||
template<
|
||||
typename R_,
|
||||
bool ToCommonRange = false,
|
||||
text::format OtherRangeFormat = no_format,
|
||||
bool = std::is_pointer_v<remove_cv_ref_t<R_>> ||
|
||||
text::detail::is_bounded_array_v<remove_cv_ref_t<R_>>>
|
||||
struct to_range
|
||||
{
|
||||
template<typename R>
|
||||
static constexpr auto call(R && r)
|
||||
{
|
||||
static_assert(std::is_same_v<R, R_>);
|
||||
using T = remove_cv_ref_t<R>;
|
||||
if constexpr (std::is_pointer_v<T>) {
|
||||
if constexpr (OtherRangeFormat == no_format) {
|
||||
if constexpr (ToCommonRange)
|
||||
return BOOST_PARSER_SUBRANGE(r, r + std::strlen(r));
|
||||
else
|
||||
return BOOST_PARSER_SUBRANGE(r, null_sentinel_t{});
|
||||
} else {
|
||||
if constexpr (ToCommonRange) {
|
||||
return BOOST_PARSER_SUBRANGE(
|
||||
r, r + std::strlen(r)) |
|
||||
as_utf<OtherRangeFormat>;
|
||||
} else {
|
||||
return BOOST_PARSER_SUBRANGE(r, null_sentinel_t{}) |
|
||||
as_utf<OtherRangeFormat>;
|
||||
}
|
||||
}
|
||||
} else if constexpr (text::detail::is_bounded_array_v<T>) {
|
||||
auto const first = std::begin(r);
|
||||
auto last = std::end(r);
|
||||
constexpr auto n = std::extent_v<T>;
|
||||
if (n && !r[n - 1])
|
||||
--last;
|
||||
if constexpr (OtherRangeFormat == no_format) {
|
||||
return BOOST_PARSER_SUBRANGE(first, last);
|
||||
} else {
|
||||
return BOOST_PARSER_SUBRANGE(first, last) |
|
||||
as_utf<OtherRangeFormat>;
|
||||
}
|
||||
} else {
|
||||
return (R &&) r | as_utf<OtherRangeFormat>;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R_, bool ToCommonRange>
|
||||
struct to_range<R_, ToCommonRange, no_format, false>
|
||||
{
|
||||
template<typename R>
|
||||
static constexpr R && call(R && r)
|
||||
{
|
||||
return (R &&) r;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
using to_range_t = decltype(to_range<R>::call(std::declval<R>()));
|
||||
|
||||
struct phony
|
||||
{};
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
auto search_impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
auto first = text::detail::begin(r);
|
||||
auto const last = text::detail::end(r);
|
||||
|
||||
if (first == last)
|
||||
return BOOST_PARSER_SUBRANGE(first, first);
|
||||
|
||||
auto const search_parser = omit[*(char_ - parser)] >> -raw[parser];
|
||||
if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
|
||||
auto result = parser::prefix_parse(
|
||||
first, last, search_parser, trace_mode);
|
||||
if (*result)
|
||||
return **result;
|
||||
} else {
|
||||
auto result = parser::prefix_parse(
|
||||
first, last, search_parser, skip, trace_mode);
|
||||
if (*result)
|
||||
return **result;
|
||||
}
|
||||
|
||||
return BOOST_PARSER_SUBRANGE(first, first);
|
||||
}
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
std::ranges::borrowed_subrange_t<R>
|
||||
#else
|
||||
auto
|
||||
#endif
|
||||
search_repack_shim(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
using value_type = range_value_t<decltype(r)>;
|
||||
if constexpr (std::is_same_v<value_type, char>) {
|
||||
return detail::search_impl((R &&) r, parser, skip, trace_mode);
|
||||
} else {
|
||||
auto r_unpacked = detail::text::unpack_iterator_and_sentinel(
|
||||
text::detail::begin(r), text::detail::end(r));
|
||||
auto result =
|
||||
detail::search_impl(r | as_utf32, parser, skip, trace_mode);
|
||||
return BOOST_PARSER_SUBRANGE(
|
||||
r_unpacked.repack(text::detail::begin(result).base()),
|
||||
r_unpacked.repack(text::detail::end(result).base()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_parser_iface = false;
|
||||
template<typename T>
|
||||
constexpr bool is_parser_iface<parser_interface<T>> = true;
|
||||
}
|
||||
|
||||
/** Returns a subrange to the first match for parser `parser` in `r`,
|
||||
using skip-parser `skip`. This function has a similar interface and
|
||||
semantics to `std::ranges::search()`. Returns `std::ranges::dangling`
|
||||
in C++20 and later if `r` is a non-borrowable rvalue. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
parsable_range_like R,
|
||||
#else
|
||||
typename R,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>
|
||||
#endif
|
||||
>
|
||||
auto search(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return detail::search_repack_shim(
|
||||
detail::to_range<R>::call((R &&) r), parser, skip, trace_mode);
|
||||
}
|
||||
|
||||
/** Returns a subrange to the first match for parser `parser` in `[first,
|
||||
last)`, using skip-parser `skip`. This function has a similar
|
||||
interface and semantics to `std::ranges::search()`. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
parsable_iter I,
|
||||
std::sentinel_for<I> S,
|
||||
#else
|
||||
typename I,
|
||||
typename S,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename SkipParser,
|
||||
typename GlobalState,
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
error_handler<I, S, GlobalState> ErrorHandler
|
||||
#else
|
||||
typename ErrorHandler,
|
||||
typename Enable = std::enable_if_t<
|
||||
detail::is_parsable_iter_v<I> &&
|
||||
detail::is_equality_comparable_with_v<I, S>>
|
||||
#endif
|
||||
>
|
||||
auto search(
|
||||
I first,
|
||||
S last,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return parser::search(
|
||||
BOOST_PARSER_SUBRANGE(first, last), parser, skip, trace_mode);
|
||||
}
|
||||
|
||||
/** Returns a subrange to the first match for parser `parser` in `r`.
|
||||
This function has a similar interface and semantics to
|
||||
`std::ranges::search()`. Returns `std::ranges::dangling` in C++20 and
|
||||
later if `r` is a non-borrowable rvalue. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
parsable_range_like R,
|
||||
#else
|
||||
typename R,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>
|
||||
#endif
|
||||
>
|
||||
auto search(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return parser::search(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
/** Returns a subrange to the first match for parser `parser` in `[first,
|
||||
last)`. This function has a similar interface and semantics to
|
||||
`std::ranges::search()`. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
parsable_iter I,
|
||||
std::sentinel_for<I> S,
|
||||
#else
|
||||
typename I,
|
||||
typename S,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
error_handler<I, S, GlobalState> ErrorHandler
|
||||
#else
|
||||
typename ErrorHandler,
|
||||
typename Enable = std::enable_if_t<
|
||||
detail::is_parsable_iter_v<I> &&
|
||||
detail::is_equality_comparable_with_v<I, S>>
|
||||
#endif
|
||||
>
|
||||
auto search(
|
||||
I first,
|
||||
S last,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
trace trace_mode = trace::off)
|
||||
{
|
||||
return parser::search(
|
||||
BOOST_PARSER_SUBRANGE(first, last),
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
/** Produces a sequence of subranges of the underlying sequence of type
|
||||
`V`. Each subrange is a nonoverlapping match of the given parser,
|
||||
using a skip-parser if provided. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
std::ranges::viewable_range V,
|
||||
#else
|
||||
typename V,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
struct search_all_view
|
||||
: detail::stl_interfaces::view_interface<
|
||||
search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
|
||||
{
|
||||
constexpr search_all_view() = default;
|
||||
constexpr search_all_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
skip_(skip),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
constexpr search_all_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
skip_(),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
|
||||
constexpr V base() const &
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::copy_constructible<V>
|
||||
#endif
|
||||
{
|
||||
return base_;
|
||||
}
|
||||
constexpr V base() && { return std::move(base_); }
|
||||
|
||||
constexpr auto begin() { return iterator<false>{this}; }
|
||||
constexpr auto end() { return sentinel<false>{}; }
|
||||
|
||||
constexpr auto begin() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return iterator<true>{this};
|
||||
}
|
||||
constexpr auto end() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return sentinel<true>{};
|
||||
}
|
||||
|
||||
template<bool Const>
|
||||
struct sentinel
|
||||
{};
|
||||
|
||||
template<bool Const>
|
||||
struct iterator
|
||||
: detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator<Const>,
|
||||
std::forward_iterator_tag,
|
||||
BOOST_PARSER_SUBRANGE<
|
||||
detail::iterator_t<detail::maybe_const<Const, V>>>>
|
||||
{
|
||||
using I = detail::iterator_t<detail::maybe_const<Const, V>>;
|
||||
using S = detail::sentinel_t<detail::maybe_const<Const, V>>;
|
||||
|
||||
constexpr iterator() = default;
|
||||
constexpr iterator(
|
||||
detail::maybe_const<Const, search_all_view> * parent) :
|
||||
parent_(parent),
|
||||
r_(parent_->base_.begin(), parent_->base_.end()),
|
||||
curr_(r_.begin(), r_.begin()),
|
||||
next_it_(r_.begin())
|
||||
{
|
||||
++*this;
|
||||
}
|
||||
|
||||
constexpr iterator & operator++()
|
||||
{
|
||||
r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
|
||||
curr_ = parser::search(
|
||||
r_, parent_->parser_, parent_->skip_, parent_->trace_mode_);
|
||||
next_it_ = curr_.end();
|
||||
if (curr_.begin() == curr_.end())
|
||||
r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr BOOST_PARSER_SUBRANGE<I> operator*() const
|
||||
{
|
||||
return curr_;
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(iterator lhs, iterator rhs)
|
||||
{
|
||||
return lhs.r_.begin() == rhs.r_.begin();
|
||||
}
|
||||
friend constexpr bool operator==(iterator it, sentinel<Const>)
|
||||
{
|
||||
return it.r_.begin() == it.r_.end();
|
||||
}
|
||||
|
||||
using base_type = detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator,
|
||||
std::forward_iterator_tag,
|
||||
BOOST_PARSER_SUBRANGE<I>>;
|
||||
using base_type::operator++;
|
||||
|
||||
private:
|
||||
detail::maybe_const<Const, search_all_view> * parent_;
|
||||
BOOST_PARSER_SUBRANGE<I, S> r_;
|
||||
BOOST_PARSER_SUBRANGE<I> curr_;
|
||||
I next_it_;
|
||||
};
|
||||
|
||||
template<bool Const>
|
||||
friend struct iterator;
|
||||
|
||||
private:
|
||||
V base_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
|
||||
// deduction guides
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
search_all_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>,
|
||||
trace)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
search_all_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
search_all_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
|
||||
-> search_all_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
using search_all_view_expr = decltype(search_all_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
trace::on));
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool can_search_all_view = is_detected_v<
|
||||
search_all_view_expr,
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
struct search_all_impl
|
||||
{
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
can_search_all_view<
|
||||
to_range_t<R>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return search_all_view(
|
||||
to_range<R>::call((R &&) r), parser, skip, trace_mode);
|
||||
}
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
can_search_all_view<
|
||||
to_range_t<R>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return (*this)(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser =
|
||||
parser_interface<eps_parser<detail::phony>>,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
SkipParser const & skip = SkipParser{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
if constexpr (
|
||||
std::
|
||||
is_same_v<detail::remove_cv_ref_t<SkipParser>, trace> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, trace) case
|
||||
return impl(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
skip);
|
||||
} else if constexpr (
|
||||
detail::is_parser_iface<SkipParser> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, skip, trace) case
|
||||
return impl((R &&) r, parser, skip, trace_mode);
|
||||
} else {
|
||||
static_assert(
|
||||
sizeof(R) == 1 && false,
|
||||
"Only the signatures search_all(R, parser, skip, trace "
|
||||
"= trace::off) and search_all(R, parser, trace = "
|
||||
"trace::off) are supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
return search_all_view(
|
||||
to_range<R>::call((R &&) r), parser, skip, trace_mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
/** A range adaptor object ([range.adaptor.object]). Given subexpressions
|
||||
`E` and `P`, `Q`, and `R`, each of the expressions `search_all(E, P)`,
|
||||
`search_all(E, P, Q)`, and `search_all(E, P, Q, R)` are
|
||||
expression-equivalent to `search_all_view(E, P)`, `search_all_view(E,
|
||||
P, Q)`, and `search_all_view(E, P, Q, R)`, respectively. */
|
||||
inline constexpr detail::stl_interfaces::adaptor<detail::search_all_impl>
|
||||
search_all = detail::search_all_impl{};
|
||||
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool std::ranges::enable_borrowed_range<
|
||||
boost::parser::
|
||||
search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
|
||||
std::ranges::enable_borrowed_range<V>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
399
include/boost/parser/split.hpp
Normal file
399
include/boost/parser/split.hpp
Normal file
@@ -0,0 +1,399 @@
|
||||
#ifndef BOOST_PARSER_SPLIT_HPP
|
||||
#define BOOST_PARSER_SPLIT_HPP
|
||||
|
||||
#include <boost/parser/search.hpp>
|
||||
|
||||
|
||||
namespace boost::parser {
|
||||
|
||||
/** Produces a sequence of subranges of the underlying sequence of type
|
||||
`V`. the underlying sequence is split into subranges delimited by
|
||||
matches of the given parser, possibly using a given skip-parser. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
std::ranges::viewable_range V,
|
||||
#else
|
||||
typename V,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
struct split_view
|
||||
: detail::stl_interfaces::view_interface<
|
||||
split_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
|
||||
{
|
||||
constexpr split_view() = default;
|
||||
constexpr split_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
skip_(skip),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
constexpr split_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
parser_(parser),
|
||||
skip_(),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
|
||||
constexpr V base() const &
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::copy_constructible<V>
|
||||
#endif
|
||||
{
|
||||
return base_;
|
||||
}
|
||||
constexpr V base() && { return std::move(base_); }
|
||||
|
||||
constexpr auto begin() { return iterator<false>{this}; }
|
||||
constexpr auto end() { return sentinel<false>{}; }
|
||||
|
||||
constexpr auto begin() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return iterator<true>{this};
|
||||
}
|
||||
constexpr auto end() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return sentinel<true>{};
|
||||
}
|
||||
|
||||
template<bool Const>
|
||||
struct sentinel
|
||||
{};
|
||||
|
||||
template<bool Const>
|
||||
struct iterator
|
||||
: detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator<Const>,
|
||||
std::forward_iterator_tag,
|
||||
BOOST_PARSER_SUBRANGE<
|
||||
detail::iterator_t<detail::maybe_const<Const, V>>>>
|
||||
{
|
||||
using I = detail::iterator_t<detail::maybe_const<Const, V>>;
|
||||
using S = detail::sentinel_t<detail::maybe_const<Const, V>>;
|
||||
|
||||
constexpr iterator() = default;
|
||||
constexpr iterator(
|
||||
detail::maybe_const<Const, split_view> * parent) :
|
||||
parent_(parent),
|
||||
r_(parent_->base_.begin(), parent_->base_.end()),
|
||||
curr_(r_.begin(), r_.begin()),
|
||||
next_it_(r_.begin()),
|
||||
next_follows_match_(false)
|
||||
{
|
||||
++*this;
|
||||
}
|
||||
|
||||
constexpr iterator & operator++()
|
||||
{
|
||||
if (next_it_ == r_.end() && next_follows_match_) {
|
||||
curr_ = BOOST_PARSER_SUBRANGE(next_it_, next_it_);
|
||||
next_follows_match_ = false;
|
||||
return *this;
|
||||
}
|
||||
r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
|
||||
auto const curr_match = parser::search(
|
||||
r_, parent_->parser_, parent_->skip_, parent_->trace_mode_);
|
||||
curr_ = BOOST_PARSER_SUBRANGE(next_it_, curr_match.begin());
|
||||
next_it_ = curr_match.end();
|
||||
next_follows_match_ = !curr_match.empty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr BOOST_PARSER_SUBRANGE<I> operator*() const
|
||||
{
|
||||
return curr_;
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(iterator lhs, iterator rhs)
|
||||
{
|
||||
return lhs.r_.begin() == rhs.r_.begin();
|
||||
}
|
||||
friend constexpr bool operator==(iterator it, sentinel<Const>)
|
||||
{
|
||||
return it.r_.begin() == it.r_.end();
|
||||
}
|
||||
|
||||
using base_type = detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator,
|
||||
std::forward_iterator_tag,
|
||||
BOOST_PARSER_SUBRANGE<I>>;
|
||||
using base_type::operator++;
|
||||
|
||||
private:
|
||||
detail::maybe_const<Const, split_view> * parent_;
|
||||
BOOST_PARSER_SUBRANGE<I, S> r_;
|
||||
BOOST_PARSER_SUBRANGE<I> curr_;
|
||||
I next_it_;
|
||||
bool next_follows_match_;
|
||||
};
|
||||
|
||||
template<bool Const>
|
||||
friend struct iterator;
|
||||
|
||||
private:
|
||||
V base_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
|
||||
// deduction guides
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
split_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>,
|
||||
trace)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
split_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
split_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
split_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
|
||||
-> split_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
using split_view_expr = decltype(split_view<
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
trace::on));
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool can_split_view = is_detected_v<
|
||||
split_view_expr,
|
||||
V,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
struct split_impl
|
||||
{
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
can_split_view<
|
||||
to_range_t<R>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return split_view(
|
||||
to_range<R>::call((R &&) r), parser, skip, trace_mode);
|
||||
}
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
requires(
|
||||
std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
can_split_view<
|
||||
to_range_t<R>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return (*this)(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser =
|
||||
parser_interface<eps_parser<detail::phony>>,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
SkipParser const & skip = SkipParser{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
if constexpr (
|
||||
std::
|
||||
is_same_v<detail::remove_cv_ref_t<SkipParser>, trace> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, trace) case
|
||||
return impl(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
skip);
|
||||
} else if constexpr (
|
||||
detail::is_parser_iface<SkipParser> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, skip, trace) case
|
||||
return impl((R &&) r, parser, skip, trace_mode);
|
||||
} else {
|
||||
static_assert(
|
||||
sizeof(R) == 1 && false,
|
||||
"Only the signatures split(R, parser, skip, trace "
|
||||
"= trace::off) and split(R, parser, trace = "
|
||||
"trace::off) are supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
return split_view(
|
||||
to_range<R>::call((R &&) r), parser, skip, trace_mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
/** A range adaptor object ([range.adaptor.object]). Given subexpressions
|
||||
`E` and `P`, `Q`, and `R`, each of the expressions `split(E, P)`,
|
||||
`split(E, P, Q)`, and `split(E, P, Q, R)` are
|
||||
expression-equivalent to `split_view(E, P)`, `split_view(E,
|
||||
P, Q)`, and `split_view(E, P, Q, R)`, respectively. */
|
||||
inline constexpr detail::stl_interfaces::adaptor<detail::split_impl>
|
||||
split = detail::split_impl{};
|
||||
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
template<
|
||||
typename V,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool std::ranges::enable_borrowed_range<
|
||||
boost::parser::
|
||||
split_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
|
||||
std::ranges::enable_borrowed_range<V>;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
841
include/boost/parser/transform_replace.hpp
Normal file
841
include/boost/parser/transform_replace.hpp
Normal file
@@ -0,0 +1,841 @@
|
||||
#ifndef BOOST_PARSER_TRANSFORM_REPLACE_HPP
|
||||
#define BOOST_PARSER_TRANSFORM_REPLACE_HPP
|
||||
|
||||
#include <boost/parser/replace.hpp>
|
||||
|
||||
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS)
|
||||
|
||||
|
||||
namespace boost::parser {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename F>
|
||||
constexpr bool tidy_func = std::is_trivially_copyable_v<F> &&
|
||||
sizeof(F) <= sizeof(void *) * 2;
|
||||
|
||||
template<typename I, typename S, typename Parser>
|
||||
using attr_type = decltype(std::declval<Parser const &>().call(
|
||||
std::bool_constant<false>{},
|
||||
std::declval<I &>(),
|
||||
std::declval<S>(),
|
||||
std::declval<parse_context<I, S, default_error_handler>>(),
|
||||
ws,
|
||||
detail::default_flags(),
|
||||
std::declval<bool &>()));
|
||||
template<typename R, typename Parser>
|
||||
using range_attr_t = attr_type<iterator_t<R>, sentinel_t<R>, Parser>;
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
// clang-format off
|
||||
template<typename F, typename V, typename Parser>
|
||||
concept transform_replacement_for =
|
||||
std::regular_invocable<F &, range_attr_t<V, Parser>> &&
|
||||
detail::replacement_for<
|
||||
std::invoke_result_t<F &, range_attr_t<V, Parser>>, V> &&
|
||||
(detail::range_utf_format_v<V> ==
|
||||
detail::range_utf_format_v<
|
||||
std::invoke_result_t<F &, range_attr_t<V, Parser>>>);
|
||||
// clang-format on
|
||||
#else
|
||||
template<typename F, typename V, typename Parser>
|
||||
using transform_replacement_for_expr = decltype(std::declval<F &>()(
|
||||
std::declval<range_attr_t<V, Parser>>()));
|
||||
template<
|
||||
typename F,
|
||||
typename V,
|
||||
typename Parser,
|
||||
bool = is_detected_v<transform_replacement_for_expr, F, V, Parser>>
|
||||
constexpr bool transform_replacement_for = false;
|
||||
template<typename F, typename V, typename Parser>
|
||||
constexpr bool transform_replacement_for<F, V, Parser, true> =
|
||||
replacement_for<transform_replacement_for_expr<F, V, Parser>, V> &&
|
||||
(detail::range_utf_format_v<V> ==
|
||||
detail::range_utf_format_v<
|
||||
transform_replacement_for_expr<F, V, Parser>>);
|
||||
#endif
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Result,
|
||||
text::format OtherFormat = range_utf_format_v<remove_cv_ref_t<R>>,
|
||||
text::format Format = range_utf_format_v<remove_cv_ref_t<Result>>>
|
||||
struct utf_wrap
|
||||
{
|
||||
template<typename R_ = R>
|
||||
static auto call(R_ && r)
|
||||
{
|
||||
return (R_ &&) r | as_utf<OtherFormat>;
|
||||
}
|
||||
};
|
||||
template<typename R, typename Result, text::format Format>
|
||||
struct utf_wrap<R, Result, Format, Format>
|
||||
{
|
||||
template<typename R_ = R>
|
||||
static R_ && call(R_ && r)
|
||||
{
|
||||
return (R_ &&) r;
|
||||
}
|
||||
};
|
||||
template<typename R, typename Result>
|
||||
struct utf_wrap<R, Result, no_format, no_format>
|
||||
{
|
||||
template<typename R_ = R>
|
||||
static R_ && call(R_ && r)
|
||||
{
|
||||
return (R_ &&) r;
|
||||
}
|
||||
};
|
||||
template<typename R, typename Result, text::format Format>
|
||||
struct utf_wrap<R, Result, no_format, Format>
|
||||
{
|
||||
// Looks like you tried to use transform_replace() to replace
|
||||
// subranges of chars with subranges of some UTF-N (for N=8, 16,
|
||||
// or 32). Transcoding from char (unkown encoding) is not
|
||||
// supported. Check the return type of your transform function.
|
||||
};
|
||||
template<typename R, typename Result, text::format Format>
|
||||
struct utf_wrap<R, Result, Format, no_format>
|
||||
{
|
||||
// Looks like you tried to use transform_replace() to replace
|
||||
// subranges of some UTF-N (for N=8, 16, or 32) with subranges of
|
||||
// chars. Transcoding to char (unkown encoding) is not supported.
|
||||
// Check the return type of your transform function.
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct regular_ref_wrapper
|
||||
{
|
||||
regular_ref_wrapper() = default;
|
||||
regular_ref_wrapper(T & ref) : ptr_(&ref) {}
|
||||
|
||||
T & get() const { return *ptr_; }
|
||||
|
||||
T * ptr_;
|
||||
};
|
||||
|
||||
// This type catches results of calling F, to accommodate when F
|
||||
// returns an rvalue or a type that needs to be transcoded to a
|
||||
// different UTF.
|
||||
template<typename R, typename F, typename Attr>
|
||||
struct utf_rvalue_shim
|
||||
{
|
||||
using result_type = std::invoke_result_t<F &, Attr>;
|
||||
using maybe_wrapped_result_type =
|
||||
decltype(utf_wrap<R, result_type>::call(
|
||||
std::declval<result_type>()));
|
||||
static constexpr bool final_type_is_reference =
|
||||
std::is_lvalue_reference_v<maybe_wrapped_result_type>;
|
||||
using final_type = std::conditional_t<
|
||||
final_type_is_reference,
|
||||
regular_ref_wrapper<
|
||||
std::remove_reference_t<maybe_wrapped_result_type>>,
|
||||
remove_cv_ref_t<maybe_wrapped_result_type>>;
|
||||
|
||||
template<typename F_ = F>
|
||||
utf_rvalue_shim(F_ && f) : f_((F_ &&) f)
|
||||
{}
|
||||
|
||||
// These two only have return values for testing and metaprogramming
|
||||
// purposes.
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<B>>
|
||||
decltype(auto) operator()(Attr && attr) const
|
||||
{
|
||||
result_ = final_type(
|
||||
utf_wrap<R, result_type>::call((*f_)((Attr &&) attr)));
|
||||
return result_->get();
|
||||
}
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<B>>
|
||||
decltype(auto) operator()(Attr && attr)
|
||||
{
|
||||
result_ = final_type(
|
||||
utf_wrap<R, result_type>::call((*f_)((Attr &&) attr)));
|
||||
return result_->get();
|
||||
}
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<!B>>
|
||||
final_type & operator()(Attr && attr) const
|
||||
{
|
||||
result_ = utf_wrap<R, result_type>::call((*f_)((Attr &&) attr));
|
||||
return *result_;
|
||||
}
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<!B>>
|
||||
final_type & operator()(Attr && attr)
|
||||
{
|
||||
result_ = utf_wrap<R, result_type>::call((*f_)((Attr &&) attr));
|
||||
return *result_;
|
||||
}
|
||||
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<B>>
|
||||
decltype(auto) get() const
|
||||
{
|
||||
return result_->get();
|
||||
}
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<B>>
|
||||
decltype(auto) get()
|
||||
{
|
||||
return result_->get();
|
||||
}
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<!B>>
|
||||
final_type & get() const
|
||||
{
|
||||
return *result_;
|
||||
}
|
||||
template<
|
||||
bool B = final_type_is_reference,
|
||||
typename Enable = std::enable_if_t<!B>>
|
||||
final_type & get()
|
||||
{
|
||||
return *result_;
|
||||
}
|
||||
|
||||
std::optional<F> f_;
|
||||
mutable std::optional<final_type> result_;
|
||||
};
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
auto attr_search_impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
auto first = text::detail::begin(r);
|
||||
auto const last = text::detail::end(r);
|
||||
|
||||
auto match_first = first;
|
||||
auto match_last = first;
|
||||
auto before = [&match_first](auto & ctx) {
|
||||
match_first = _where(ctx).begin();
|
||||
};
|
||||
auto after = [&match_last](auto & ctx) {
|
||||
match_last = _where(ctx).begin();
|
||||
};
|
||||
|
||||
auto const search_parser =
|
||||
omit[*(char_ - parser)] >>
|
||||
-lexeme[eps[before] >> parser::skip[parser] >> eps[after]];
|
||||
|
||||
using parse_result_outer = decltype(parser::prefix_parse(
|
||||
first, last, search_parser, trace_mode));
|
||||
|
||||
static_assert(
|
||||
!std::is_same_v<parse_result_outer, bool>,
|
||||
"If you're seeing this error, you passed a parser to "
|
||||
"transform_replace() that has no attribute. Please fix.");
|
||||
|
||||
using parse_result =
|
||||
remove_cv_ref_t<decltype(**std::declval<parse_result_outer>())>;
|
||||
|
||||
using return_tuple = tuple<
|
||||
decltype(BOOST_PARSER_SUBRANGE(first, first)),
|
||||
parse_result>;
|
||||
|
||||
if (first == last) {
|
||||
return return_tuple(
|
||||
BOOST_PARSER_SUBRANGE(first, first), parse_result{});
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
|
||||
auto result = parser::prefix_parse(
|
||||
first, last, search_parser, trace_mode);
|
||||
if (*result) {
|
||||
return return_tuple(
|
||||
BOOST_PARSER_SUBRANGE(match_first, match_last),
|
||||
std::move(**result));
|
||||
}
|
||||
} else {
|
||||
auto result = parser::prefix_parse(
|
||||
first, last, search_parser, skip, trace_mode);
|
||||
if (*result) {
|
||||
return return_tuple(
|
||||
BOOST_PARSER_SUBRANGE(match_first, match_last),
|
||||
std::move(**result));
|
||||
}
|
||||
}
|
||||
|
||||
return return_tuple(
|
||||
BOOST_PARSER_SUBRANGE(first, first), parse_result{});
|
||||
}
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
auto attr_search_repack_shim(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
trace trace_mode)
|
||||
{
|
||||
using value_type = range_value_t<decltype(r)>;
|
||||
if constexpr (std::is_same_v<value_type, char>) {
|
||||
return detail::attr_search_impl(
|
||||
(R &&) r, parser, skip, trace_mode);
|
||||
} else {
|
||||
auto r_unpacked = detail::text::unpack_iterator_and_sentinel(
|
||||
text::detail::begin(r), text::detail::end(r));
|
||||
auto result = detail::attr_search_impl(
|
||||
r | as_utf32, parser, skip, trace_mode);
|
||||
auto subrng = parser::get(result, llong<0>{});
|
||||
auto & attr = parser::get(result, llong<1>{});
|
||||
return tuple<
|
||||
decltype(BOOST_PARSER_SUBRANGE(
|
||||
r_unpacked.repack(subrng.begin().base()),
|
||||
r_unpacked.repack(subrng.end().base()))),
|
||||
remove_cv_ref_t<decltype(attr)>>(
|
||||
BOOST_PARSER_SUBRANGE(
|
||||
r_unpacked.repack(subrng.begin().base()),
|
||||
r_unpacked.repack(subrng.end().base())),
|
||||
std::move(attr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Produces a range of subranges of a given range `base`. Each subrange
|
||||
is either a subrange of `base` that does not match the given parser
|
||||
`parser`, or is `f(*boost::parser::parse(match, parser))`, where `f`
|
||||
is the given invocable and `match` is the matching subrange. */
|
||||
template<
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
std::ranges::viewable_range V,
|
||||
std::move_constructible F,
|
||||
#else
|
||||
typename V,
|
||||
typename F,
|
||||
#endif
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser
|
||||
#if !BOOST_PARSER_USE_CONCEPTS
|
||||
,
|
||||
typename Enable =
|
||||
std::enable_if_t<detail::transform_replacement_for<F, V, Parser>>
|
||||
#endif
|
||||
>
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires detail::transform_replacement_for<F, V, Parser>
|
||||
#endif
|
||||
struct transform_replace_view
|
||||
: detail::stl_interfaces::view_interface<transform_replace_view<
|
||||
V,
|
||||
F,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>>
|
||||
{
|
||||
private:
|
||||
using attr_t = detail::range_attr_t<V, Parser>;
|
||||
using replacement_range = std::invoke_result_t<F &, attr_t>;
|
||||
|
||||
public:
|
||||
constexpr transform_replace_view() = default;
|
||||
constexpr transform_replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F f,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
f_(std::move(f)),
|
||||
parser_(parser),
|
||||
skip_(skip),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
constexpr transform_replace_view(
|
||||
V base,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
|
||||
F f,
|
||||
trace trace_mode = trace::off) :
|
||||
base_(std::move(base)),
|
||||
f_(std::move(f)),
|
||||
parser_(parser),
|
||||
skip_(),
|
||||
trace_mode_(trace_mode)
|
||||
{}
|
||||
|
||||
constexpr V base() const &
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::copy_constructible<V>
|
||||
#endif
|
||||
{
|
||||
return base_;
|
||||
}
|
||||
constexpr V base() && { return std::move(base_); }
|
||||
|
||||
constexpr F const & f() const { return *f_.f_; }
|
||||
|
||||
constexpr auto begin() { return iterator<false>{this}; }
|
||||
constexpr auto end() { return sentinel<false>{}; }
|
||||
|
||||
constexpr auto begin() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return iterator<true>{this};
|
||||
}
|
||||
constexpr auto end() const
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
requires std::ranges::range<const V>
|
||||
#endif
|
||||
{
|
||||
return sentinel<true>{};
|
||||
}
|
||||
|
||||
template<bool Const>
|
||||
struct sentinel
|
||||
{};
|
||||
|
||||
template<bool Const>
|
||||
struct iterator
|
||||
: detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator<Const>,
|
||||
std::forward_iterator_tag,
|
||||
BOOST_PARSER_SUBRANGE<detail::either_iterator<
|
||||
detail::maybe_const<Const, V>,
|
||||
detail::maybe_const<Const, replacement_range>>>>
|
||||
{
|
||||
using I = detail::iterator_t<detail::maybe_const<Const, V>>;
|
||||
using S = detail::sentinel_t<detail::maybe_const<Const, V>>;
|
||||
|
||||
using ref_t_iter = detail::either_iterator<
|
||||
detail::maybe_const<Const, V>,
|
||||
detail::maybe_const<Const, replacement_range>>;
|
||||
using reference_type = BOOST_PARSER_SUBRANGE<ref_t_iter>;
|
||||
|
||||
constexpr iterator() = default;
|
||||
constexpr iterator(
|
||||
detail::maybe_const<Const, transform_replace_view> * parent) :
|
||||
parent_(parent),
|
||||
r_(parent_->base_.begin(), parent_->base_.end()),
|
||||
curr_(r_.begin(), r_.begin()),
|
||||
next_it_(r_.begin()),
|
||||
in_match_(true)
|
||||
{
|
||||
++*this;
|
||||
}
|
||||
|
||||
constexpr iterator & operator++()
|
||||
{
|
||||
if (in_match_) {
|
||||
r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
|
||||
auto new_match_and_attr = detail::attr_search_repack_shim(
|
||||
r_,
|
||||
parent_->parser_,
|
||||
parent_->skip_,
|
||||
parent_->trace_mode_);
|
||||
auto const new_match =
|
||||
parser::get(new_match_and_attr, llong<0>{});
|
||||
parent_->f_(
|
||||
parser::get(std::move(new_match_and_attr), llong<1>{}));
|
||||
if (new_match.begin() == curr_.end()) {
|
||||
curr_ = new_match;
|
||||
} else {
|
||||
curr_ =
|
||||
BOOST_PARSER_SUBRANGE(next_it_, new_match.begin());
|
||||
in_match_ = false;
|
||||
}
|
||||
next_it_ = new_match.end();
|
||||
} else {
|
||||
if (!curr_.empty()) {
|
||||
curr_ = BOOST_PARSER_SUBRANGE(curr_.end(), next_it_);
|
||||
in_match_ = true;
|
||||
}
|
||||
if (curr_.empty())
|
||||
r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reference_type operator*() const
|
||||
{
|
||||
if (in_match_) {
|
||||
return reference_type(
|
||||
ref_t_iter(parent_->f_.get().begin()),
|
||||
ref_t_iter(parent_->f_.get().end()));
|
||||
} else {
|
||||
return reference_type(
|
||||
ref_t_iter(curr_.begin()), ref_t_iter(curr_.end()));
|
||||
}
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(iterator lhs, iterator rhs)
|
||||
{
|
||||
return lhs.r_.begin() == rhs.r_.begin();
|
||||
}
|
||||
friend constexpr bool operator==(iterator it, sentinel<Const>)
|
||||
{
|
||||
return it.r_.begin() == it.r_.end();
|
||||
}
|
||||
|
||||
using base_type = detail::stl_interfaces::proxy_iterator_interface<
|
||||
iterator,
|
||||
std::forward_iterator_tag,
|
||||
reference_type>;
|
||||
using base_type::operator++;
|
||||
|
||||
private:
|
||||
detail::maybe_const<Const, transform_replace_view> * parent_;
|
||||
BOOST_PARSER_SUBRANGE<I, S> r_;
|
||||
BOOST_PARSER_SUBRANGE<I> curr_;
|
||||
I next_it_;
|
||||
bool in_match_;
|
||||
};
|
||||
|
||||
template<bool Const>
|
||||
friend struct iterator;
|
||||
|
||||
private:
|
||||
V base_;
|
||||
F f_;
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> parser_;
|
||||
parser_interface<SkipParser> skip_;
|
||||
trace trace_mode_;
|
||||
};
|
||||
|
||||
// deduction guides
|
||||
template<
|
||||
typename V,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
transform_replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>,
|
||||
F &&,
|
||||
trace)
|
||||
-> transform_replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::remove_cv_ref_t<F>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
transform_replace_view(
|
||||
V &&,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler>,
|
||||
parser_interface<SkipParser>,
|
||||
F &&)
|
||||
-> transform_replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::remove_cv_ref_t<F>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
transform_replace_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&, trace)
|
||||
-> transform_replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::remove_cv_ref_t<F>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
transform_replace_view(
|
||||
V &&, parser_interface<Parser, GlobalState, ErrorHandler>, F &&)
|
||||
-> transform_replace_view<
|
||||
detail::text::detail::all_t<V>,
|
||||
detail::remove_cv_ref_t<F>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>;
|
||||
|
||||
namespace detail {
|
||||
template<
|
||||
typename V,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
using transform_replace_view_expr = decltype(transform_replace_view<
|
||||
V,
|
||||
F,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>(
|
||||
std::declval<V>(),
|
||||
std::declval<
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
|
||||
std::declval<parser_interface<SkipParser> const &>(),
|
||||
std::declval<F>(),
|
||||
trace::on));
|
||||
|
||||
template<
|
||||
typename V,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool can_transform_replace_view = is_detected_v<
|
||||
transform_replace_view_expr,
|
||||
V,
|
||||
F,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>;
|
||||
|
||||
struct transform_replace_impl
|
||||
{
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
std::move_constructible F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
std::regular_invocable<
|
||||
F &,
|
||||
range_attr_t<to_range_t<R>, Parser>> &&
|
||||
// clang-format on
|
||||
can_transform_replace_view<
|
||||
to_range_t<R>,
|
||||
utf_rvalue_shim<
|
||||
to_range_t<R>,
|
||||
std::remove_cvref_t<F>,
|
||||
range_attr_t<to_range_t<R>, Parser>>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F && f,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return transform_replace_view(
|
||||
to_range<R>::call((R &&) r),
|
||||
parser,
|
||||
skip,
|
||||
utf_rvalue_shim<
|
||||
to_range_t<R>,
|
||||
std::remove_cvref_t<F>,
|
||||
range_attr_t<to_range_t<R>, Parser>>((F &&) f),
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
template<
|
||||
parsable_range_like R,
|
||||
std::move_constructible F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler>
|
||||
requires
|
||||
// clang-format off
|
||||
(std::is_pointer_v<std::remove_cvref_t<R>> ||
|
||||
std::ranges::viewable_range<R>) &&
|
||||
std::regular_invocable<
|
||||
F &,
|
||||
range_attr_t<to_range_t<R>, Parser>> &&
|
||||
// clang-format on
|
||||
can_transform_replace_view<
|
||||
to_range_t<R>,
|
||||
utf_rvalue_shim<
|
||||
to_range_t<R>,
|
||||
std::remove_cvref_t<F>,
|
||||
range_attr_t<to_range_t<R>, Parser>>,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
parser_interface<eps_parser<detail::phony>>>
|
||||
// clang-format off
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
F && f,
|
||||
trace trace_mode = trace::off) const
|
||||
// clang-format on
|
||||
{
|
||||
return (*this)(
|
||||
(R &&) r,
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
(F &&) f,
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<
|
||||
typename R,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser,
|
||||
typename F = trace,
|
||||
typename Trace = trace,
|
||||
typename Enable = std::enable_if_t<is_parsable_range_like_v<R>>>
|
||||
[[nodiscard]] constexpr auto operator()(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
SkipParser && skip,
|
||||
F && f = F{},
|
||||
Trace trace_mode = Trace{}) const
|
||||
{
|
||||
if constexpr (
|
||||
is_parser_iface<remove_cv_ref_t<SkipParser>> &&
|
||||
std::is_invocable_v<
|
||||
F &,
|
||||
range_attr_t<to_range_t<R>, Parser>> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, skip, f, trace) case
|
||||
return impl(
|
||||
to_range<R>::call((R &&) r),
|
||||
parser,
|
||||
skip,
|
||||
(F &&) f,
|
||||
trace_mode);
|
||||
} else if constexpr (
|
||||
std::is_invocable_v<
|
||||
SkipParser &,
|
||||
range_attr_t<to_range_t<R>, Parser>> &&
|
||||
std::is_same_v<remove_cv_ref_t<F>, trace> &&
|
||||
std::is_same_v<Trace, trace>) {
|
||||
// (r, parser, f, trace) case
|
||||
return impl(
|
||||
to_range<R>::call((R &&) r),
|
||||
parser,
|
||||
parser_interface<eps_parser<detail::phony>>{},
|
||||
(SkipParser &&) skip,
|
||||
f);
|
||||
} else {
|
||||
static_assert(
|
||||
sizeof(R) == 1 && false,
|
||||
"Only the signatures replace(R, parser, skip, "
|
||||
"replcement trace = trace::off) and replace(R, parser, "
|
||||
"f, trace = trace::off) are supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template<
|
||||
typename R,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
[[nodiscard]] constexpr auto impl(
|
||||
R && r,
|
||||
parser_interface<Parser, GlobalState, ErrorHandler> const &
|
||||
parser,
|
||||
parser_interface<SkipParser> const & skip,
|
||||
F && f,
|
||||
trace trace_mode = trace::off) const
|
||||
{
|
||||
return transform_replace_view(
|
||||
(R &&) r,
|
||||
parser,
|
||||
skip,
|
||||
utf_rvalue_shim<
|
||||
R,
|
||||
remove_cv_ref_t<F>,
|
||||
range_attr_t<R, Parser>>((F &&) f),
|
||||
trace_mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
/** A range adaptor object ([range.adaptor.object]). Given subexpressions
|
||||
`E` and `P`, `Q`, `R`, and 'S', each of the expressions `replace(E,
|
||||
P)`, `replace(E, P, Q)`. `replace(E, P, Q, R)`, and `replace(E, P, Q,
|
||||
R, S)` are expression-equivalent to `replace_view(E, P)`,
|
||||
`replace_view(E, P, Q)`, `replace_view(E, P, Q, R)`, `replace_view(E,
|
||||
P, Q, R, S)`, respectively. */
|
||||
inline constexpr detail::stl_interfaces::adaptor<
|
||||
detail::transform_replace_impl>
|
||||
transform_replace = detail::transform_replace_impl{};
|
||||
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
template<
|
||||
typename V,
|
||||
typename F,
|
||||
typename Parser,
|
||||
typename GlobalState,
|
||||
typename ErrorHandler,
|
||||
typename SkipParser>
|
||||
constexpr bool
|
||||
std::ranges::enable_borrowed_range<boost::parser::transform_replace_view<
|
||||
V,
|
||||
F,
|
||||
Parser,
|
||||
GlobalState,
|
||||
ErrorHandler,
|
||||
SkipParser>> = std::ranges::enable_borrowed_range<V> &&
|
||||
(std::ranges::enable_borrowed_range<F> ||
|
||||
boost::parser::detail::tidy_func<F>);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@ add_executable(parser_ parser.cpp)
|
||||
set_property(TARGET parser_ PROPERTY CXX_STANDARD ${CXX_STD})
|
||||
target_link_libraries(parser_ parser gtest gtest_main ${link_flags})
|
||||
if (MSVC)
|
||||
target_compile_options(parser_ PRIVATE /source-charset:utf-8)
|
||||
target_compile_options(parser_ PRIVATE /source-charset:utf-8 /bigobj)
|
||||
endif ()
|
||||
add_test(NAME parser_ COMMAND parser_ ---gtest_catch_exceptions=1)
|
||||
|
||||
@@ -21,7 +21,7 @@ add_executable(parser_api parser_api.cpp)
|
||||
set_property(TARGET parser_api PROPERTY CXX_STANDARD ${CXX_STD})
|
||||
target_link_libraries(parser_api parser gtest gtest_main ${link_flags})
|
||||
if (MSVC)
|
||||
target_compile_options(parser_api PRIVATE /source-charset:utf-8)
|
||||
target_compile_options(parser_api PRIVATE /source-charset:utf-8 /bigobj)
|
||||
endif ()
|
||||
add_test(NAME parser_api COMMAND parser_api ---gtest_catch_exceptions=1)
|
||||
|
||||
@@ -41,11 +41,17 @@ macro(add_test_executable name)
|
||||
set_property(TARGET ${name} PROPERTY CXX_STANDARD ${CXX_STD})
|
||||
target_link_libraries(${name} parser gtest gtest_main ${link_flags})
|
||||
if (MSVC)
|
||||
target_compile_options(${name} PRIVATE /source-charset:utf-8)
|
||||
target_compile_options(${name} PRIVATE /source-charset:utf-8 /bigobj)
|
||||
endif ()
|
||||
add_test(NAME ${name} COMMAND ${name} --gtest_catch_exceptions=1)
|
||||
endmacro()
|
||||
|
||||
#add_test_executable(quoted_string)
|
||||
add_test_executable(all_t)
|
||||
add_test_executable(search)
|
||||
add_test_executable(split)
|
||||
add_test_executable(replace)
|
||||
add_test_executable(transform_replace)
|
||||
add_test_executable(hl)
|
||||
add_test_executable(aggr_tuple_assignment)
|
||||
add_test_executable(parser_lazy_params)
|
||||
@@ -58,6 +64,8 @@ add_test_executable(parser_symbol_table)
|
||||
add_test_executable(tracing)
|
||||
add_test_executable(parse_empty)
|
||||
add_test_executable(tuple_aggregate)
|
||||
add_test_executable(class_type)
|
||||
add_test_executable(case_fold_generated)
|
||||
add_test_executable(no_case)
|
||||
add_test_executable(merge_separate)
|
||||
add_test_executable(parse_coords_new)
|
||||
|
||||
104
test/all_t.cpp
Normal file
104
test/all_t.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/parser/config.hpp>
|
||||
#include <boost/parser/detail/text/detail/all_t.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
using namespace boost::parser::detail::text;
|
||||
|
||||
TEST(all_t, basic)
|
||||
{
|
||||
std::string str;
|
||||
std::string const const_str;
|
||||
|
||||
{
|
||||
auto && result = detail::all(
|
||||
BOOST_PARSER_SUBRANGE(const_str.begin(), const_str.end()));
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
BOOST_PARSER_SUBRANGE<decltype(const_str.begin())> &&>);
|
||||
}
|
||||
{
|
||||
auto && result = detail::all(str);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(result), detail::ref_view<std::string> &&>);
|
||||
}
|
||||
{
|
||||
auto && result = detail::all(const_str);
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
detail::ref_view<std::string const> &&>);
|
||||
}
|
||||
{
|
||||
auto && result = detail::all(std::string{});
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
detail::owning_view<std::string> &&>);
|
||||
}
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
detail::all_t<BOOST_PARSER_SUBRANGE<decltype(const_str.begin())>>,
|
||||
BOOST_PARSER_SUBRANGE<decltype(const_str.begin())>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
detail::all_t<std::string &>,
|
||||
detail::ref_view<std::string>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
detail::all_t<std::string const &>,
|
||||
detail::ref_view<std::string const>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
detail::all_t<std::string &&>,
|
||||
detail::owning_view<std::string>>);
|
||||
}
|
||||
|
||||
TEST(all_t, array)
|
||||
{
|
||||
char str[] = "text";
|
||||
char const const_str[] = "text";
|
||||
|
||||
static_assert(detail::range_<char[5]>);
|
||||
static_assert(std::is_object_v<char[5]>);
|
||||
detail::ref_view<char[5]> ref_view_(str);
|
||||
{
|
||||
auto && result = detail::all(
|
||||
BOOST_PARSER_SUBRANGE(std::begin(const_str), std::end(const_str)));
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
BOOST_PARSER_SUBRANGE<decltype(std::begin(const_str))> &&>);
|
||||
}
|
||||
{
|
||||
auto && result = detail::all(str);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(result), detail::ref_view<char[5]> &&>);
|
||||
}
|
||||
{
|
||||
auto && result = detail::all(const_str);
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
detail::ref_view<char const[5]> &&>);
|
||||
}
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
detail::all_t<BOOST_PARSER_SUBRANGE<decltype(std::begin(const_str))>>,
|
||||
BOOST_PARSER_SUBRANGE<decltype(std::begin(const_str))>>);
|
||||
|
||||
static_assert(
|
||||
std::
|
||||
is_same_v<detail::all_t<char(&)[5]>, detail::ref_view<char[5]>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
detail::all_t<char const(&)[5]>,
|
||||
detail::ref_view<char const[5]>>);
|
||||
}
|
||||
908
test/class_type.cpp
Normal file
908
test/class_type.cpp
Normal file
@@ -0,0 +1,908 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/parser/parser.hpp>
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
using namespace boost::parser;
|
||||
|
||||
|
||||
TEST(class_type, std_type_from_tuple)
|
||||
{
|
||||
{
|
||||
constexpr auto parser = lexeme[+(char_ - ' ')] >> uint_ >> uint_;
|
||||
std::string out;
|
||||
auto result = parse("something 4 5", parser, ws, out);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(out, "thing");
|
||||
}
|
||||
{
|
||||
constexpr auto p = lexeme[+(char_ - ' ')] >> uint_ >> uint_;
|
||||
constexpr auto parser = +p >> -p;
|
||||
std::vector<std::string> out;
|
||||
auto result = parse("something 4 5 some 0 2", parser, ws, out);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(out.size(), 2u);
|
||||
EXPECT_EQ(out[0], "thing");
|
||||
EXPECT_EQ(out[1], "so");
|
||||
}
|
||||
{
|
||||
constexpr auto p = lexeme[+(char_ - ' ')] >> uint_ >> uint_;
|
||||
constexpr auto parser = -p;
|
||||
std::optional<std::string> out;
|
||||
auto result = parse("something 4 5", parser, ws, out);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(out);
|
||||
EXPECT_EQ(*out, "thing");
|
||||
}
|
||||
{
|
||||
constexpr auto parser = lexeme[+(char_ - ' ')] >> uint_ >> uint_;
|
||||
std::optional<std::string> out;
|
||||
auto result = parse("something 4 5", parser, ws, out);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(out);
|
||||
EXPECT_EQ(*out, "thing");
|
||||
}
|
||||
{
|
||||
constexpr auto parser = uint_ >> char_ >> char_;
|
||||
std::vector<std::string> out;
|
||||
auto result = parse("4 ab", parser, ws, out);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(out, std::vector<std::string>({"ab", "ab", "ab", "ab"}));
|
||||
}
|
||||
}
|
||||
|
||||
struct s0_rule_tag
|
||||
{};
|
||||
struct s1_rule_a_tag
|
||||
{};
|
||||
struct s1_rule_b_tag
|
||||
{};
|
||||
struct s2_rule_a_tag
|
||||
{};
|
||||
struct s2_rule_b_tag
|
||||
{};
|
||||
|
||||
|
||||
struct s0
|
||||
{
|
||||
s0() = default;
|
||||
s0(int i, std::string str, std::vector<int> vec) :
|
||||
i_(i), str_(std::move(str)), vec_(std::move(vec))
|
||||
{}
|
||||
|
||||
int i() const { return i_; }
|
||||
std::string str() const { return str_; }
|
||||
std::vector<int> vec() const { return vec_; }
|
||||
|
||||
private:
|
||||
int i_;
|
||||
std::string str_;
|
||||
std::vector<int> vec_;
|
||||
};
|
||||
|
||||
using s0_tuple = tuple<int, std::string, std::vector<int>>;
|
||||
|
||||
auto s0_parser = "s0" >> int_ >> lexeme[+(char_ - ' ')] >> *int_;
|
||||
|
||||
callback_rule<s0_rule_tag, s0> s0_rule = "s0_rule";
|
||||
auto s0_rule_def = s0_parser;
|
||||
|
||||
struct s1
|
||||
{
|
||||
s1() = default;
|
||||
s1(int i, std::string str, std::vector<int> vec) :
|
||||
i_(i), str_(std::move(str)), vec_(std::move(vec))
|
||||
{}
|
||||
s1(int i, double str, std::vector<int> vec) :
|
||||
i_(i), str_(str), vec_(std::move(vec))
|
||||
{}
|
||||
|
||||
int i() const { return i_; }
|
||||
std::variant<std::string, double> str() const { return str_; }
|
||||
std::vector<int> vec() const { return vec_; }
|
||||
|
||||
private:
|
||||
int i_;
|
||||
std::variant<std::string, double> str_;
|
||||
std::vector<int> vec_;
|
||||
};
|
||||
|
||||
using s1_tuple =
|
||||
tuple<int, std::variant<std::string, double>, std::vector<int>>;
|
||||
|
||||
auto s1_parser_a = "s1" >> int_ >> lexeme[+(char_ - ' ')] >> *int_;
|
||||
auto s1_parser_b = "s1" >> int_ >> double_ >> *int_;
|
||||
|
||||
callback_rule<s1_rule_a_tag, s1> s1_rule_a = "s1_rule_a";
|
||||
callback_rule<s1_rule_b_tag, s1> s1_rule_b = "s1_rule_b";
|
||||
auto s1_rule_a_def = s1_parser_a;
|
||||
auto s1_rule_b_def = s1_parser_b;
|
||||
|
||||
struct s2
|
||||
{
|
||||
s2() = default;
|
||||
s2(int i, std::string str, std::optional<std::vector<int>> vec) :
|
||||
i_(i), str_(std::move(str)), vec_(std::move(vec))
|
||||
{}
|
||||
|
||||
int i() const { return i_; }
|
||||
std::string str() const { return str_; }
|
||||
std::optional<std::vector<int>> vec() const { return vec_; }
|
||||
|
||||
private:
|
||||
int i_;
|
||||
std::string str_;
|
||||
std::optional<std::vector<int>> vec_;
|
||||
};
|
||||
|
||||
using s2_tuple = tuple<int, std::string, std::optional<std::vector<int>>>;
|
||||
|
||||
auto s2_parser_a = "s2" >> int_ >> lexeme[+(char_ - ' ')] >> *int_;
|
||||
auto s2_parser_b = "s2" >> int_ >> lexeme[+(char_ - ' ')] >> -+int_;
|
||||
|
||||
callback_rule<s2_rule_a_tag, s2> s2_rule_a = "s2_rule_a";
|
||||
callback_rule<s2_rule_b_tag, s2> s2_rule_b = "s2_rule_b";
|
||||
auto s2_rule_a_def = s2_parser_a;
|
||||
auto s2_rule_b_def = s2_parser_b;
|
||||
|
||||
BOOST_PARSER_DEFINE_RULES(s0_rule, s1_rule_a, s1_rule_b, s2_rule_a, s2_rule_b);
|
||||
|
||||
|
||||
TEST(class_type, seq_parser_struct_rule)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Parse-generated attribute.
|
||||
|
||||
{
|
||||
std::optional<s0> result = parse("s0 42 text 1 2 3", s0_rule, ws);
|
||||
EXPECT_TRUE(result);
|
||||
s0 & struct_ = *result;
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<s1> const result =
|
||||
parse("s1 42 text 1 2 3", s1_rule_a, ws);
|
||||
EXPECT_TRUE(result);
|
||||
s1 const & struct_ = *result;
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(struct_.str()), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<s1> const result =
|
||||
parse("s1 42 13.0 1 2 3", s1_rule_b, ws);
|
||||
EXPECT_TRUE(result);
|
||||
s1 const & struct_ = *result;
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(struct_.str()), 13.0);
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<s2> const result =
|
||||
parse("s2 42 text 1 2 3", s2_rule_a, ws);
|
||||
EXPECT_TRUE(result);
|
||||
s2 const & struct_ = *result;
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<s2> const result =
|
||||
parse("s2 42 text 1 2 3", s2_rule_b, ws);
|
||||
EXPECT_TRUE(result);
|
||||
s2 const & struct_ = *result;
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
|
||||
// Use the rule as part of a larger parse.
|
||||
{
|
||||
std::optional<tuple<int, s0>> const result =
|
||||
parse("99 s0 42 text 1 2 3", int_ >> s0_rule, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, s1>> const result =
|
||||
parse("99 s1 42 text 1 2 3", int_ >> s1_rule_a, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(struct_.str()), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, s1>> const result =
|
||||
parse("99 s1 42 13.0 1 2 3", int_ >> s1_rule_b, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(struct_.str()), 13.0);
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, s2>> const result =
|
||||
parse("99 s2 42 text 1 2 3", int_ >> s2_rule_a, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, s2>> const result =
|
||||
parse("99 s2 42 text 1 2 3", int_ >> s2_rule_b, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Pass attribute to parse.
|
||||
|
||||
{
|
||||
s0 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s0 42 text 1 2 3", s0_rule, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s1 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s1 42 text 1 2 3", s1_rule_a, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(struct_.str()), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s1 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s1 42 13.0 1 2 3", s1_rule_b, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(struct_.str()), 13.0);
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s2 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s2 42 text 1 2 3", s2_rule_a, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s2 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s2 42 text 1 2 3", s2_rule_b, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
|
||||
// Use the rule as part of a larger parse.
|
||||
{
|
||||
tuple<int, s0> result;
|
||||
|
||||
EXPECT_TRUE(parse("99 s0 42 text 1 2 3", int_ >> s0_rule, ws, result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
tuple<int, s1> result;
|
||||
|
||||
EXPECT_TRUE(parse("99 s1 42 text 1 2 3", int_ >> s1_rule_a, ws, result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(struct_.str()), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
tuple<int, s1> result;
|
||||
|
||||
EXPECT_TRUE(parse("99 s1 42 13.0 1 2 3", int_ >> s1_rule_b, ws, result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(struct_.str()), 13.0);
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
tuple<int, s2> result;
|
||||
|
||||
EXPECT_TRUE(parse("99 s2 42 text 1 2 3", int_ >> s2_rule_a, ws, result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
tuple<int, s2> result;
|
||||
|
||||
EXPECT_TRUE(parse("99 s2 42 text 1 2 3", int_ >> s2_rule_b, ws, result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto struct_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(class_type, repeated_seq_parser_struct_rule)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Parse-generated attribute.
|
||||
|
||||
{
|
||||
std::optional<std::vector<s0>> result =
|
||||
parse("s0 42 text 1 2 3 s0 41 texty 1 3 2", *s0_rule, ws);
|
||||
EXPECT_TRUE(result);
|
||||
std::vector<s0> & structs_ = *result;
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<std::vector<s1>> const result =
|
||||
parse("s1 42 text 1 2 3 s1 41 texty 1 3 2", *s1_rule_a, ws);
|
||||
EXPECT_TRUE(result);
|
||||
std::vector<s1> const & structs_ = *result;
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[0].str()), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[1].str()), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<std::vector<s1>> const result =
|
||||
parse("s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", *s1_rule_b, ws);
|
||||
EXPECT_TRUE(result);
|
||||
std::vector<s1> const & structs_ = *result;
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[0].str()), 13.0);
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[1].str()), 12.0);
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<std::vector<s2>> const result =
|
||||
parse("s2 42 text 1 2 3 s2 41 texty 1 3 2", *s2_rule_a, ws);
|
||||
EXPECT_TRUE(result);
|
||||
std::vector<s2> const & structs_ = *result;
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<std::vector<s2>> const result =
|
||||
parse("s2 42 text 1 2 3 s2 41 texty 1 3 2", *s2_rule_b, ws);
|
||||
EXPECT_TRUE(result);
|
||||
std::vector<s2> const & structs_ = *result;
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
|
||||
// Use the rule as part of a larger parse.
|
||||
{
|
||||
std::optional<tuple<int, std::vector<s0>>> const result =
|
||||
parse("99 s0 42 text 1 2 3 s0 41 texty 1 3 2", int_ >> *s0_rule, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, std::vector<s1>>> const result =
|
||||
parse("99 s1 42 text 1 2 3 s1 41 texty 1 3 2", int_ >> *s1_rule_a, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[0].str()), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[1].str()), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, std::vector<s1>>> const result =
|
||||
parse("99 s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", int_ >> *s1_rule_b, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[0].str()), 13.0);
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[1].str()), 12.0);
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, std::vector<s2>>> const result =
|
||||
parse("99 s2 42 text 1 2 3 s2 41 texty 1 3 2", int_ >> *s2_rule_a, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::optional<tuple<int, std::vector<s2>>> const result =
|
||||
parse("99 s2 42 text 1 2 3 s2 41 texty 1 3 2", int_ >> *s2_rule_b, ws);
|
||||
auto i_ = get(*result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(*result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Pass attribute to parse.
|
||||
|
||||
{
|
||||
std::vector<s0> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s0 42 text 1 2 3 s0 41 texty 1 3 2", *s0_rule, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s1> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s1 42 text 1 2 3 s1 41 texty 1 3 2", *s1_rule_a, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[0].str()), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[1].str()), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s1> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", *s1_rule_b, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[0].str()), 13.0);
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[1].str()), 12.0);
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s2> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s2 42 text 1 2 3 s2 41 texty 1 3 2", *s2_rule_a, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s2> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s2 42 text 1 2 3 s2 41 texty 1 3 2", *s2_rule_b, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
|
||||
// Use the rule as part of a larger parse.
|
||||
{
|
||||
tuple<int, std::vector<s0>> result;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"99 s0 42 text 1 2 3 s0 41 texty 1 3 2",
|
||||
int_ >> *s0_rule,
|
||||
ws,
|
||||
result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
tuple<int, std::vector<s1>> result;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"99 s1 42 text 1 2 3 s1 41 texty 1 3 2",
|
||||
int_ >> *s1_rule_a,
|
||||
ws,
|
||||
result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[0].str()), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[1].str()), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
tuple<int, std::vector<s1>> result;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"99 s1 42 13.0 1 2 3 s1 41 12.0 1 3 2",
|
||||
int_ >> *s1_rule_b,
|
||||
ws,
|
||||
result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[0].str()), 13.0);
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[1].str()), 12.0);
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
tuple<int, std::vector<s2>> result;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"99 s2 42 text 1 2 3 s2 41 texty 1 3 2",
|
||||
int_ >> *s2_rule_a,
|
||||
ws,
|
||||
result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
tuple<int, std::vector<s2>> result;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"99 s2 42 text 1 2 3 s2 41 texty 1 3 2",
|
||||
int_ >> *s2_rule_b,
|
||||
ws,
|
||||
result));
|
||||
auto i_ = get(result, llong<0>{});
|
||||
EXPECT_EQ(i_, 99);
|
||||
auto structs_ = get(result, llong<1>{});
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
}
|
||||
|
||||
struct callbacks_t
|
||||
{
|
||||
void operator()(s0_rule_tag, s0 s) const { s0s.push_back(std::move(s)); }
|
||||
void operator()(s1_rule_a_tag, s1 s) const { s1s.push_back(std::move(s)); }
|
||||
void operator()(s1_rule_b_tag, s1 s) const { s1s.push_back(std::move(s)); }
|
||||
void operator()(s2_rule_a_tag, s2 s) const { s2s.push_back(std::move(s)); }
|
||||
void operator()(s2_rule_b_tag, s2 s) const { s2s.push_back(std::move(s)); }
|
||||
|
||||
mutable std::vector<s0> s0s;
|
||||
mutable std::vector<s1> s1s;
|
||||
mutable std::vector<s2> s2s;
|
||||
};
|
||||
|
||||
TEST(class_type, seq_parser_struct_cb_rule)
|
||||
{
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse("s0 42 text 1 2 3", s0_rule, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s0s.size(), 1u);
|
||||
s0 const & struct_ = callbacks.s0s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse("s1 42 text 1 2 3", s1_rule_a, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s1s.size(), 1u);
|
||||
s1 const & struct_ = callbacks.s1s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(struct_.str()), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse("s1 42 13.0 1 2 3", s1_rule_b, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s1s.size(), 1u);
|
||||
s1 const & struct_ = callbacks.s1s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(struct_.str()), 13.0);
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse("s2 42 text 1 2 3", s2_rule_a, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s2s.size(), 1u);
|
||||
s2 const & struct_ = callbacks.s2s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse("s2 42 text 1 2 3", s2_rule_b, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s2s.size(), 1u);
|
||||
s2 const & struct_ = callbacks.s2s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
|
||||
// Use the rule as part of a larger parse.
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse(
|
||||
"99 s0 42 text 1 2 3", int_ >> s0_rule, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s0s.size(), 1u);
|
||||
s0 const & struct_ = callbacks.s0s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse(
|
||||
"99 s1 42 text 1 2 3", int_ >> s1_rule_a, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s1s.size(), 1u);
|
||||
s1 const & struct_ = callbacks.s1s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(struct_.str()), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse(
|
||||
"99 s1 42 13.0 1 2 3", int_ >> s1_rule_b, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s1s.size(), 1u);
|
||||
s1 const & struct_ = callbacks.s1s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(struct_.str()), 13.0);
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse(
|
||||
"99 s2 42 text 1 2 3", int_ >> s2_rule_a, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s2s.size(), 1u);
|
||||
s2 const & struct_ = callbacks.s2s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
callbacks_t callbacks;
|
||||
EXPECT_TRUE(callback_parse(
|
||||
"99 s2 42 text 1 2 3", int_ >> s2_rule_b, ws, callbacks));
|
||||
EXPECT_EQ(callbacks.s2s.size(), 1u);
|
||||
s2 const & struct_ = callbacks.s2s[0];
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(class_type, parse_into_struct)
|
||||
{
|
||||
{
|
||||
s0 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s0 42 text 1 2 3", s0_parser, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s1 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s1 42 text 1 2 3", s1_parser_a, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(struct_.str()), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s1 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s1 42 13.0 1 2 3", s1_parser_b, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(struct_.str()), 13.0);
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s2 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s2 42 text 1 2 3", s2_parser_a, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
{
|
||||
s2 struct_;
|
||||
|
||||
EXPECT_TRUE(parse("s2 42 text 1 2 3", s2_parser_b, ws, struct_));
|
||||
EXPECT_EQ(struct_.i(), 42);
|
||||
EXPECT_EQ(struct_.str(), "text");
|
||||
EXPECT_EQ(struct_.vec(), std::vector<int>({1, 2, 3}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(class_type, repeated_parse_into_struct)
|
||||
{
|
||||
{
|
||||
std::vector<s0> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s0 42 text 1 2 3 s0 41 texty 1 3 2", *s0_parser, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s1> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s1 42 text 1 2 3 s1 41 texty 1 3 2", *s1_parser_a, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[0].str()), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 0u);
|
||||
EXPECT_EQ(std::get<0>(structs_[1].str()), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s1> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s1 42 13.0 1 2 3 s1 41 12.0 1 3 2", *s1_parser_b, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[0].str()), 13.0);
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str().index(), 1u);
|
||||
EXPECT_EQ(std::get<1>(structs_[1].str()), 12.0);
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s2> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s2 42 text 1 2 3 s2 41 texty 1 3 2", *s2_parser_a, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
{
|
||||
std::vector<s2> structs_;
|
||||
|
||||
EXPECT_TRUE(parse(
|
||||
"s2 42 text 1 2 3 s2 41 texty 1 3 2", *s2_parser_b, ws, structs_));
|
||||
EXPECT_EQ(structs_[0].i(), 42);
|
||||
EXPECT_EQ(structs_[0].str(), "text");
|
||||
EXPECT_EQ(structs_[0].vec(), std::vector<int>({1, 2, 3}));
|
||||
EXPECT_EQ(structs_[1].i(), 41);
|
||||
EXPECT_EQ(structs_[1].str(), "texty");
|
||||
EXPECT_EQ(structs_[1].vec(), std::vector<int>({1, 3, 2}));
|
||||
}
|
||||
}
|
||||
@@ -297,13 +297,13 @@ void compile_attribute_unicode_utf32()
|
||||
[[maybe_unused]] rule<class test_rule, std::string> const test_rule =
|
||||
"test_rule";
|
||||
auto const test_rule_def = +char_;
|
||||
BOOST_PARSER_DEFINE_RULE(test_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(test_rule);
|
||||
|
||||
[[maybe_unused]] rule<class ints, std::vector<int>> const ints = "ints";
|
||||
auto twenty_zeros = [](auto & ctx) { _val(ctx).resize(20, 0); };
|
||||
auto push_back = [](auto & ctx) { _val(ctx).push_back(_attr(ctx)); };
|
||||
auto const ints_def = lit("20-zeros")[twenty_zeros] | +int_[push_back];
|
||||
BOOST_PARSER_DEFINE_RULE(ints);
|
||||
BOOST_PARSER_DEFINE_RULES(ints);
|
||||
|
||||
void compile_attribute_sentinel()
|
||||
{
|
||||
|
||||
@@ -213,6 +213,18 @@ void compile_seq_attribute()
|
||||
static_assert(
|
||||
std::is_same_v<attr_t, std::optional<std::vector<std::string>>>);
|
||||
}
|
||||
{
|
||||
constexpr auto parser = *(char_ - "str") >> eps >> *string("str");
|
||||
using attr_t = decltype(prefix_parse(first, last, parser));
|
||||
static_assert(
|
||||
std::is_same_v<attr_t, std::optional<std::vector<std::string>>>);
|
||||
}
|
||||
{
|
||||
constexpr auto parser = *(char_ >> eps) >> eps >> *string("str");
|
||||
using attr_t = decltype(prefix_parse(first, last, parser));
|
||||
static_assert(
|
||||
std::is_same_v<attr_t, std::optional<std::vector<std::string>>>);
|
||||
}
|
||||
{
|
||||
constexpr auto parser = *char_ >> eps >> *string("str");
|
||||
using attr_t = decltype(prefix_parse(first, last, parser));
|
||||
|
||||
@@ -208,8 +208,7 @@ TEST(merge_separate, merge_)
|
||||
*result, detail::hl::make_tuple('z', std::string("abcdefghi")));
|
||||
}
|
||||
}
|
||||
#if 0 // TODO: Document that this does not work, and why (flattening), and how
|
||||
// making a rule for the parethesized part is a fix.
|
||||
#if 0 // Intentionally ill-formed.
|
||||
{
|
||||
constexpr auto parser =
|
||||
char_ >> merge[(string("abc") >> char_ >> char_) >> string("ghi")];
|
||||
|
||||
@@ -125,9 +125,10 @@ TEST(no_case, match_any_within_string)
|
||||
EXPECT_TRUE(*result == U's');
|
||||
}
|
||||
{
|
||||
// Non-Unicode parsing fails to match, since 'ß' is not treated as a
|
||||
// single character.
|
||||
auto const result = parse("s", _trasse_p);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, 's');
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
{
|
||||
auto const result = parse(U"S", _trasse_p);
|
||||
@@ -136,8 +137,7 @@ TEST(no_case, match_any_within_string)
|
||||
}
|
||||
{
|
||||
auto const result = parse("S", _trasse_p);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, 'S');
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
{
|
||||
auto const result = parse(U"t", _trasse_p);
|
||||
@@ -159,6 +159,10 @@ TEST(no_case, match_any_within_string)
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, 'T');
|
||||
}
|
||||
{
|
||||
auto const result = parse("X", _trasse_p);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto capital_sharp_s = u8"ẞ"; // U+1E9E
|
||||
@@ -304,6 +308,51 @@ TEST(no_case, detail_no_case_iter)
|
||||
EXPECT_EQ(folded, "sss");
|
||||
EXPECT_TRUE(first.base() == detail::text::null_sentinel);
|
||||
}
|
||||
{
|
||||
auto const street = U"Straße";
|
||||
std::string folded;
|
||||
auto const first_const =
|
||||
detail::no_case_iter(street, detail::text::null_sentinel);
|
||||
auto first = first_const;
|
||||
while (first != detail::text::null_sentinel) {
|
||||
folded.push_back(*first);
|
||||
++first;
|
||||
}
|
||||
EXPECT_EQ(folded, "strasse");
|
||||
EXPECT_TRUE(first.base() == detail::text::null_sentinel);
|
||||
|
||||
first = first_const;
|
||||
std::u32string_view const sv = U"strasse";
|
||||
auto mismatches = detail::text::mismatch(
|
||||
first, detail::text::null_sentinel, sv.begin(), sv.end());
|
||||
EXPECT_TRUE(mismatches.first == detail::text::null_sentinel);
|
||||
EXPECT_TRUE(mismatches.second == sv.end());
|
||||
|
||||
{
|
||||
first = first_const;
|
||||
auto search_result = detail::text::search(
|
||||
first, detail::text::null_sentinel, sv.begin(), sv.end());
|
||||
EXPECT_TRUE(search_result.begin() == first);
|
||||
EXPECT_TRUE(search_result.end() == detail::text::null_sentinel);
|
||||
}
|
||||
|
||||
{
|
||||
first = first_const;
|
||||
auto search_result = detail::text::search(
|
||||
sv.begin(), sv.end(), first, detail::text::null_sentinel);
|
||||
EXPECT_TRUE(search_result.begin() == sv.begin());
|
||||
EXPECT_TRUE(search_result.end() == sv.end());
|
||||
}
|
||||
|
||||
{
|
||||
detail::case_fold_array_t folded_char;
|
||||
auto folded_last = detail::case_fold('X', folded_char.begin());
|
||||
auto search_result = detail::text::search(
|
||||
sv.begin(), sv.end(), folded_char.begin(), folded_last);
|
||||
EXPECT_TRUE(search_result.begin() == sv.end());
|
||||
EXPECT_TRUE(search_result.end() == sv.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(no_case, detail_no_case_mismatch)
|
||||
|
||||
194
test/parse_coords_new.cpp
Normal file
194
test/parse_coords_new.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Copyright (C) 2024 Phil Endecott
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
|
||||
#include "boost/parser/parser.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
using namespace boost::hana::literals;
|
||||
|
||||
namespace g2d {
|
||||
struct Vector
|
||||
{
|
||||
double x, y;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & os, Vector vec)
|
||||
{
|
||||
os << "vec{" << vec.x << ", " << vec.y << "}";
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bp::rule<struct uint_0_60, unsigned int> uint_0_60 = "uint_0_60";
|
||||
bp::rule<struct double_0_60, double> double_0_60 = "double_0_60";
|
||||
bp::rule<struct degrees_decimal_minutes, double> degrees_decimal_minutes = "degrees_decimal_minutes";
|
||||
bp::rule<struct degrees_minutes_seconds, double> degrees_minutes_seconds = "degrees_minutes_seconds";
|
||||
bp::rule<struct degrees, double> degrees = "degrees";
|
||||
bp::rule<struct latitude, double> latitude = "latitude";
|
||||
bp::rule<struct longitude, double> longitude = "longitude";
|
||||
bp::rule<struct signed_latitude, double> signed_latitude = "signed_latitude";
|
||||
bp::rule<struct signed_longitude, double> signed_longitude = "signed_longitude";
|
||||
bp::rule<struct latlon, g2d::Vector> latlon = "latlon";
|
||||
|
||||
|
||||
const auto degrees_symbol = bp::no_case[ bp::lit("degrees") | bp::lit("deg") | bp::lit('d') ];
|
||||
const auto minutes_symbol = bp::no_case[ bp::lit('\'') | bp::lit("minutes") | bp::lit("min") | bp::lit('m') ];
|
||||
const auto seconds_symbol = bp::no_case[ bp::lit('"') | bp::lit("seconds") | bp::lit("sec") | bp::lit('s') ];
|
||||
|
||||
const auto uint_0_60_def = bp::uint_ [( [](auto ctx) { _pass(ctx) = _attr(ctx) < 60U; _val(ctx) = _attr(ctx); } )];
|
||||
const auto double_0_60_def = bp::double_ [( [](auto ctx) { _pass(ctx) = _attr(ctx) < 60; _val(ctx) = _attr(ctx); } )];
|
||||
|
||||
const auto decimal_degrees = bp::double_ >> -degrees_symbol;
|
||||
|
||||
const auto degrees_decimal_minutes_def = (bp::uint_ >> -degrees_symbol
|
||||
>> (double_0_60 - '.') >> -minutes_symbol) [( [](auto ctx) {
|
||||
auto d = _attr(ctx)[0_c];
|
||||
auto m = _attr(ctx)[1_c];
|
||||
_val(ctx) = d + m/60.0;
|
||||
} )];
|
||||
|
||||
const auto degrees_minutes_seconds_def = (bp::uint_ >> -degrees_symbol
|
||||
>> uint_0_60 >> -minutes_symbol
|
||||
>> (double_0_60 - '.') >> -seconds_symbol) [( [](auto ctx) {
|
||||
auto d = _attr(ctx)[0_c];
|
||||
auto m = _attr(ctx)[1_c];
|
||||
auto s = _attr(ctx)[2_c];
|
||||
_val(ctx) = d + m/60.0 + s/3600.0;
|
||||
} )];
|
||||
|
||||
const auto degrees_def = degrees_minutes_seconds
|
||||
| degrees_decimal_minutes
|
||||
| decimal_degrees;
|
||||
|
||||
const auto northsouth = bp::no_case[ bp::char_("ns") ];
|
||||
const auto eastwest = bp::no_case[ bp::char_("ew") ];
|
||||
|
||||
const auto latitude_def = (degrees >> northsouth) [( [](auto ctx) {
|
||||
auto d = _attr(ctx)[0_c];
|
||||
auto ns = _attr(ctx)[1_c];
|
||||
_pass(ctx) = d <= 90;
|
||||
_val(ctx) = ns=='S' || ns=='s' ? -d : d;
|
||||
} )];
|
||||
|
||||
const auto longitude_def = (degrees >> eastwest) [( [](auto ctx) {
|
||||
auto d = _attr(ctx)[0_c];
|
||||
auto ew = _attr(ctx)[1_c];
|
||||
_pass(ctx) = d <= 180;
|
||||
_val(ctx) = ew=='W' || ew=='w' ? -d : d;
|
||||
} )];
|
||||
|
||||
const auto signed_degrees = bp::double_ >> -degrees_symbol;
|
||||
|
||||
const auto signed_latitude_def = signed_degrees [( [](auto ctx) { auto d = _attr(ctx); _pass(ctx) = -90 <= d && d <= 90; _val(ctx) = _attr(ctx); } )];
|
||||
const auto signed_longitude_def = signed_degrees [( [](auto ctx) { auto d = _attr(ctx); _pass(ctx) = -180 <= d && d <= 180; _val(ctx) = _attr(ctx); } )];
|
||||
|
||||
const auto latlon_def = ((latitude >> longitude) [( [](auto ctx) { _val(ctx) = g2d::Vector{_attr(ctx)[1_c], _attr(ctx)[0_c]}; } )] )
|
||||
| ((longitude >> latitude) [( [](auto ctx) { _val(ctx) = g2d::Vector{_attr(ctx)[0_c], _attr(ctx)[1_c]}; } )] )
|
||||
| ((signed_longitude >> signed_latitude)
|
||||
[( [](auto ctx) { _val(ctx) = g2d::Vector{_attr(ctx)[0_c], _attr(ctx)[1_c]}; } )] );
|
||||
|
||||
BOOST_PARSER_DEFINE_RULES(uint_0_60);
|
||||
BOOST_PARSER_DEFINE_RULES(double_0_60);
|
||||
BOOST_PARSER_DEFINE_RULES(degrees_decimal_minutes);
|
||||
BOOST_PARSER_DEFINE_RULES(degrees_minutes_seconds);
|
||||
BOOST_PARSER_DEFINE_RULES(degrees);
|
||||
BOOST_PARSER_DEFINE_RULES(latitude);
|
||||
BOOST_PARSER_DEFINE_RULES(longitude);
|
||||
BOOST_PARSER_DEFINE_RULES(signed_latitude);
|
||||
BOOST_PARSER_DEFINE_RULES(signed_longitude);
|
||||
BOOST_PARSER_DEFINE_RULES(latlon);
|
||||
|
||||
|
||||
#if 0
|
||||
static std::optional<g2d::Vector> try_parse_latlon(std::string_view s)
|
||||
{
|
||||
auto input = latlon >> bp::eoi;
|
||||
return parse(s,input, bp::ws|bp::lit(','));
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
assert(argc==2);
|
||||
|
||||
auto opt_coords = try_parse_latlon(argv[1]);
|
||||
|
||||
if (!opt_coords) {
|
||||
std::cerr << "parse error\n";
|
||||
return 1;
|
||||
} else {
|
||||
std::cout << opt_coords->x << " " << opt_coords->y << "\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(parse_coords, all_examples)
|
||||
{
|
||||
std::vector<std::string> test_coords = {
|
||||
"12.34 N, 56.78 E",
|
||||
"56.78,-12.34",
|
||||
"12d 30' n 45d 15' 7\" w",
|
||||
"12 30 45 N, 45 15 7 W",
|
||||
"12d 30m 15s S 50d 59m 59s W",
|
||||
"50d 0.5m n 50d 59m 59s W"};
|
||||
|
||||
{
|
||||
auto result = bp::parse(test_coords[0], latlon, bp::ws | bp::lit(','));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_LT(std::abs(result->x - 56.78), 0.001);
|
||||
EXPECT_LT(std::abs(result->y - 12.34), 0.001);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(test_coords[1], latlon, bp::ws | bp::lit(','));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_LT(std::abs(result->x - 56.78), 0.001);
|
||||
EXPECT_LT(std::abs(result->y - -12.34), 0.001);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(test_coords[2], latlon, bp::ws | bp::lit(','));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_LT(std::abs(result->x - -45.2519), 0.001);
|
||||
EXPECT_LT(std::abs(result->y - 12.5), 0.001);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(test_coords[3], latlon, bp::ws | bp::lit(','));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_LT(std::abs(result->x - -45.2519), 0.001);
|
||||
EXPECT_LT(std::abs(result->y - 12.5125), 0.001);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(test_coords[4], latlon, bp::ws | bp::lit(','));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_LT(std::abs(result->x - -50.9997), 0.001);
|
||||
EXPECT_LT(std::abs(result->y - -12.5042), 0.001);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(test_coords[5], latlon, bp::ws | bp::lit(','));
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_LT(std::abs(result->x - -50.9997), 0.001);
|
||||
EXPECT_LT(std::abs(result->y - 50.0083), 0.001);
|
||||
}
|
||||
}
|
||||
668
test/parser.cpp
668
test/parser.cpp
@@ -21,6 +21,172 @@
|
||||
|
||||
using namespace boost::parser;
|
||||
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS && defined(_MSC_VER)
|
||||
#include <algorithm>
|
||||
|
||||
TEST(parser, msvc_string_view)
|
||||
{
|
||||
std::string_view sv = "text";
|
||||
std::wstring_view wsv = L"text";
|
||||
|
||||
{
|
||||
auto r = detail::text::as_utf8(sv);
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = detail::text::as_utf8(wsv);
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
{
|
||||
auto r = sv | detail::text::as_utf8;
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = wsv | detail::text::as_utf8;
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = detail::text::as_utf16(sv);
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = detail::text::as_utf16(wsv);
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
{
|
||||
auto r = sv | detail::text::as_utf16;
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = wsv | detail::text::as_utf16;
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = detail::text::as_utf32(sv);
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = detail::text::as_utf32(wsv);
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
{
|
||||
auto r = sv | detail::text::as_utf32;
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = wsv | detail::text::as_utf32;
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, msvc_string)
|
||||
{
|
||||
std::string sv = "text";
|
||||
std::wstring wsv = L"text";
|
||||
|
||||
{
|
||||
auto r = detail::text::as_utf8(sv);
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = detail::text::as_utf8(wsv);
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
{
|
||||
auto r = sv | detail::text::as_utf8;
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = wsv | detail::text::as_utf8;
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = detail::text::as_utf16(sv);
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = detail::text::as_utf16(wsv);
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
{
|
||||
auto r = sv | detail::text::as_utf16;
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = wsv | detail::text::as_utf16;
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
|
||||
{
|
||||
auto r = detail::text::as_utf32(sv);
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = detail::text::as_utf32(wsv);
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
{
|
||||
auto r = sv | detail::text::as_utf32;
|
||||
std::string str = " ";
|
||||
std::ranges::copy(r, str.begin());
|
||||
EXPECT_EQ(str, sv);
|
||||
}
|
||||
{
|
||||
auto r = wsv | detail::text::as_utf32;
|
||||
std::wstring wstr = L" ";
|
||||
std::ranges::copy(r, wstr.begin());
|
||||
EXPECT_EQ(wstr, wsv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TEST_BOOST_OPTIONAL
|
||||
template<typename T>
|
||||
constexpr bool boost::parser::enable_optional<boost::optional<T>> = true;
|
||||
@@ -71,10 +237,8 @@ TEST(parser, basic)
|
||||
}
|
||||
{
|
||||
std::string str = " ";
|
||||
char c = '\0';
|
||||
EXPECT_TRUE(parse(str, ascii::blank, c));
|
||||
EXPECT_EQ(c, ' ');
|
||||
EXPECT_FALSE(parse(str, ascii::lower));
|
||||
EXPECT_TRUE(parse(str, blank));
|
||||
EXPECT_FALSE(parse(str, lower));
|
||||
}
|
||||
{
|
||||
std::string str = "ab";
|
||||
@@ -189,6 +353,15 @@ TEST(parser, basic)
|
||||
EXPECT_EQ(c, boost::none);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
constexpr auto parser = *(char_ - "str") >> *string("str");
|
||||
std::string str = "somethingstrstrstr";
|
||||
auto result = boost::parser::parse(str, parser);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(
|
||||
*result,
|
||||
std::vector<std::string>({"something", "str", "str", "str"}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, int_uint)
|
||||
@@ -209,7 +382,7 @@ TEST(parser, int_uint)
|
||||
std::string str = "-42";
|
||||
int i = 3;
|
||||
EXPECT_FALSE(parse(str, uint_, i));
|
||||
EXPECT_EQ(i, 3);
|
||||
EXPECT_EQ(i, 0);
|
||||
}
|
||||
{
|
||||
std::string str = "42";
|
||||
@@ -790,6 +963,18 @@ TEST(parser, repeat)
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
constexpr auto parser = *char_ >> eps >> *string("str");
|
||||
auto result = parse("abcdefg", parser);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, std::vector<std::string>({"abcdefg"}));
|
||||
}
|
||||
{
|
||||
constexpr auto parser = *(char_ - "str") >> eps >> *string("str");
|
||||
auto result = parse("abcdefgstrstr", parser);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, std::vector<std::string>({"abcdefg", "str", "str"}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, raw)
|
||||
@@ -810,8 +995,7 @@ TEST(parser, raw)
|
||||
std::string const str = "z";
|
||||
range_t r;
|
||||
EXPECT_FALSE(parse(str, parser, r));
|
||||
EXPECT_EQ(r.begin(), str.begin());
|
||||
EXPECT_EQ(r.end(), str.begin());
|
||||
EXPECT_EQ(r.begin(), r.end());
|
||||
}
|
||||
{
|
||||
std::string const str = "z";
|
||||
@@ -966,7 +1150,6 @@ TEST(parser, string_view)
|
||||
EXPECT_TRUE(prefix_parse(first, str.end(), parser, r));
|
||||
EXPECT_TRUE(r == U"");
|
||||
}
|
||||
#if 0 // TODO Odd failure on MSVC.
|
||||
{
|
||||
std::u32string const str = U"zs";
|
||||
range_t r;
|
||||
@@ -979,7 +1162,6 @@ TEST(parser, string_view)
|
||||
EXPECT_TRUE(parse(str, parser, r));
|
||||
EXPECT_TRUE(r == U"zszs");
|
||||
}
|
||||
#endif
|
||||
{
|
||||
std::u32string const str = U"";
|
||||
std::optional<range_t> result = parse(str, parser);
|
||||
@@ -999,7 +1181,6 @@ TEST(parser, string_view)
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(*result == U"");
|
||||
}
|
||||
#if 0 // TODO: Same as above.
|
||||
{
|
||||
std::u32string const str = U"zs";
|
||||
std::optional<range_t> result = parse(str, parser);
|
||||
@@ -1012,7 +1193,6 @@ TEST(parser, string_view)
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(*result == U"zszs");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1088,7 +1268,7 @@ TEST(parser, delimited)
|
||||
{
|
||||
std::vector<std::string> chars;
|
||||
EXPECT_FALSE(parse(str, parser, chars));
|
||||
EXPECT_EQ(chars, std::vector<std::string>({"yay"}));
|
||||
EXPECT_EQ(chars, std::vector<std::string>{});
|
||||
}
|
||||
{
|
||||
std::vector<std::string> chars;
|
||||
@@ -1470,6 +1650,91 @@ TEST(parser, delimited)
|
||||
EXPECT_EQ(*chars, std::vector<std::string>({"yay", "yay", "yay"}));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto yay = string("yay") % ',';
|
||||
constexpr auto aww = string("aww") % ',';
|
||||
constexpr auto parser = yay >> ',' >> aww;
|
||||
|
||||
{
|
||||
std::string str = "yay, yay, yay, aww, aww";
|
||||
auto result = parse(str, parser, ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(
|
||||
*result,
|
||||
(tuple<std::vector<std::string>, std::vector<std::string>>(
|
||||
std::vector<std::string>({"yay", "yay", "yay"}),
|
||||
std::vector<std::string>({"aww", "aww"}))));
|
||||
}
|
||||
{
|
||||
std::string str = "yay, yay, yay , aww, aww";
|
||||
auto result = parse(str, parser, ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(
|
||||
*result,
|
||||
(tuple<std::vector<std::string>, std::vector<std::string>>(
|
||||
std::vector<std::string>({"yay", "yay", "yay"}),
|
||||
std::vector<std::string>({"aww", "aww"}))));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto yay = string("yay") % ',';
|
||||
constexpr auto aww = string("aww") % ',';
|
||||
constexpr auto parser = raw[yay] >> ',' >> raw[aww];
|
||||
|
||||
{
|
||||
std::string str = "yay, yay, yay, aww, aww";
|
||||
auto result = parse(str, parser, ws);
|
||||
EXPECT_TRUE(result);
|
||||
auto subrange_0 = boost::parser::get(*result, llong<0>{});
|
||||
auto subrange_1 = boost::parser::get(*result, llong<1>{});
|
||||
EXPECT_EQ(subrange_0.begin(), str.begin());
|
||||
EXPECT_EQ(subrange_0.end(), str.begin() + 13);
|
||||
EXPECT_EQ(subrange_1.begin(), str.begin() + 15);
|
||||
EXPECT_EQ(subrange_1.end(), str.begin() + 23);
|
||||
}
|
||||
{
|
||||
std::string str = "yay, yay, yay , aww, aww";
|
||||
auto result = parse(str, parser, ws);
|
||||
EXPECT_TRUE(result);
|
||||
auto subrange_0 = boost::parser::get(*result, llong<0>{});
|
||||
auto subrange_1 = boost::parser::get(*result, llong<1>{});
|
||||
EXPECT_EQ(subrange_0.begin(), str.begin());
|
||||
EXPECT_EQ(subrange_0.end(), str.begin() + 13);
|
||||
EXPECT_EQ(subrange_1.begin(), str.begin() + 16);
|
||||
EXPECT_EQ(subrange_1.end(), str.begin() + 24);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto yay = *string("yay");
|
||||
constexpr auto aww = *string("aww");
|
||||
constexpr auto parser = raw[yay] >> ',' >> raw[aww];
|
||||
|
||||
{
|
||||
std::string str = "yay yay yay, aww aww";
|
||||
auto result = parse(str, parser, ws);
|
||||
EXPECT_TRUE(result);
|
||||
auto subrange_0 = boost::parser::get(*result, llong<0>{});
|
||||
auto subrange_1 = boost::parser::get(*result, llong<1>{});
|
||||
EXPECT_EQ(subrange_0.begin(), str.begin());
|
||||
EXPECT_EQ(subrange_0.end(), str.begin() + 11);
|
||||
EXPECT_EQ(subrange_1.begin(), str.begin() + 13);
|
||||
EXPECT_EQ(subrange_1.end(), str.begin() + 20);
|
||||
}
|
||||
{
|
||||
std::string str = "yay yay yay , aww aww";
|
||||
auto result = parse(str, parser, ws);
|
||||
EXPECT_TRUE(result);
|
||||
auto subrange_0 = boost::parser::get(*result, llong<0>{});
|
||||
auto subrange_1 = boost::parser::get(*result, llong<1>{});
|
||||
EXPECT_EQ(subrange_0.begin(), str.begin());
|
||||
EXPECT_EQ(subrange_0.end(), str.begin() + 11);
|
||||
EXPECT_EQ(subrange_1.begin(), str.begin() + 14);
|
||||
EXPECT_EQ(subrange_1.end(), str.begin() + 21);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, lexeme)
|
||||
@@ -1587,6 +1852,99 @@ TEST(parser, lexeme)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const parser = string("abc");
|
||||
|
||||
// Follows the parser used in transform_replace().
|
||||
auto before = [&](auto & ctx) {};
|
||||
auto after = [&](auto & ctx) {};
|
||||
auto const search_parser =
|
||||
omit[*(char_ - parser)] >>
|
||||
-lexeme[eps[before] >> skip[parser] >> eps[after]];
|
||||
|
||||
{
|
||||
std::string str = "abc";
|
||||
std::optional<std::string> result;
|
||||
EXPECT_TRUE(parse(str, search_parser, char_(' '), result));
|
||||
EXPECT_EQ(*result, "abc");
|
||||
|
||||
{
|
||||
std::string str = "abc";
|
||||
auto first = detail::text::detail::begin(str);
|
||||
auto last = detail::text::detail::end(str);
|
||||
auto const result =
|
||||
prefix_parse(first, last, search_parser, char_(' '));
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
std::optional<std::optional<std::string>> const>);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(**result, "abc");
|
||||
}
|
||||
}
|
||||
{
|
||||
std::string str = " abc";
|
||||
std::optional<std::string> result;
|
||||
EXPECT_TRUE(parse(str, search_parser, char_(' '), result));
|
||||
EXPECT_EQ(*result, "abc");
|
||||
|
||||
{
|
||||
std::string str = " abc";
|
||||
auto const result = parse(str, search_parser, char_(' '));
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
std::optional<std::optional<std::string>> const>);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(**result, "abc");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const parser = int_ % ',';
|
||||
|
||||
// Follows the parser used in transform_replace().
|
||||
auto before = [&](auto & ctx) {};
|
||||
auto after = [&](auto & ctx) {};
|
||||
auto const search_parser =
|
||||
omit[*(char_ - parser)] >>
|
||||
-lexeme[eps[before] >> skip[parser] >> eps[after]];
|
||||
|
||||
{
|
||||
std::string str = "1, 2, 4";
|
||||
std::optional<std::vector<int>> result;
|
||||
EXPECT_TRUE(parse(str, search_parser, char_(' '), result));
|
||||
EXPECT_EQ(*result, std::vector<int>({1, 2, 4}));
|
||||
|
||||
{
|
||||
std::string str = "1, 2, 4";
|
||||
auto const result = parse(str, search_parser, char_(' '));
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(result),
|
||||
std::optional<std::optional<std::vector<int>>> const>);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(**result, std::vector<int>({1, 2, 4}));
|
||||
}
|
||||
}
|
||||
{
|
||||
std::string str = " 1, 2, 4";
|
||||
std::optional<std::vector<int>> result;
|
||||
EXPECT_TRUE(parse(str, search_parser, char_(' '), result));
|
||||
EXPECT_EQ(*result, std::vector<int>({1, 2, 4}));
|
||||
|
||||
{
|
||||
std::string str = " 1, 2, 4";
|
||||
auto const result = parse(str, search_parser, char_(' '));
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(result),
|
||||
std::optional<std::optional<std::vector<int>>> const>);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(**result, std::vector<int>({1, 2, 4}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, skip)
|
||||
@@ -1634,7 +1992,7 @@ TEST(parser, combined_seq_and_or)
|
||||
std::string str = "abc";
|
||||
tuple<char, char, char> chars;
|
||||
EXPECT_TRUE(parse(str, parser, chars));
|
||||
EXPECT_EQ(chars, tup('c', '\0', '\0')); // TODO: Document this behavior.
|
||||
EXPECT_EQ(chars, tup('c', '\0', '\0'));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1809,6 +2167,13 @@ TEST(parser, combined_seq_and_or)
|
||||
EXPECT_EQ(chars, "xyz");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto parser = int_ >> -(lit('a') | 'b');
|
||||
auto result = parse("34b", parser);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, 34);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, eol_)
|
||||
@@ -2000,24 +2365,225 @@ TEST(parser, ws_)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, blank_)
|
||||
{
|
||||
{
|
||||
constexpr auto parser = blank;
|
||||
constexpr auto alt_parser = ws - eol;
|
||||
|
||||
{
|
||||
std::string str = "y";
|
||||
EXPECT_FALSE(parse(str, parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u0009";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u000a";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u000d\u000a";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u000b";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u000c";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u000d";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u0085";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u00a0";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u1680";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2000";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2001";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2002";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2003";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2004";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2005";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2006";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2007";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2008";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2009";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u200a";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2028";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u2029";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u202F";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u205F";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
{
|
||||
std::string s = (char const *)u8"\u3000";
|
||||
auto str = boost::parser::detail::text::as_utf8(s);
|
||||
EXPECT_EQ(parse(str, parser), parse(str, alt_parser));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, digit_)
|
||||
{
|
||||
constexpr auto parser = +digit;
|
||||
|
||||
std::u32string str = U"a/09:\x0659\x0660\x0669\x066a";
|
||||
std::vector<uint32_t> result;
|
||||
EXPECT_TRUE(parse(str, parser, char_ - digit, result));
|
||||
EXPECT_EQ(result, std::vector<uint32_t>({'0', '9', 0x0660, 0x0669}));
|
||||
}
|
||||
|
||||
TEST(parser, hex_digit_)
|
||||
{
|
||||
constexpr auto parser = +hex_digit;
|
||||
|
||||
std::u32string str = U"a/09:A\uff0f\uff10\uff19\uff1a";
|
||||
std::vector<uint32_t> result;
|
||||
EXPECT_TRUE(parse(str, parser, char_ - hex_digit, result));
|
||||
EXPECT_EQ(
|
||||
result,
|
||||
std::vector<uint32_t>({'a', '0', '9', 'A', U'\uff10', U'\uff19'}));
|
||||
}
|
||||
|
||||
TEST(parser, control_)
|
||||
{
|
||||
constexpr auto parser = +control;
|
||||
|
||||
std::u32string str = U"\u0001\u001f\u0020\u007e\u007f\u009f\u00a0";
|
||||
std::vector<uint32_t> result;
|
||||
EXPECT_TRUE(parse(str, parser, char_ - control, result));
|
||||
EXPECT_EQ(result, std::vector<uint32_t>({1, 0x001f, 0x007f, 0x009f}));
|
||||
}
|
||||
|
||||
TEST(parser, punct_)
|
||||
{
|
||||
auto parser = +punct;
|
||||
|
||||
std::u32string str = U"\u0020\u0021\u0fda\u0fdb";
|
||||
std::vector<uint32_t> result;
|
||||
EXPECT_TRUE(parse(str, parser, char_ - punct, result));
|
||||
EXPECT_EQ(result, std::vector<uint32_t>({0x21, 0xfda}));
|
||||
}
|
||||
|
||||
TEST(parser, lower_)
|
||||
{
|
||||
auto parser = +lower;
|
||||
|
||||
std::u32string str = U"aA\u016F\u0170";
|
||||
std::vector<uint32_t> result;
|
||||
EXPECT_TRUE(parse(str, parser, char_ - lower, result));
|
||||
EXPECT_EQ(result, std::vector<uint32_t>({'a', 0x16f}));
|
||||
}
|
||||
|
||||
TEST(parser, upper_)
|
||||
{
|
||||
auto parser = +upper;
|
||||
|
||||
std::u32string str = U"aA\u0105\u0106";
|
||||
std::vector<uint32_t> result;
|
||||
EXPECT_TRUE(parse(str, parser, char_ - upper, result));
|
||||
EXPECT_EQ(result, std::vector<uint32_t>({'A', 0x106}));
|
||||
}
|
||||
|
||||
TEST(parser, github_issue_36)
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
|
||||
auto id = bp::lexeme[+(bp::ascii::alnum | bp::char_('_'))];
|
||||
auto id = bp::lexeme[+bp::char_(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789")];
|
||||
auto ids = +id;
|
||||
|
||||
std::string str;
|
||||
std::vector<std::string> vec;
|
||||
|
||||
bp::parse("id1", id, bp::ascii::space, str); // (1)
|
||||
bp::parse("id1", id, bp::ws, str); // (1)
|
||||
EXPECT_EQ(str, "id1");
|
||||
str.clear();
|
||||
bp::parse("id1 id2", ids, bp::ascii::space, vec); // (2)
|
||||
bp::parse("id1 id2", ids, bp::ws, vec); // (2)
|
||||
EXPECT_EQ(vec, std::vector<std::string>({"id1", "id2"}));
|
||||
|
||||
// Intentionally ill-formed.
|
||||
// bp::parse("i1 i2", ids, bp::ascii::space, str); // (3)
|
||||
// bp::parse("i1 i2", ids, bp::ws, str); // (3)
|
||||
}
|
||||
|
||||
namespace issue_50 {
|
||||
@@ -2146,6 +2712,26 @@ TEST(parser, github_issue_52)
|
||||
}
|
||||
}
|
||||
|
||||
namespace issue_90 { namespace parser {
|
||||
const auto string =
|
||||
'"' >> boost::parser::lexeme[*(boost::parser::char_ - '"')] > '"';
|
||||
const auto specifier = string > ':' > string;
|
||||
}}
|
||||
|
||||
TEST(parser, github_issue_90)
|
||||
{
|
||||
using namespace issue_90;
|
||||
namespace bp = boost::parser;
|
||||
|
||||
std::string input = R"( "dd" : "2" )";
|
||||
std::pair<std::string, std::string> result;
|
||||
|
||||
auto b = bp::parse(input, parser::specifier, bp::ws, result);
|
||||
EXPECT_TRUE(b);
|
||||
EXPECT_EQ(result.first, "dd");
|
||||
EXPECT_EQ(result.second, "2");
|
||||
}
|
||||
|
||||
TEST(parser, no_need_for_sprit_2_hold_directive)
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
@@ -2222,3 +2808,51 @@ TEST(parser, string_view_doc_example)
|
||||
static_assert(std::is_same_v<decltype(sv2), std::optional<std::string_view>>);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(parser, variant_compat_example)
|
||||
{
|
||||
struct key_value
|
||||
{
|
||||
int key;
|
||||
double value;
|
||||
};
|
||||
|
||||
namespace bp = boost::parser;
|
||||
std::variant<key_value, double> kv_or_d;
|
||||
key_value kv;
|
||||
bp::parse("42 13.0", bp::int_ >> bp::double_, kv); // Ok.
|
||||
#if 0
|
||||
bp::parse("42 13.0", bp::int_ >> bp::double_, kv_or_d); // Error: ill-formed!
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
namespace rule_construction_example {
|
||||
struct type_t
|
||||
{
|
||||
type_t() = default;
|
||||
explicit type_t(double x) : x_(x) {}
|
||||
// etc.
|
||||
|
||||
double x_;
|
||||
};
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
auto doubles_to_type = [](auto & ctx) {
|
||||
_val(ctx) = type_t(
|
||||
bp::get(_attr(ctx), bp::llong<0>{}) *
|
||||
bp::get(_attr(ctx), bp::llong<1>{}));
|
||||
};
|
||||
|
||||
bp::rule<struct type_tag, type_t> type = "type";
|
||||
auto const type_def = (bp::double_ >> bp::double_)[doubles_to_type];
|
||||
BOOST_PARSER_DEFINE_RULES(type);
|
||||
}
|
||||
|
||||
TEST(parser, rule_example)
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
using namespace rule_construction_example;
|
||||
EXPECT_TRUE(bp::parse("3 4", type, bp::ws));
|
||||
}
|
||||
|
||||
@@ -22,15 +22,13 @@ using namespace boost::parser;
|
||||
constexpr callback_rule<struct callback_char_rule_tag, char>
|
||||
callback_char_rule = "callback_char_rule";
|
||||
constexpr auto callback_char_rule_def = char_;
|
||||
BOOST_PARSER_DEFINE_RULE(callback_char_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(callback_char_rule);
|
||||
|
||||
struct callback_char_rule_tag
|
||||
{};
|
||||
|
||||
TEST(parser, full_parse_api)
|
||||
{
|
||||
constexpr auto skip_ws = ascii::space;
|
||||
|
||||
std::string const str = "a";
|
||||
|
||||
// attr out param, iter/sent
|
||||
@@ -111,7 +109,7 @@ TEST(parser, full_parse_api)
|
||||
first,
|
||||
boost::parser::detail::text::null_sentinel,
|
||||
char_,
|
||||
skip_ws,
|
||||
ws,
|
||||
out));
|
||||
first = str.c_str();
|
||||
EXPECT_EQ(out, 'a');
|
||||
@@ -121,26 +119,26 @@ TEST(parser, full_parse_api)
|
||||
first,
|
||||
boost::parser::detail::text::null_sentinel,
|
||||
char_('b'),
|
||||
skip_ws,
|
||||
ws,
|
||||
out));
|
||||
EXPECT_EQ(out, 0);
|
||||
}
|
||||
// attr out param, using skipper, range
|
||||
{
|
||||
char out = 0;
|
||||
EXPECT_TRUE(parse(str, char_, skip_ws, out));
|
||||
EXPECT_TRUE(parse(str, char_, ws, out));
|
||||
EXPECT_EQ(out, 'a');
|
||||
out = 0;
|
||||
EXPECT_FALSE(parse(str, char_('b'), skip_ws, out));
|
||||
EXPECT_FALSE(parse(str, char_('b'), ws, out));
|
||||
EXPECT_EQ(out, 0);
|
||||
}
|
||||
// attr out param, using skipper, pointer-as-range
|
||||
{
|
||||
char out = 0;
|
||||
EXPECT_TRUE(parse(str.c_str(), char_, skip_ws, out));
|
||||
EXPECT_TRUE(parse(str.c_str(), char_, ws, out));
|
||||
EXPECT_EQ(out, 'a');
|
||||
out = 0;
|
||||
EXPECT_FALSE(parse(str.c_str(), char_('b'), skip_ws, out));
|
||||
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws, out));
|
||||
EXPECT_EQ(out, 0);
|
||||
}
|
||||
|
||||
@@ -148,33 +146,33 @@ TEST(parser, full_parse_api)
|
||||
{
|
||||
auto first = str.c_str();
|
||||
EXPECT_TRUE(prefix_parse(
|
||||
first, boost::parser::detail::text::null_sentinel, char_, skip_ws));
|
||||
first, boost::parser::detail::text::null_sentinel, char_, ws));
|
||||
first = str.c_str();
|
||||
EXPECT_EQ(
|
||||
*prefix_parse(
|
||||
first,
|
||||
boost::parser::detail::text::null_sentinel,
|
||||
char_,
|
||||
skip_ws),
|
||||
ws),
|
||||
'a');
|
||||
first = str.c_str();
|
||||
EXPECT_TRUE(!prefix_parse(
|
||||
first,
|
||||
boost::parser::detail::text::null_sentinel,
|
||||
char_('b'),
|
||||
skip_ws));
|
||||
ws));
|
||||
}
|
||||
// returned attr, using skipper, range
|
||||
{
|
||||
EXPECT_TRUE(parse(str, char_, skip_ws));
|
||||
EXPECT_EQ(*parse(str, char_, skip_ws), 'a');
|
||||
EXPECT_FALSE(parse(str, char_('b'), skip_ws));
|
||||
EXPECT_TRUE(parse(str, char_, ws));
|
||||
EXPECT_EQ(*parse(str, char_, ws), 'a');
|
||||
EXPECT_FALSE(parse(str, char_('b'), ws));
|
||||
}
|
||||
// returned attr, using skipper, pointer-as-range
|
||||
{
|
||||
EXPECT_TRUE(parse(str.c_str(), char_, skip_ws));
|
||||
EXPECT_EQ(*parse(str.c_str(), char_, skip_ws), 'a');
|
||||
EXPECT_FALSE(parse(str.c_str(), char_('b'), skip_ws));
|
||||
EXPECT_TRUE(parse(str.c_str(), char_, ws));
|
||||
EXPECT_EQ(*parse(str.c_str(), char_, ws), 'a');
|
||||
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws));
|
||||
}
|
||||
|
||||
// callback, iter/sent
|
||||
@@ -214,7 +212,7 @@ TEST(parser, full_parse_api)
|
||||
first,
|
||||
boost::parser::detail::text::null_sentinel,
|
||||
callback_char_rule,
|
||||
skip_ws,
|
||||
ws,
|
||||
callbacks));
|
||||
first = str.c_str();
|
||||
EXPECT_EQ(out, 'a');
|
||||
@@ -224,7 +222,7 @@ TEST(parser, full_parse_api)
|
||||
char out = 0;
|
||||
auto callbacks = [&out](auto tag, auto x) { out = x; };
|
||||
EXPECT_TRUE(
|
||||
callback_parse(str, callback_char_rule, skip_ws, callbacks));
|
||||
callback_parse(str, callback_char_rule, ws, callbacks));
|
||||
EXPECT_EQ(out, 'a');
|
||||
}
|
||||
// callback, using skipper, pointer-as-range
|
||||
@@ -232,7 +230,7 @@ TEST(parser, full_parse_api)
|
||||
char out = 0;
|
||||
auto callbacks = [&out](auto tag, auto x) { out = x; };
|
||||
EXPECT_TRUE(callback_parse(
|
||||
str.c_str(), callback_char_rule, skip_ws, callbacks));
|
||||
str.c_str(), callback_char_rule, ws, callbacks));
|
||||
EXPECT_EQ(out, 'a');
|
||||
}
|
||||
}
|
||||
@@ -282,10 +280,8 @@ TEST(parser, basic)
|
||||
}
|
||||
{
|
||||
char const * str = " ";
|
||||
char c = '\0';
|
||||
EXPECT_TRUE(parse(str, ascii::blank, c));
|
||||
EXPECT_EQ(c, ' ');
|
||||
EXPECT_FALSE(parse(str, ascii::lower));
|
||||
EXPECT_TRUE(parse(str, blank));
|
||||
EXPECT_FALSE(parse(str, lower));
|
||||
}
|
||||
{
|
||||
char const * str = "ab";
|
||||
@@ -475,7 +471,7 @@ TEST(parser, uint_)
|
||||
char const * str = "-42";
|
||||
unsigned int i = 3;
|
||||
EXPECT_FALSE(parse(str, uint_, i));
|
||||
EXPECT_EQ(i, 3);
|
||||
EXPECT_EQ(i, 0);
|
||||
}
|
||||
{
|
||||
char const * str = "42";
|
||||
@@ -2005,3 +2001,12 @@ TEST(parser, attr_out_param_compat)
|
||||
assert(bp::get(result, 1_c) == "foo");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(parser, github_issue_78)
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
std::vector<int> result;
|
||||
auto b = bp::parse("3 4 c", +bp::int_, bp::ws, result);
|
||||
EXPECT_FALSE(b);
|
||||
EXPECT_TRUE(result.empty());
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ using namespace boost::parser;
|
||||
|
||||
constexpr rule<struct flat_rule_tag> flat_rule = "flat_rule";
|
||||
constexpr auto flat_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(flat_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(flat_rule);
|
||||
|
||||
constexpr rule<struct recursive_rule_tag> recursive_rule = "recursive_rule";
|
||||
constexpr auto recursive_rule_def = string("abc") >> -('a' >> recursive_rule);
|
||||
BOOST_PARSER_DEFINE_RULE(recursive_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(recursive_rule);
|
||||
|
||||
TEST(parser, no_attribute_rules)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ TEST(parser, no_attribute_rules)
|
||||
constexpr rule<struct flat_string_rule_tag, std::string> flat_string_rule =
|
||||
"flat_string_rule";
|
||||
constexpr auto flat_string_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(flat_string_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(flat_string_rule);
|
||||
|
||||
constexpr callback_rule<struct recursive_string_rule_tag, std::string>
|
||||
recursive_string_rule = "recursive_string_rule";
|
||||
@@ -64,7 +64,7 @@ auto append_string = [](auto & ctx) {
|
||||
};
|
||||
constexpr auto recursive_string_rule_def = string("abc")[append_string] >>
|
||||
-('a' >> recursive_string_rule);
|
||||
BOOST_PARSER_DEFINE_RULE(recursive_string_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(recursive_string_rule);
|
||||
|
||||
TEST(parser, string_attribute_rules)
|
||||
{
|
||||
@@ -112,7 +112,7 @@ TEST(parser, string_attribute_rules)
|
||||
constexpr rule<struct flat_vector_rule_tag, std::vector<char>>
|
||||
flat_vector_rule = "flat_vector_rule";
|
||||
constexpr auto flat_vector_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(flat_vector_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(flat_vector_rule);
|
||||
|
||||
TEST(parser, vector_attribute_rules)
|
||||
{
|
||||
@@ -155,12 +155,12 @@ TEST(parser, vector_attribute_rules)
|
||||
constexpr callback_rule<struct callback_vector_rule_tag, std::vector<char>>
|
||||
callback_vector_rule = "callback_vector_rule";
|
||||
constexpr auto callback_vector_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(callback_vector_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(callback_vector_rule);
|
||||
|
||||
constexpr callback_rule<struct callback_void_rule_tag> callback_void_rule =
|
||||
"callback_void_rule";
|
||||
constexpr auto callback_void_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(callback_void_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(callback_void_rule);
|
||||
|
||||
struct callback_vector_rule_tag
|
||||
{};
|
||||
@@ -353,7 +353,7 @@ constexpr callback_rule<recursive_strings_rule_tag, std::vector<std::string>>
|
||||
auto push_back = [](auto & ctx) { _val(ctx).push_back(std::move(_attr(ctx))); };
|
||||
constexpr auto recursive_strings_rule_def = string("abc")[push_back] >>
|
||||
-('a' >> recursive_strings_rule);
|
||||
BOOST_PARSER_DEFINE_RULE(recursive_strings_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(recursive_strings_rule);
|
||||
|
||||
TEST(param_parser, container_populating_recursive_rule)
|
||||
{
|
||||
@@ -485,7 +485,7 @@ namespace more_about_rules_1 {
|
||||
auto const ints = '{' > (value % ',') > '}';
|
||||
auto const value_def = bp::int_ | ints;
|
||||
|
||||
BOOST_PARSER_DEFINE_RULE(value);
|
||||
BOOST_PARSER_DEFINE_RULES(value);
|
||||
}
|
||||
|
||||
namespace more_about_rules_2 {
|
||||
|
||||
@@ -15,11 +15,11 @@ auto make_13 = [](auto & context) { return 13; };
|
||||
|
||||
constexpr rule<struct flat_rule_tag> flat_rule = "flat_rule";
|
||||
constexpr auto flat_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(flat_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(flat_rule);
|
||||
|
||||
constexpr rule<struct recursive_rule_tag> recursive_rule = "recursive_rule";
|
||||
constexpr auto recursive_rule_def = string("abc") >> -('a' >> recursive_rule);
|
||||
BOOST_PARSER_DEFINE_RULE(recursive_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(recursive_rule);
|
||||
|
||||
TEST(param_parser, no_attribute_rules)
|
||||
{
|
||||
@@ -62,7 +62,7 @@ TEST(param_parser, no_attribute_rules)
|
||||
constexpr rule<struct flat_string_rule_tag, std::string> flat_string_rule =
|
||||
"flat_string_rule";
|
||||
constexpr auto flat_string_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(flat_string_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(flat_string_rule);
|
||||
|
||||
constexpr rule<struct recursive_string_rule_tag, std::string>
|
||||
recursive_string_rule = "recursive_string_rule";
|
||||
@@ -73,7 +73,7 @@ auto append_string = [](auto & ctx) {
|
||||
};
|
||||
constexpr auto recursive_string_rule_def = string("abc")[append_string] >>
|
||||
-('a' >> recursive_string_rule);
|
||||
BOOST_PARSER_DEFINE_RULE(recursive_string_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(recursive_string_rule);
|
||||
|
||||
TEST(param_parser, string_attribute_rules)
|
||||
{
|
||||
@@ -123,7 +123,7 @@ TEST(param_parser, string_attribute_rules)
|
||||
constexpr rule<struct flat_vector_rule_tag, std::vector<char>>
|
||||
flat_vector_rule = "flat_vector_rule";
|
||||
constexpr auto flat_vector_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(flat_vector_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(flat_vector_rule);
|
||||
|
||||
TEST(param_parser, vector_attribute_rules)
|
||||
{
|
||||
@@ -177,12 +177,12 @@ TEST(param_parser, vector_attribute_rules)
|
||||
constexpr callback_rule<struct callback_vector_rule_tag, std::vector<char>>
|
||||
callback_vector_rule = "callback_vector_rule";
|
||||
constexpr auto callback_vector_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(callback_vector_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(callback_vector_rule);
|
||||
|
||||
constexpr callback_rule<struct callback_void_rule_tag> callback_void_rule =
|
||||
"callback_void_rule";
|
||||
constexpr auto callback_void_rule_def = string("abc") | string("def");
|
||||
BOOST_PARSER_DEFINE_RULE(callback_void_rule);
|
||||
BOOST_PARSER_DEFINE_RULES(callback_void_rule);
|
||||
|
||||
struct callback_vector_rule_tag
|
||||
{};
|
||||
|
||||
127
test/quoted_string.cpp
Normal file
127
test/quoted_string.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/parser/parser.hpp>
|
||||
#include <boost/parser/transcode_view.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
TEST(quoted_string, basic)
|
||||
{
|
||||
constexpr auto parser = bp::quoted_string;
|
||||
|
||||
{
|
||||
auto result = bp::parse("", parser, bp::ws);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"("foo")", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"("foo\\")", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo\\");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"("\"foo\"")", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "\"foo\"");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(quoted_string, different_char)
|
||||
{
|
||||
constexpr auto parser = bp::quoted_string('\'');
|
||||
|
||||
{
|
||||
auto result = bp::parse("", parser, bp::ws);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"('foo')", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"('foo\\')", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo\\");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"('\'foo\'')", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "'foo'");
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(quoted_string, char_set)
|
||||
{
|
||||
constexpr auto parser = bp::quoted_string("'\"");
|
||||
|
||||
{
|
||||
auto result = bp::parse("", parser, bp::ws);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
{
|
||||
EXPECT_FALSE(bp::parse(R"('foo")", parser, bp::ws));
|
||||
EXPECT_FALSE(bp::parse(R"("foo')", parser, bp::ws));
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"('foo')", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo");
|
||||
}
|
||||
{
|
||||
auto result = bp::parse(R"("foo")", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"('foo\\')", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo\\");
|
||||
}
|
||||
{
|
||||
auto result = bp::parse(R"("foo\\")", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "foo\\");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = bp::parse(R"('\'foo\'')", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "'foo'");
|
||||
}
|
||||
{
|
||||
auto result = bp::parse(R"("\"foo\"")", parser, bp::ws);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(*result, "'foo'");
|
||||
}
|
||||
|
||||
{
|
||||
// Can't escape arbitrary characters, only backslash and the quote
|
||||
// character.
|
||||
EXPECT_FALSE(bp::parse(R"("\'foo")", parser, bp::ws));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
471
test/replace.cpp
Normal file
471
test/replace.cpp
Normal file
@@ -0,0 +1,471 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/parser/replace.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "ill_formed.hpp"
|
||||
|
||||
#include <list>
|
||||
|
||||
#if !defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
namespace deduction {
|
||||
using namespace std::literals;
|
||||
std::string str;
|
||||
auto const parser = bp::char_;
|
||||
auto const skip = bp::ws;
|
||||
|
||||
auto deduced_1 = bp::replace_view(str, parser, skip, "foo", bp::trace::on);
|
||||
auto deduced_2 = bp::replace_view(str, parser, skip, "foo");
|
||||
auto deduced_3 = bp::replace_view(str, parser, "foo", bp::trace::on);
|
||||
auto deduced_4 = bp::replace_view(str, parser, "foo");
|
||||
}
|
||||
#endif
|
||||
|
||||
static_assert(
|
||||
bp::detail::range_utf_format<char const *&>() == bp::detail::no_format);
|
||||
|
||||
TEST(replace, either_iterator)
|
||||
{
|
||||
{
|
||||
std::list<int> l({1, 2, 3});
|
||||
std::vector<int> v({4, 5, 6});
|
||||
bp::detail::either_iterator<std::list<int>, std::vector<int>>
|
||||
either_l_begin(l.begin());
|
||||
bp::detail::either_iterator<std::list<int>, std::vector<int>>
|
||||
either_l_end(l.end());
|
||||
bp::detail::either_iterator<std::list<int>, std::vector<int>>
|
||||
either_v_begin(v.begin());
|
||||
bp::detail::either_iterator<std::list<int>, std::vector<int>>
|
||||
either_v_end(v.end());
|
||||
|
||||
int const l_array[] = {1, 2, 3};
|
||||
auto l_array_curr = l_array;
|
||||
for (auto it = either_l_begin; it != either_l_end;
|
||||
++it, ++l_array_curr) {
|
||||
EXPECT_EQ(*it, *l_array_curr);
|
||||
}
|
||||
|
||||
int const v_array[] = {4, 5, 6};
|
||||
auto v_array_curr = v_array;
|
||||
for (auto it = either_v_begin; it != either_v_end;
|
||||
++it, ++v_array_curr) {
|
||||
EXPECT_EQ(*it, *v_array_curr);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto r1 = bp::detail::to_range<decltype("")>::call("");
|
||||
auto r2 = bp::detail::to_range<decltype("foo")>::call("foo");
|
||||
|
||||
bp::detail::either_iterator<decltype(r1), decltype(r2)> either_r1_begin(
|
||||
r1.begin());
|
||||
bp::detail::either_iterator<decltype(r1), decltype(r2)> either_r1_end(
|
||||
r1.end());
|
||||
bp::detail::either_iterator<decltype(r1), decltype(r2)> either_r2_begin(
|
||||
r2.begin());
|
||||
bp::detail::either_iterator<decltype(r1), decltype(r2)> either_r2_end(
|
||||
r2.end());
|
||||
|
||||
EXPECT_EQ(either_r1_begin, either_r1_end);
|
||||
std::string copy;
|
||||
for (auto it = either_r2_begin; it != either_r2_end; ++it) {
|
||||
copy.push_back(*it);
|
||||
}
|
||||
EXPECT_EQ(copy, "foo");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(replace, replace)
|
||||
{
|
||||
{
|
||||
auto r = bp::replace("", bp::lit("XYZ"), bp::ws, "foo");
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZb";
|
||||
auto r = bp::replace(str, bp::lit("XYZ"), bp::ws, "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "b"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "a a XYZ baa ba XYZ";
|
||||
auto r =
|
||||
str | bp::replace(bp::lit("XYZ"), bp::ws, "foo", bp::trace::off);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"a a ", "foo", " baa ba ", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
#if !defined(__GNUC__) || 12 <= __GNUC__
|
||||
// Older GCCs don't like the use of temporaries like the
|
||||
// std::string("foo") below.
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
auto r = str | bp::replace(
|
||||
bp::lit("XYZ"), std::string("foo"), bp::trace::off);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "baaba", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
const auto r = str | bp::replace(bp::lit("XYZ"), "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "baaba", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
char const * replacement = "foo";
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), replacement);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
char const * replacement = "foo";
|
||||
auto const r = str | bp::replace(bp::lit("XYZ"), replacement);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
}
|
||||
|
||||
// MSVC produces hard errors here, so ill_formed does not work.
|
||||
#if defined(__cpp_char8_t) && !defined(_MSC_VER)
|
||||
char const empty_str[] = "";
|
||||
|
||||
template<typename T>
|
||||
using char_str_utf8_replacement =
|
||||
decltype(std::declval<T>() | bp::replace(bp::lit("XYZ"), std::declval<T>() | bp::as_utf8));
|
||||
static_assert(ill_formed<char_str_utf8_replacement, decltype(empty_str)>{});
|
||||
|
||||
template<typename T>
|
||||
using char_str_utf16_replacement =
|
||||
decltype(std::declval<T>() | bp::replace(bp::lit("XYZ"), std::declval<T>() | bp::as_utf16));
|
||||
static_assert(ill_formed<char_str_utf16_replacement, decltype(empty_str)>{});
|
||||
|
||||
template<typename T>
|
||||
using utf8_str_char_replacement =
|
||||
decltype(std::declval<T>() | bp::as_utf8 | bp::replace(bp::lit("XYZ"), std::declval<T>()));
|
||||
static_assert(ill_formed<utf8_str_char_replacement, decltype(empty_str)>{});
|
||||
#endif
|
||||
|
||||
TEST(replace, replace_unicode)
|
||||
{
|
||||
{
|
||||
char const str_[] = "";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = bp::replace(str, bp::lit("XYZ"), bp::ws, "foo" | bp::as_utf8);
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const * str_ = "aaXYZb";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = bp::replace(str, bp::lit("XYZ"), bp::ws, "foo" | bp::as_utf16);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "b"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r =
|
||||
str |
|
||||
bp::replace(
|
||||
bp::lit("XYZ"), bp::ws, "foo" | bp::as_utf32, bp::trace::off);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "baaba", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = str | bp::replace(
|
||||
bp::lit("XYZ"), "foo" | bp::as_utf8, bp::trace::off);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "baaba", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "baaba", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {"aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo" | bp::as_utf8);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo");
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo" | bp::as_utf8);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::replace(bp::lit("XYZ"), "foo" | bp::as_utf32);
|
||||
int count = 0;
|
||||
std::string_view const strs[] = {
|
||||
"foo", "foo", "aa", "foo", "baaba", "foo", "foo"};
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
EXPECT_EQ(str, strs[count]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS && (!defined(__GNUC__) || 12 <= __GNUC__)
|
||||
// Older GCCs don't like the use of temporaries like the std::string("foo")
|
||||
// below. This causes | join to break.
|
||||
TEST(replace, join_compat)
|
||||
{
|
||||
{
|
||||
char const str[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto rng = str | bp::as_utf32 |
|
||||
bp::replace(bp::lit("XYZ"), "foo" | bp::as_utf8) |
|
||||
std::views::join;
|
||||
std::string replace_result;
|
||||
for (auto ch : rng) {
|
||||
static_assert(std::is_same_v<decltype(ch), char32_t>);
|
||||
replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(replace_result, "foofooaafoobaabafoofoo");
|
||||
}
|
||||
|
||||
{
|
||||
char const str[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto rng = str | bp::replace(bp::lit("XYZ"), "foo") | std::views::join;
|
||||
std::string replace_result;
|
||||
for (auto ch : rng) {
|
||||
replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(replace_result, "foofooaafoobaabafoofoo");
|
||||
}
|
||||
{
|
||||
std::string str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto rng = str | bp::replace(bp::lit("XYZ"), "foo") | std::views::join;
|
||||
std::string replace_result;
|
||||
for (auto ch : rng) {
|
||||
replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(replace_result, "foofooaafoobaabafoofoo");
|
||||
}
|
||||
{
|
||||
std::string const str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto rng = str | bp::replace(bp::lit("XYZ"), "foo") | std::views::join;
|
||||
std::string replace_result;
|
||||
for (auto ch : rng) {
|
||||
replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(replace_result, "foofooaafoobaabafoofoo");
|
||||
}
|
||||
{
|
||||
auto rng = std::string("XYZXYZaaXYZbaabaXYZXYZ") |
|
||||
bp::replace(bp::lit("XYZ"), "foo") | std::views::join;
|
||||
std::string replace_result;
|
||||
for (auto ch : rng) {
|
||||
replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(replace_result, "foofooaafoobaabafoofoo");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(replace, doc_examples)
|
||||
{
|
||||
// clang-format off
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
auto card_number = bp::int_ >> bp::repeat(3)['-' >> bp::int_];
|
||||
auto rng = "My credit card number is 1234-5678-9012-3456." | bp::replace(card_number, "XXXX-XXXX-XXXX-XXXX");
|
||||
int count = 0;
|
||||
// Prints My credit card number is XXXX-XXXX-XXXX-XXXX.
|
||||
for (auto subrange : rng) {
|
||||
std::cout << std::string_view(subrange.begin(), subrange.end() - subrange.begin());
|
||||
++count;
|
||||
}
|
||||
std::cout << "\n";
|
||||
assert(count == 3);
|
||||
}
|
||||
#if BOOST_PARSER_USE_CONCEPTS && (!defined(__GNUC__) || 12 <= __GNUC__)
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
auto card_number = bp::int_ >> bp::repeat(3)['-' >> bp::int_];
|
||||
auto rng = "My credit card number is 1234-5678-9012-3456." |
|
||||
bp::replace(card_number, "XXXX-XXXX-XXXX-XXXX") |
|
||||
std::views::join;
|
||||
std::string replace_result;
|
||||
for (auto ch : rng) {
|
||||
replace_result.push_back(ch);
|
||||
}
|
||||
assert(replace_result == "My credit card number is XXXX-XXXX-XXXX-XXXX.");
|
||||
#endif
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
#endif
|
||||
754
test/search.cpp
Normal file
754
test/search.cpp
Normal file
@@ -0,0 +1,754 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/parser/search.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
namespace deduction {
|
||||
std::string str;
|
||||
auto const parser = bp::char_;
|
||||
auto const skip = bp::ws;
|
||||
|
||||
auto deduced_1 = bp::search_all_view(str, parser, skip, bp::trace::on);
|
||||
auto deduced_2 = bp::search_all_view(str, parser, skip);
|
||||
auto deduced_3 = bp::search_all_view(str, parser, bp::trace::on);
|
||||
auto deduced_4 = bp::search_all_view(str, parser);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(search, search_range_skip)
|
||||
{
|
||||
// array of char
|
||||
{
|
||||
char const str[] = "";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str);
|
||||
EXPECT_EQ(result.end(), str);
|
||||
}
|
||||
{
|
||||
char const str[] = "not here";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::end(str) - 1);
|
||||
EXPECT_EQ(result.end(), std::end(str) - 1);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZb";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZab";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "gbXYZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "XXYZZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
{
|
||||
char const * str = "XXYZZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
{
|
||||
auto result = bp::search(std::string("XXYZZ"), bp::lit("XYZ"), bp::ws);
|
||||
static_assert(std::same_as<decltype(result), std::ranges::dangling>);
|
||||
}
|
||||
#endif
|
||||
|
||||
// array of char | as_utf32
|
||||
{
|
||||
char const str[] = "";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str);
|
||||
EXPECT_EQ(result.end(), str);
|
||||
}
|
||||
{
|
||||
char const str[] = "not here";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::end(str) - 1);
|
||||
EXPECT_EQ(result.end(), std::end(str) - 1);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZb";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZab";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "gbXYZ";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZ";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "XXYZZ";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str = "";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str);
|
||||
EXPECT_EQ(result.end(), str);
|
||||
}
|
||||
{
|
||||
char const * str = "not here";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_TRUE(result.begin() == bp::null_sentinel_t{});
|
||||
EXPECT_TRUE(result.end() == bp::null_sentinel_t{});
|
||||
}
|
||||
{
|
||||
char const * str = "aaXYZb";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZab";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const * str = "gbXYZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const * str = "XXYZZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str_ = "";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str.begin());
|
||||
EXPECT_EQ(result.end(), str.end());
|
||||
}
|
||||
{
|
||||
char const * str_ = "not here";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_TRUE(result.begin() == str.end());
|
||||
EXPECT_TRUE(result.end() == str.end());
|
||||
}
|
||||
{
|
||||
char const * str_ = "aaXYZb";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 2));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 5));
|
||||
}
|
||||
{
|
||||
char const * str_ = "XYZab";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
{
|
||||
char const * str_ = "gbXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 2));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 5));
|
||||
}
|
||||
{
|
||||
char const * str_ = "XYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
{
|
||||
char const * str_ = "XXYZZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 1));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 4));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(search, search_iters_skip)
|
||||
{
|
||||
// array of char
|
||||
{
|
||||
char const str[] = "XYZab";
|
||||
auto result =
|
||||
bp::search(std::begin(str), std::end(str), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "gbXYZ";
|
||||
auto result =
|
||||
bp::search(std::begin(str), std::end(str), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZ";
|
||||
auto result =
|
||||
bp::search(std::begin(str), std::end(str), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
|
||||
// array of char | as_utf32
|
||||
{
|
||||
char const str_[] = "";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result =
|
||||
bp::search(str.begin(), str.end(), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str_);
|
||||
EXPECT_EQ(result.end(), str_);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result =
|
||||
bp::search(str.begin(), str.end(), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str_ + 0);
|
||||
EXPECT_EQ(result.end(), str_ + 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XXYZZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result =
|
||||
bp::search(str.begin(), str.end(), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str_ + 1);
|
||||
EXPECT_EQ(result.end(), str_ + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str = "";
|
||||
auto result =
|
||||
bp::search(str, bp::null_sentinel_t{}, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str);
|
||||
EXPECT_EQ(result.end(), str);
|
||||
}
|
||||
{
|
||||
char const * str = "not here";
|
||||
auto result =
|
||||
bp::search(str, bp::null_sentinel_t{}, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_TRUE(result.begin() == bp::null_sentinel_t{});
|
||||
EXPECT_TRUE(result.end() == bp::null_sentinel_t{});
|
||||
}
|
||||
{
|
||||
char const * str = "XXYZZ";
|
||||
auto result =
|
||||
bp::search(str, bp::null_sentinel_t{}, bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str_ = "XYZab";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result =
|
||||
bp::search(str.begin(), str.end(), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
{
|
||||
char const * str_ = "gbXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto result =
|
||||
bp::search(str.begin(), str.end(), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 2));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 5));
|
||||
}
|
||||
{
|
||||
char const * str_ = "XYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto result =
|
||||
bp::search(str.begin(), str.end(), bp::lit("XYZ"), bp::ws);
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(search, search_range_no_skip)
|
||||
{
|
||||
// array of char
|
||||
{
|
||||
char const str[] = "XYZab";
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "gbXYZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
|
||||
// array of char | as_utf32
|
||||
{
|
||||
char const str[] = "";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str);
|
||||
EXPECT_EQ(result.end(), str);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZ";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "XXYZZ";
|
||||
auto result = bp::search(str | bp::as_utf32, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str = "";
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str);
|
||||
EXPECT_EQ(result.end(), str);
|
||||
}
|
||||
{
|
||||
char const * str = "not here";
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_TRUE(result.begin() == bp::null_sentinel_t{});
|
||||
EXPECT_TRUE(result.end() == bp::null_sentinel_t{});
|
||||
}
|
||||
{
|
||||
char const * str = "XXYZZ";
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str_ = "XYZab";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
{
|
||||
char const * str_ = "gbXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 2));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 5));
|
||||
}
|
||||
{
|
||||
char const * str_ = "XYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto result = bp::search(str, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(search, search_iters_no_skip)
|
||||
{
|
||||
// array of char
|
||||
{
|
||||
char const str[] = "XYZab";
|
||||
auto result =
|
||||
bp::search(std::begin(str), std::end(str), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "gbXYZ";
|
||||
auto result =
|
||||
bp::search(std::begin(str), std::end(str), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 2);
|
||||
EXPECT_EQ(result.end(), str + 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZ";
|
||||
auto result =
|
||||
bp::search(std::begin(str), std::end(str), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 0);
|
||||
EXPECT_EQ(result.end(), str + 3);
|
||||
}
|
||||
|
||||
// array of char | as_utf32
|
||||
{
|
||||
char const str_[] = "";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str.begin(), str.end(), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str_);
|
||||
EXPECT_EQ(result.end(), str_);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str.begin(), str.end(), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str_ + 0);
|
||||
EXPECT_EQ(result.end(), str_ + 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XXYZZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str.begin(), str.end(), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str_ + 1);
|
||||
EXPECT_EQ(result.end(), str_ + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str = "";
|
||||
auto result = bp::search(str, bp::null_sentinel_t{}, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str);
|
||||
EXPECT_EQ(result.end(), str);
|
||||
}
|
||||
{
|
||||
char const * str = "not here";
|
||||
auto result = bp::search(str, bp::null_sentinel_t{}, bp::lit("XYZ"));
|
||||
EXPECT_TRUE(result.begin() == bp::null_sentinel_t{});
|
||||
EXPECT_TRUE(result.end() == bp::null_sentinel_t{});
|
||||
}
|
||||
{
|
||||
char const * str = "XXYZZ";
|
||||
auto result = bp::search(str, bp::null_sentinel_t{}, bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), str + 1);
|
||||
EXPECT_EQ(result.end(), str + 4);
|
||||
}
|
||||
|
||||
// pointer
|
||||
{
|
||||
char const * str_ = "XYZab";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto result = bp::search(str.begin(), str.end(), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
{
|
||||
char const * str_ = "gbXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto result = bp::search(str.begin(), str.end(), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 2));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 5));
|
||||
}
|
||||
{
|
||||
char const * str_ = "XYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto result = bp::search(str.begin(), str.end(), bp::lit("XYZ"));
|
||||
EXPECT_EQ(result.begin(), std::next(str.begin(), 0));
|
||||
EXPECT_EQ(result.end(), std::next(str.begin(), 3));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(search, search_all)
|
||||
{
|
||||
{
|
||||
auto r = bp::search_all("", bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZb";
|
||||
auto r = bp::search_all(str, bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 1);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"), bp::ws, bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"), bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13, 13, 16};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 3, 5, 8, 13, 16, 16, 19};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 3, 3, 6, 8, 11, 16, 19, 19, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 3, 3, 6, 8, 11, 16, 19, 19, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto const r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 3, 3, 6, 8, 11, 16, 19, 19, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(search, search_all_unicode)
|
||||
{
|
||||
{
|
||||
char const str_[] = "";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = bp::search_all(str, bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const * str_ = "aaXYZb";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = bp::search_all(str, bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 1);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"), bp::ws, bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"), bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {2, 5, 10, 13, 13, 16};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 3, 5, 8, 13, 16, 16, 19};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 3, 3, 6, 8, 11, 16, 19, 19, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(search, doc_examples)
|
||||
{
|
||||
{
|
||||
namespace bp = boost::parser;
|
||||
auto result = bp::search("aaXYZq", bp::lit("XYZ"), bp::ws);
|
||||
assert(!result.empty());
|
||||
assert(
|
||||
std::string_view(result.begin(), result.end() - result.begin()) ==
|
||||
"XYZ");
|
||||
}
|
||||
{
|
||||
auto r = "XYZaaXYZbaabaXYZXYZ" | bp::search_all(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
// Prints XYZ XYZ XYZ XYZ.
|
||||
for (auto subrange : r) {
|
||||
std::cout << std::string_view(subrange.begin(), subrange.end() - subrange.begin()) << " ";
|
||||
++count;
|
||||
}
|
||||
std::cout << "\n";
|
||||
assert(count == 4);
|
||||
}
|
||||
}
|
||||
269
test/split.cpp
Normal file
269
test/split.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/parser/split.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
namespace deduction {
|
||||
std::string str;
|
||||
auto const parser = bp::char_;
|
||||
auto const skip = bp::ws;
|
||||
|
||||
auto deduced_1 = bp::split_view(str, parser, skip, bp::trace::on);
|
||||
auto deduced_2 = bp::split_view(str, parser, skip);
|
||||
auto deduced_3 = bp::split_view(str, parser, bp::trace::on);
|
||||
auto deduced_4 = bp::split_view(str, parser);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(split, split_)
|
||||
{
|
||||
{
|
||||
auto r = bp::split("", bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZb";
|
||||
auto r = bp::split(str, bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 6};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
auto r = str | bp::split(bp::lit("XYZ"), bp::ws, bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
auto r = str | bp::split(bp::lit("XYZ"), bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZ";
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13, 16, 16};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 0, 3, 5, 8, 13, 16, 16, 19, 19};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 0, 3, 3, 6, 8, 11, 16, 19, 19, 22, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 0, 3, 3, 6, 8, 11, 16, 19, 19, 22, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
{
|
||||
char const * str = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto const r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 0, 3, 3, 6, 8, 11, 16, 19, 19, 22, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin() - str, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end() - str, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(split, split_unicode)
|
||||
{
|
||||
{
|
||||
char const str_[] = "";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = bp::split(str, bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const * str_ = "aaXYZb";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = bp::split(str, bp::lit("XYZ"), bp::ws);
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 6};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 2);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r = str | bp::split(bp::lit("XYZ"), bp::ws, bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
const auto r = str | bp::split(bp::lit("XYZ"), bp::trace::off);
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 2, 5, 10, 13, 13, 16, 16};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 0, 3, 5, 8, 13, 16, 16, 19, 19};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 5);
|
||||
}
|
||||
{
|
||||
char const str_[] = "XYZXYZaaXYZbaabaXYZXYZ";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
int const offsets[] = {0, 0, 3, 3, 6, 8, 11, 16, 19, 19, 22, 22};
|
||||
for (auto subrange : r) {
|
||||
EXPECT_EQ(subrange.begin().base() - str_, offsets[count * 2 + 0]);
|
||||
EXPECT_EQ(subrange.end().base() - str_, offsets[count * 2 + 1]);
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(split, doc_examples)
|
||||
{
|
||||
{
|
||||
auto r = "XYZaaXYZbaabaXYZXYZ" | bp::split(bp::lit("XYZ"));
|
||||
int count = 0;
|
||||
// Prints '' 'aa' 'baaba' '' ''.
|
||||
for (auto subrange : r) {
|
||||
std::cout << "'" << std::string_view(subrange.begin(), subrange.end() - subrange.begin()) << "' ";
|
||||
++count;
|
||||
}
|
||||
std::cout << "\n";
|
||||
assert(count == 5);
|
||||
}
|
||||
}
|
||||
@@ -297,6 +297,15 @@ int main()
|
||||
|
||||
PARSE(string("h"));
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| quoted_string() |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(quoted_string);
|
||||
PARSE(quoted_string('\''));
|
||||
PARSE(quoted_string("'\""));
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| eol |\n"
|
||||
@@ -313,21 +322,52 @@ int main()
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| ascii character classes |\n"
|
||||
<< "| blank |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(ascii::alnum);
|
||||
PARSE(ascii::alpha);
|
||||
PARSE(ascii::blank);
|
||||
PARSE(ascii::cntrl);
|
||||
PARSE(ascii::digit);
|
||||
PARSE(ascii::graph);
|
||||
PARSE(ascii::print);
|
||||
PARSE(ascii::punct);
|
||||
PARSE(ascii::space);
|
||||
PARSE(ascii::xdigit);
|
||||
PARSE(ascii::lower);
|
||||
PARSE(ascii::upper);
|
||||
PARSE(blank);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| digit |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(digit);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| control |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(control);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| punct |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(punct);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| lower |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(lower);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| upper |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(upper);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
<< "| hex_digit |\n"
|
||||
<< "----------------------------------------\n";
|
||||
|
||||
PARSE(hex_digit);
|
||||
|
||||
std::cout << "\n\n"
|
||||
<< "----------------------------------------\n"
|
||||
|
||||
859
test/transform_replace.cpp
Normal file
859
test/transform_replace.cpp
Normal file
@@ -0,0 +1,859 @@
|
||||
/**
|
||||
* Copyright (C) 2024 T. Zachary Laine
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/parser/transform_replace.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "ill_formed.hpp"
|
||||
|
||||
#include <list>
|
||||
|
||||
#if (!defined(_MSC_VER) || BOOST_PARSER_USE_CONCEPTS)
|
||||
|
||||
namespace bp = boost::parser;
|
||||
|
||||
auto f_str = [](std::vector<int> const & ints) {
|
||||
std::string retval;
|
||||
for (auto x : ints) {
|
||||
retval += std::to_string(x);
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
auto f_str_ref = [](std::vector<int> const & ints) -> std::string & {
|
||||
static std::string retval;
|
||||
for (auto x : ints) {
|
||||
retval += std::to_string(x);
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
namespace deduction {
|
||||
using namespace std::literals;
|
||||
std::string str;
|
||||
auto const parser = bp::int_ % ',';
|
||||
auto const skip = bp::ws;
|
||||
using attr_t = std::vector<int>;
|
||||
|
||||
auto deduced_1 = bp::transform_replace_view(
|
||||
str,
|
||||
parser,
|
||||
skip,
|
||||
bp::detail::utf_rvalue_shim<std::string, decltype(f_str), attr_t>(
|
||||
f_str),
|
||||
bp::trace::on);
|
||||
auto deduced_2 = bp::transform_replace_view(
|
||||
str,
|
||||
parser,
|
||||
skip,
|
||||
bp::detail::utf_rvalue_shim<std::string, decltype(f_str), attr_t>(
|
||||
f_str));
|
||||
auto deduced_3 = bp::transform_replace_view(
|
||||
str,
|
||||
parser,
|
||||
bp::detail::utf_rvalue_shim<std::string, decltype(f_str), attr_t>(
|
||||
f_str),
|
||||
bp::trace::on);
|
||||
auto deduced_4 = bp::transform_replace_view(
|
||||
str,
|
||||
parser,
|
||||
bp::detail::utf_rvalue_shim<std::string, decltype(f_str), attr_t>(
|
||||
f_str));
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace detail_attr_type {
|
||||
constexpr auto int_char_p = bp::int_ >> bp::char_;
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
bp::detail::range_attr_t<std::string, decltype(int_char_p.parser_)>,
|
||||
bp::tuple<int, char>>);
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
bp::detail::
|
||||
range_attr_t<std::u32string, decltype(int_char_p.parser_)>,
|
||||
bp::tuple<int, char32_t>>);
|
||||
|
||||
constexpr auto ints_p = *bp::int_;
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
bp::detail::range_attr_t<std::u32string, decltype(ints_p.parser_)>,
|
||||
std::vector<int>>);
|
||||
}
|
||||
|
||||
#if defined(__cpp_char8_t)
|
||||
auto f_u8str = [](std::vector<int> ints) {
|
||||
std::u8string retval;
|
||||
for (auto x : ints) {
|
||||
auto const s = std::to_string(x);
|
||||
retval.insert(retval.end(), s.begin(), s.end());
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
// NOTE: *const* & return type!
|
||||
auto f_u8str_ref = [](std::vector<int> ints) -> std::u8string const & {
|
||||
static std::u8string retval;
|
||||
for (auto x : ints) {
|
||||
auto const s = std::to_string(x);
|
||||
retval.insert(retval.end(), s.begin(), s.end());
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
#endif
|
||||
auto f_u16str = [](std::vector<int> ints) {
|
||||
std::u16string retval;
|
||||
for (auto x : ints) {
|
||||
auto const s = std::to_string(x);
|
||||
retval.insert(retval.end(), s.begin(), s.end());
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
auto f_u16str_ref = [](std::vector<int> ints) -> std::u16string & {
|
||||
static std::u16string retval;
|
||||
for (auto x : ints) {
|
||||
auto const s = std::to_string(x);
|
||||
retval.insert(retval.end(), s.begin(), s.end());
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
auto f_u32str = [](std::vector<int> ints) {
|
||||
std::u32string retval;
|
||||
for (auto x : ints) {
|
||||
auto const s = std::to_string(x);
|
||||
retval.insert(retval.end(), s.begin(), s.end());
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
auto f_u32str_ref = [](std::vector<int> ints) -> std::u32string & {
|
||||
static std::u32string retval;
|
||||
for (auto x : ints) {
|
||||
auto const s = std::to_string(x);
|
||||
retval.insert(retval.end(), s.begin(), s.end());
|
||||
retval += '_';
|
||||
}
|
||||
return retval;
|
||||
};
|
||||
|
||||
namespace detail_utf_rvalue_shim {
|
||||
constexpr auto ints_p = *bp::int_;
|
||||
|
||||
using attr_t = std::vector<int>;
|
||||
|
||||
// char -> char
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::string, decltype(f_str), attr_t>
|
||||
char_char_shim(f_str);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(char_char_shim(attr_t{})), std::string &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(char_char_shim),
|
||||
std::string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::string, decltype(f_str_ref), attr_t>
|
||||
char_char_ref_shim(f_str_ref);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(char_char_ref_shim(attr_t{})), std::string &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(char_char_ref_shim),
|
||||
std::string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
#if defined(__cpp_char8_t) && BOOST_PARSER_USE_CONCEPTS
|
||||
// char8_t -> char8_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u8string, decltype(f_u8str), attr_t>
|
||||
u8_u8_shim(f_u8str);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(u8_u8_shim(attr_t{})), std::u8string &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u8_u8_shim),
|
||||
std::u8string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u8string, decltype(f_u8str_ref), attr_t>
|
||||
u8_u8_ref_shim(f_u8str_ref);
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u8_u8_ref_shim(attr_t{})),
|
||||
std::u8string const &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u8_u8_ref_shim),
|
||||
std::u8string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
// char8_t -> char16_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u8string, decltype(f_u16str), attr_t>
|
||||
u8_u16_shim(f_u16str);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u8_u16_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf8,
|
||||
std::ranges::owning_view<std::u16string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u8_u16_shim),
|
||||
std::u8string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u8string, decltype(f_u16str_ref), attr_t>
|
||||
u8_u16_ref_shim(f_u16str_ref);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u8_u16_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf8,
|
||||
std::ranges::ref_view<std::u16string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u8_u16_ref_shim),
|
||||
std::u8string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
// char8_t -> char32_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u8string, decltype(f_u32str), attr_t>
|
||||
u8_u32_shim(f_u32str);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u8_u32_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf8,
|
||||
std::ranges::owning_view<std::u32string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u8_u32_shim),
|
||||
std::u8string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u8string, decltype(f_u32str_ref), attr_t>
|
||||
u8_u32_ref_shim(f_u32str_ref);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u8_u32_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf8,
|
||||
std::ranges::ref_view<std::u32string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u8_u32_ref_shim),
|
||||
std::u8string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
// char16_t -> char8_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u16string, decltype(f_u8str), attr_t>
|
||||
u16_u8_shim(f_u8str);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u16_u8_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf16,
|
||||
std::ranges::owning_view<std::u8string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u16_u8_shim),
|
||||
std::u16string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u16string, decltype(f_u8str_ref), attr_t>
|
||||
u16_u8_ref_shim(f_u8str_ref);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u16_u8_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf16,
|
||||
std::ranges::ref_view<std::u8string const>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u16_u8_ref_shim),
|
||||
std::u16string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
// char32_t -> char8_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u32string, decltype(f_u8str), attr_t>
|
||||
u32_u8_shim(f_u8str);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u32_u8_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf32,
|
||||
std::ranges::owning_view<std::u8string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u32_u8_shim),
|
||||
std::u32string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u32string, decltype(f_u8str_ref), attr_t>
|
||||
u32_u8_ref_shim(f_u8str_ref);
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u32_u8_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf32,
|
||||
std::ranges::ref_view<std::u8string const>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u32_u8_ref_shim),
|
||||
std::u32string,
|
||||
decltype(ints_p.parser_)>);
|
||||
#endif
|
||||
// char16_t -> char16_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u16string, decltype(f_u16str), attr_t>
|
||||
u16_u16_shim(f_u16str);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(u16_u16_shim(attr_t{})), std::u16string &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u16_u16_shim),
|
||||
std::u16string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u16string, decltype(f_u16str_ref), attr_t>
|
||||
u16_u16_ref_shim(f_u16str_ref);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(u16_u16_ref_shim(attr_t{})), std::u16string &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u16_u16_ref_shim),
|
||||
std::u16string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
// char16_t -> char32_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u16string, decltype(f_u32str), attr_t>
|
||||
u16_u32_shim(f_u32str);
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u16_u32_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf16,
|
||||
std::ranges::owning_view<std::u32string>> &>);
|
||||
#endif
|
||||
#else
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(u16_u32_shim(attr_t{})),
|
||||
bp::detail::text::utf16_view<
|
||||
bp::detail::text::detail::owning_view<std::u32string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u16_u32_shim),
|
||||
std::u16string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u16string, decltype(f_u32str_ref), attr_t>
|
||||
u16_u32_ref_shim(f_u32str_ref);
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u16_u32_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf16,
|
||||
std::ranges::ref_view<std::u32string>> &>);
|
||||
#endif
|
||||
#else
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u16_u32_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf16_view<
|
||||
bp::detail::text::detail::ref_view<std::u32string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u16_u32_ref_shim),
|
||||
std::u16string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
// char32_t -> char32_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u32string, decltype(f_u32str), attr_t>
|
||||
u32_u32_shim(f_u32str);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(u32_u32_shim(attr_t{})), std::u32string &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u32_u32_shim),
|
||||
std::u32string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u32string, decltype(f_u32str_ref), attr_t>
|
||||
u32_u32_ref_shim(f_u32str_ref);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(u32_u32_ref_shim(attr_t{})), std::u32string &>);
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u32_u32_ref_shim),
|
||||
std::u32string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
// char32_t -> char16_t
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u32string, decltype(f_u16str), attr_t>
|
||||
u32_u16_shim(f_u16str);
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u32_u16_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf32,
|
||||
std::ranges::owning_view<std::u16string>> &>);
|
||||
#endif
|
||||
#else
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
decltype(u32_u16_shim(attr_t{})),
|
||||
bp::detail::text::utf32_view<
|
||||
bp::detail::text::detail::owning_view<std::u16string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u32_u16_shim),
|
||||
std::u32string,
|
||||
decltype(ints_p.parser_)>);
|
||||
|
||||
bp::detail::utf_rvalue_shim<std::u32string, decltype(f_u16str_ref), attr_t>
|
||||
u32_u16_ref_shim(f_u16str_ref);
|
||||
#if BOOST_PARSER_USE_CONCEPTS
|
||||
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u32_u16_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf_view<
|
||||
bp::detail::text::format::utf32,
|
||||
std::ranges::ref_view<std::u16string>> &>);
|
||||
#endif
|
||||
#else
|
||||
static_assert(std::is_same_v<
|
||||
decltype(u32_u16_ref_shim(attr_t{})),
|
||||
bp::detail::text::utf32_view<
|
||||
bp::detail::text::detail::ref_view<std::u16string>> &>);
|
||||
#endif
|
||||
static_assert(bp::detail::transform_replacement_for<
|
||||
decltype(u32_u16_ref_shim),
|
||||
std::u32string,
|
||||
decltype(ints_p.parser_)>);
|
||||
}
|
||||
|
||||
TEST(transform_replace, detail_attr_search_repack_shim)
|
||||
{
|
||||
using namespace bp::literals;
|
||||
|
||||
{
|
||||
std::string str = "";
|
||||
auto parser = bp::string("XYZ");
|
||||
|
||||
// Follows body of attr_search_impl() that constructs a custom parser
|
||||
// from the given one.
|
||||
auto first = bp::detail::text::detail::begin(str);
|
||||
auto const last = bp::detail::text::detail::end(str);
|
||||
auto match_first = first;
|
||||
auto match_last = first;
|
||||
auto before = [&match_first](auto & ctx) {
|
||||
match_first = _where(ctx).begin();
|
||||
};
|
||||
auto after = [&match_last](auto & ctx) {
|
||||
match_last = _where(ctx).begin();
|
||||
};
|
||||
auto const search_parser =
|
||||
bp::omit[*(bp::char_ - parser)] >>
|
||||
-bp::lexeme[bp::eps[before] >> bp::skip[parser] >> bp::eps[after]];
|
||||
|
||||
auto result = bp::prefix_parse(
|
||||
first, last, search_parser, bp::ws, bp::trace::off);
|
||||
static_assert(std::is_same_v<
|
||||
decltype(result),
|
||||
std::optional<std::optional<std::string>>>);
|
||||
static_assert(std::is_same_v<
|
||||
decltype(bp::prefix_parse(
|
||||
first, last, search_parser, bp::ws, bp::trace::off)),
|
||||
std::optional<std::optional<std::string>>>);
|
||||
}
|
||||
{
|
||||
std::string str = "";
|
||||
auto parser = bp::string("XYZ");
|
||||
bp::detail::attr_search_impl(str, parser, bp::ws, bp::trace::off);
|
||||
}
|
||||
{
|
||||
std::string str = "";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), std::begin(str));
|
||||
EXPECT_EQ(subrng.end(), std::begin(str));
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "");
|
||||
}
|
||||
{
|
||||
char const str[] = "not here";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), std::end(str));
|
||||
EXPECT_EQ(subrng.end(), std::end(str));
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "");
|
||||
}
|
||||
{
|
||||
char const str[] = "aaXYZb";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), str + 2);
|
||||
EXPECT_EQ(subrng.end(), str + 5);
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "XYZ");
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZab";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), str + 0);
|
||||
EXPECT_EQ(subrng.end(), str + 3);
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "XYZ");
|
||||
}
|
||||
{
|
||||
char const str[] = "gbXYZ";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), str + 2);
|
||||
EXPECT_EQ(subrng.end(), str + 5);
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "XYZ");
|
||||
}
|
||||
{
|
||||
char const str[] = "XYZ";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), str + 0);
|
||||
EXPECT_EQ(subrng.end(), str + 3);
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "XYZ");
|
||||
}
|
||||
{
|
||||
char const str[] = "XXYZZ";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), str + 1);
|
||||
EXPECT_EQ(subrng.end(), str + 4);
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "XYZ");
|
||||
}
|
||||
{
|
||||
char const str[] = "XXYZZ";
|
||||
auto result = bp::detail::attr_search_repack_shim(
|
||||
str, bp::string("XYZ"), bp::ws, bp::trace::off);
|
||||
auto subrng = bp::get(result, 0_c);
|
||||
EXPECT_EQ(subrng.begin(), str + 1);
|
||||
EXPECT_EQ(subrng.end(), str + 4);
|
||||
auto result_str = bp::get(result, 1_c);
|
||||
EXPECT_EQ(result_str, "XYZ");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(transform_replace, transform_replace)
|
||||
{
|
||||
{
|
||||
auto r = bp::transform_replace("", bp::int_ % ',', bp::ws, f_str);
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const str[] = "ab c 1, 2, 3 d e f";
|
||||
auto r = bp::transform_replace(str, bp::int_ % ',', bp::ws, f_str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
EXPECT_EQ(replace_result, "ab c 1_2_3_ d e f");
|
||||
}
|
||||
{
|
||||
char const str[] = "ab c 1, 2, 3 d e f";
|
||||
auto r = bp::transform_replace(str, bp::int_ % ',', bp::ws, f_str_ref);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 3);
|
||||
EXPECT_EQ(replace_result, "ab c 1_2_3_ d e f");
|
||||
}
|
||||
{
|
||||
char const str[] = "a a 1,2,3baa ba1 ,2 , 3";
|
||||
auto r = str | bp::transform_replace(
|
||||
bp::int_ % ',', bp::ws, f_str, bp::trace::off);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "a a 1_2_3_baa ba1_2_3_");
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str[] = "aa1,2,3baaba1,2,3 4,5,6";
|
||||
auto r = str | bp::transform_replace(bp::int_ % ',', f_str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "aa1_2_3_baaba1_2_3_ 4_5_6_");
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
{
|
||||
char const str[] = "0,0aa1,2,3baaba1,2,3 4,5,6";
|
||||
auto r = str | bp::transform_replace(bp::int_ % ',', f_str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "0_0_aa1_2_3_baaba1_2_3_ 4_5_6_");
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
{
|
||||
char const str[] = "88,88 0,0aa1,2,3baaba1,2,3 4,5,6";
|
||||
auto r = str | bp::transform_replace(bp::int_ % ',', f_str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "88_88_ 0_0_aa1_2_3_baaba1_2_3_ 4_5_6_");
|
||||
EXPECT_EQ(count, 9);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(transform_replace, transform_replace_unicode)
|
||||
{
|
||||
{
|
||||
char const str_[] = "";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = bp::transform_replace(str, bp::int_ % ',', bp::ws, f_u16str);
|
||||
int count = 0;
|
||||
for (auto subrange : r) {
|
||||
(void)subrange;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(count, 0);
|
||||
}
|
||||
{
|
||||
char const * str_ = "aa2,3,4b";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = bp::transform_replace(str, bp::int_ % ',', bp::ws, f_u16str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "aa2_3_4_b");
|
||||
EXPECT_EQ(count, 3);
|
||||
}
|
||||
{
|
||||
char const str_[] = "a a 3,4,5 baaba7, 8 ,9";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r = str | bp::transform_replace(
|
||||
bp::int_ % ',', bp::ws, f_u32str, bp::trace::off);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "a a 3_4_5_ baaba7_8_9_");
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aa88,99baaba111,2222";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
const auto r = str | bp::transform_replace(
|
||||
bp::int_ % ',', f_u16str, bp::trace::off);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "aa88_99_baaba111_2222_");
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aa88,99baaba111,2222";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto r = str | bp::transform_replace(bp::int_ % ',', f_u32str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "aa88_99_baaba111_2222_");
|
||||
EXPECT_EQ(count, 4);
|
||||
}
|
||||
{
|
||||
char const str_[] = "aa88,99baaba111,2222 3,4";
|
||||
auto str = str_ | bp::as_utf32;
|
||||
auto r = str | bp::transform_replace(bp::int_ % ',', f_u16str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "aa88_99_baaba111_2222_ 3_4_");
|
||||
EXPECT_EQ(count, 6);
|
||||
}
|
||||
{
|
||||
char const str_[] = "1aa88,99baaba111,2222 3,4";
|
||||
auto str = str_ | bp::as_utf8;
|
||||
auto r = str | bp::transform_replace(bp::int_ % ',', f_u32str);
|
||||
int count = 0;
|
||||
std::string replace_result;
|
||||
for (auto subrange : r) {
|
||||
std::string str(subrange.begin(), subrange.end());
|
||||
replace_result += str;
|
||||
++count;
|
||||
}
|
||||
EXPECT_EQ(replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
|
||||
EXPECT_EQ(count, 7);
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_PARSER_USE_CONCEPTS && (!defined(__GNUC__) || 12 <= __GNUC__)
|
||||
// Older GCCs don't like the use of temporaries like the std::string("foo")
|
||||
// below. This causes | join to break.
|
||||
TEST(transform_replace, join_compat)
|
||||
{
|
||||
{
|
||||
char const str_[] = "1aa88,99baaba111,2222 3,4";
|
||||
auto str = str_ | bp::as_utf16;
|
||||
auto rng = str | bp::transform_replace(bp::int_ % ',', f_u32str) |
|
||||
std::views::join;
|
||||
std::string transform_replace_result;
|
||||
for (auto ch : rng) {
|
||||
static_assert(std::is_same_v<decltype(ch), char16_t>);
|
||||
transform_replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
|
||||
}
|
||||
{
|
||||
char const str[] = "1aa88,99baaba111,2222 3,4";
|
||||
auto rng = str | bp::as_utf32 |
|
||||
bp::transform_replace(bp::int_ % ',', f_u8str) |
|
||||
std::views::join;
|
||||
std::string transform_replace_result;
|
||||
for (auto ch : rng) {
|
||||
static_assert(std::is_same_v<decltype(ch), char32_t>);
|
||||
transform_replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
|
||||
}
|
||||
|
||||
{
|
||||
char const str[] = "1aa88,99baaba111,2222 3,4";
|
||||
auto rng = str | bp::transform_replace(bp::int_ % ',', f_str) |
|
||||
std::views::join;
|
||||
std::string transform_replace_result;
|
||||
for (auto ch : rng) {
|
||||
transform_replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
|
||||
}
|
||||
{
|
||||
std::string str = "1aa88,99baaba111,2222 3,4";
|
||||
auto rng = str | bp::transform_replace(bp::int_ % ',', f_str) |
|
||||
std::views::join;
|
||||
std::string transform_replace_result;
|
||||
for (auto ch : rng) {
|
||||
transform_replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
|
||||
}
|
||||
{
|
||||
std::string const str = "1aa88,99baaba111,2222 3,4";
|
||||
auto rng = str | bp::transform_replace(bp::int_ % ',', f_str) |
|
||||
std::views::join;
|
||||
std::string transform_replace_result;
|
||||
for (auto ch : rng) {
|
||||
transform_replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
|
||||
}
|
||||
{
|
||||
auto rng = std::string("1aa88,99baaba111,2222 3,4") |
|
||||
bp::transform_replace(bp::int_ % ',', f_str) |
|
||||
std::views::join;
|
||||
std::string transform_replace_result;
|
||||
for (auto ch : rng) {
|
||||
transform_replace_result.push_back(ch);
|
||||
}
|
||||
EXPECT_EQ(transform_replace_result, "1_aa88_99_baaba111_2222_ 3_4_");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(transform_replace, doc_examples)
|
||||
{
|
||||
{
|
||||
auto string_sum = [](std::vector<int> const & ints) {
|
||||
return std::to_string(std::accumulate(ints.begin(), ints.end(), 0));
|
||||
};
|
||||
|
||||
auto rng = "There are groups of [1, 2, 3, 4, 5] in the set." |
|
||||
bp::transform_replace(
|
||||
'[' >> bp::int_ % ',' >> ']', bp::ws, string_sum);
|
||||
int count = 0;
|
||||
// Prints "There are groups of 15 in the set".
|
||||
for (auto subrange : rng) {
|
||||
for (auto ch : subrange) {
|
||||
std::cout << ch;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
std::cout << "\n";
|
||||
assert(count == 3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user