2
0
mirror of https://github.com/boostorg/parser.git synced 2026-01-21 05:02:14 +00:00

3 Commits

Author SHA1 Message Date
Zach Laine
20b017c965 Generated by Github action on push to master. 2024-01-18 06:56:05 +00:00
Zach Laine
c4d9e4fbcd Generated by Github action on push to master. 2024-01-18 06:27:48 +00:00
Zach Laine
c68897b9e6 Replace all the headers with a generated, unified header. 2024-01-17 23:52:18 -06:00
97 changed files with 27352 additions and 42914 deletions

View File

@@ -1,34 +0,0 @@
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

View File

@@ -2,9 +2,9 @@ name: macos-12 - Clang 13
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: Ubuntu-20.04 - GCC 9,10
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: Ubuntu-22.04 - GCC 10,11
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: windows-2019 - Visual Studio 2019
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -2,9 +2,9 @@ name: windows-2022 - Visual Studio 2022
on:
push:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
pull_request:
branches: [ master, develop, boost_review_changes ]
branches: [ master, develop ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)

View File

@@ -12,8 +12,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL Clang)
add_definitions(-g -Wall)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
add_definitions(-g -Wall)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL MSVC)
add_definitions(/W3)
endif ()
##################################################

View File

@@ -24,7 +24,6 @@ doxygen parser_reference
# note that there is no detail::unspecified -- this is a hack to get all
# the SFINAE code out of the API docs.
<doxygen:param>"PREDEFINED=\"BOOST_PARSER_DOXYGEN=1\" \\
\"BOOST_PARSER_USE_CONCEPTS=1\" \\
\"enable_if=detail::unspecified\""
<doxygen:param>HIDE_UNDOC_MEMBERS=NO
<doxygen:param>EXTRACT_PRIVATE=NO
@@ -38,7 +37,7 @@ doxygen parser_reference
}
run_doxygen [ glob ../include/boost/parser/*.hpp : ../include/boost/parser/concepts.hpp ] : "Reference" ;
run_doxygen [ glob ../include/boost/parser/*.hpp ] : "Reference" ;
xml parser
:

View File

@@ -100,43 +100,22 @@ 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` 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:
_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:
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]
@@ -163,8 +142,7 @@ However, it does not suit user needs in some ways.
rule.
* Spirit X3 is missing many of the convenient interfaces to parsers that
Spirit 2 had. For instance, you cannot add parameters to a parser (see
description of _locals_ in _more_about_rules_).
Spirit 2 had. For instance, you cannot add parameters to a parser.
* All versions of Spirit have Unicode support, but it is quite difficult to
get working.
@@ -185,104 +163,10 @@ that have been retained in _Parser_. Both libraries:
* use approximately the same set of directives to influence the parse
(e.g. `lexeme[]`);
* provide loosely-coupled rules that are separately compilable (at least for
Spirit X3); and
* are built around a flexible parse context object that has state added to and
removed from it during the parse (again, comparing to Spirit X3).
[heading The Spirit X3 rule problem]
Some readers have wanted a concrete example of my claim that Spirit X3's rules
do not compose well. Consider this program.
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <set>
#include <string>
#include <vector>
namespace x3 = boost::spirit::x3;
using ints_type = x3::rule<class ints, std::vector<int>>;
BOOST_SPIRIT_DECLARE(ints_type);
x3::rule<class ints, std::vector<int>> ints = "ints";
constexpr auto ints_def = x3::int_ % ',';
BOOST_SPIRIT_DEFINE(ints);
#define FIXED_ATTRIBUTE 0
int main()
{
std::string input = "43, 42";
auto first = input.begin();
auto const last = input.end();
#if FIXED_ATTRIBUTE
std::vector<int> result;
#else
std::set<int> result;
#endif
bool success = x3::phrase_parse(first, last, ints, x3::space, result);
if (success) {
// We want this to print "43 42\n".
for (auto x : result) {
std::cout << x << ' ';
}
std::cout << "\n";
}
return 0;
}
Defining `FIXED_ATTRIBUTE` to be `1` leads to a well-formed program that
prints `"42 43\n"` instead of the desired result. The problem here is that if
you feed an attribute out-param to `x3::phrase_parse()`, you get the
loose-match semantics that Spirit X3 and _Parser_ both do. This is a problem,
because the user explicitly asserted that the type of the `ints` rule's
attribute should be `std::vector<int>`. In my opinion, this code should be
ill-formed with `FIXED_ATTRIBUTE == 1`. To make it well-formed again, the
user could use `ints_def` directly, since it does not specify an attribute
type.
When the user explicitly states that a type is some fixed `T`, a library
should not ignore that. As a user of X3, I was bitten by this in such a way
that I considered X3 to be a nonviable option for my uses. I ran into a
problem that resulted from X3's ignoring one or more of my rules' attributes
so that it made the parse produce the wrong result, and I could see no way to
fix it.
When a library provides wider use cases via genericity, we generally consider
this a good thing. If it is too loose in its semantics, we generally say that
it is type-unsafe. Using _rs_ to nail down type flexibility is one way
_Parser_ tries to enable genericity where it is desired, and let the user turn
it off where it is not.
[endsect]
[section Cheat Sheet]
Here are all the tables containing the various _Parser_ parsers, examples,
etc., all in one place. These are repeated elsewhere in different sections of
the tutorial.
[heading The parsers]
[table_parsers_and_their_semantics]
[heading Operators defined on parsers]
[table_combining_operations]
[heading Attribute generation for certain parsers]
[table_attribute_generation]
[heading Attributes for operations on parsers]
[table_attribute_combinations]
[heading More attributes for operations on parsers]
[table_seq_or_attribute_combinations]
[endsect]

View File

@@ -36,11 +36,8 @@
[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]
[import ../test/parser.cpp]
[import ../test/parser_rule.cpp]
[import ../include/boost/parser/concepts.hpp]
[import ../include/boost/parser/error_handling_fwd.hpp]
@@ -69,17 +66,6 @@
[def _cb_r_ [classref boost::parser::callback_rule `callback_rule`]]
[def _cb_rs_ [classref boost::parser::callback_rules `callback_rule`s]]
[def _skp_p_ [classref boost::parser::skip_parser `skip_parser`]]
[def _xfm_p_ [classref boost::parser::transform_parser `tranform_parser`]]
[def _noc_p_ [classref boost::parser::no_case_parser `no_case_parser`]]
[def _sv_p_ [classref boost::parser::string_view_parser `string_view_parser`]]
[def _raw_p_ [classref boost::parser::raw_parser `raw_parser`]]
[def _omt_p_ [classref boost::parser::omit_parser `omit_parser`]]
[def _rpt_p_ [classref boost::parser::repeat_parser `repeat_parser`]]
[def _lex_p_ [classref boost::parser::lexeme_parser `lexeme_parser`]]
[def _seq_p_ [classref boost::parser::seq_parser `seq_parser`]]
[def _seq_ps_ [classref boost::parser::seq_parser `seq_parser`s]]
[def _bp_tup_ [classref boost::parser::tuple `boost::parser::tuple`]]
[def _bp_get_ [funcref boost::parser::get `boost::parser::get`]]
[def _bh_tup_ `boost::hana::tuple`]
@@ -90,22 +76,6 @@
[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>`]
@@ -118,9 +88,6 @@
[def _cbp_ [funcref boost::parser::callback_parse `callback_parse()`]]
[def _cbpp_ [funcref boost::parser::callback_prefix_parse `callback_prefix_parse()`]]
[def _attr_ [classref boost::parser::attribute `attribute`]]
[def _attr_t_ [classref boost::parser::attribute_t `attribute_t`]]
[def _w_glb_ [funcref boost::parser::with_globals `with_globals()`]]
[def _w_eh_ [funcref boost::parser::with_error_handler `with_error_handler()`]]
@@ -142,9 +109,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`]]
@@ -198,7 +165,6 @@
[def _skip_ [globalref boost::parser::skip `skip[]`]]
[def _merge_ [globalref boost::parser::merge `merge[]`]]
[def _sep_ [globalref boost::parser::separate `separate[]`]]
[def _transform_ [globalref boost::parser::transform `transform(f)[]`]]
[def _omit_np_ [globalref boost::parser::omit `omit`]]
[def _raw_np_ [globalref boost::parser::raw `raw`]]
@@ -208,15 +174,19 @@
[def _skip_np_ [globalref boost::parser::skip `skip`]]
[def _merge_np_ [globalref boost::parser::merge `merge`]]
[def _sep_np_ [globalref boost::parser::separate `separate`]]
[def _transform_np_ [globalref boost::parser::transform `transform`]]
[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 _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 _RES_ ['[^RESOLVE]]`()`]
[def _RES_np_ ['[^RESOLVE]]]
@@ -224,11 +194,10 @@
[def _ATTR_np_ ['[^ATTR]]]
[def _p_api_ [link boost_parser__proposed_.tutorial.the__parse____api The `parse()` API]]
[def _parsers_uses_ [link boost_parser__proposed_.tutorial.the_parsers_and_their_uses The Parsers And Their Uses]]
[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_into__struct_s_and__class_es Parsing into `struct`s and `class`es]]
[def _expect_pts_ [link boost_parser__proposed_.tutorial.backtracking.expectation_points Expectation points]]
[def _parsing_structs_ [link boost_parser__proposed_.tutorial.parsing__struct_s Parsing `struct`s]]
[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]]
[def _eh_debugging_ [link boost_parser__proposed_.tutorial.error_handling_and_debugging Error Handling and Debugging]]
@@ -254,7 +223,6 @@
[def _emdash_ \u2014]
[include tables.qbk]
[include intro.qbk]
[include tutorial.qbk]
[include examples.qbk]

View File

@@ -275,54 +275,4 @@ 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]

View File

@@ -1,572 +0,0 @@
[/
/ 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)
/]
[template table_parsers_and_their_semantics
This table lists all the _Parser_ parsers. For the callable parsers, a
separate entry exists for each possible arity of arguments. For a parser `p`,
if there is no entry for `p` without arguments, `p` is a function, and cannot
itself be used as a parser; it must be called. In the table below:
* each entry is a global object usable directly in your parsers, unless
otherwise noted;
* "code point" is used to refer to the elements of the input range, which
assumes that the parse is being done in the Unicode-aware code path (if the
parse is being done in the non-Unicode code path, read "code point" as
"`char`");
* _RES_ is a notional macro that expands to the resolution of parse argument
or evaluation of a parse predicate (see _parsers_uses_);
* "`_RES_np_(pred) == true`" is a shorthand notation for "`_RES_np_(pred)` is
contextually convertible to `bool` and `true`"; likewise for `false`;
* `c` is a character of type `char`, `char8_t`, or `char32_t`;
* `str` is a string literal of type `char const[]`, `char8_t const []`, or
`char32_t const []`;
* `pred` is a parse predicate;
* `arg0`, `arg1`, `arg2`, ... are parse arguments;
* `a` is a semantic action;
* `r` is an object whose type models `parsable_range_like`; and
* `p`, `p1`, `p2`, ... are parsers.
[note The definition of `parsable_range_like` is:
[parsable_range_like_concept]
It is intended to be a range-like thing; a null-terminated sequence of
characters is considered range-like, given that a pointer `T *` to a
null-terminated string is isomorphic with `subrange<T *, _null_sent_>`.]
[note Some of the parsers in this table consume no input. All parsers consume
the input they match unless otherwise stated in the table below.]
[table Parsers and Their Semantics
[[Parser] [Semantics] [Attribute Type] [Notes]]
[[ _e_ ]
[ Matches /epsilon/, the empty string. Always matches, and consumes no input. ]
[ None. ]
[ Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `*_e_`, `+_e_`, etc (this applies to unconditional _e_ only). ]]
[[ `_e_(pred)` ]
[ Fails to match the input if `_RES_np_(pred) == false`. Otherwise, the semantics are those of _e_. ]
[ None. ]
[]]
[[ _ws_ ]
[ Matches a single whitespace code point (see note), according to the Unicode White_Space property. ]
[ None. ]
[ For more info, see the [@https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt Unicode properties]. _ws_ may consume one code point or two. It only consumes two code points when it matches `"\r\n"`. ]]
[[ _eol_ ]
[ Matches a single newline (see note), following the "hard" line breaks in the Unicode line breaking algorithm. ]
[ None. ]
[ For more info, see the [@https://unicode.org/reports/tr14 Unicode Line Breaking Algorithm]. _eol_ may consume one code point or two. It only consumes two code points when it matches `"\r\n"`. ]]
[[ _eoi_ ]
[ Matches only at the end of input, and consumes no input. ]
[ None. ]
[]]
[[ _attr_np_`(arg0)` ]
[ Always matches, and consumes no input. Generates the attribute `_RES_np_(arg0)`. ]
[ `decltype(_RES_np_(arg0))`. ]
[ An important use case for `_attr_` is to provide a default attribute value as a trailing alternative. For instance, an *optional* comma-delmited list is: `int_ % ',' | attr(std::vector<int>)`. Without the "`| attr(...)`", at least one `int_` match would be required. ]]
[[ _ch_ ]
[ Matches any single code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[]]
[[ `_ch_(arg0)` ]
[ Matches exactly the code point `_RES_np_(arg0)`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[]]
[[ `_ch_(arg0, arg1)` ]
[ Matches the next code point `n` in the input, if `_RES_np_(arg0) <= n && n <= _RES_np_(arg1)`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[]]
[[ `_ch_(r)` ]
[ Matches the next code point `n` in the input, if `n` is one of the code points in `r`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See _attr_gen_. ]
[ `r` is taken to be in a UTF encoding. The exact UTF used depends on `r`'s element type. If you do not pass UTF encoded ranges for `r`, the behavior of _ch_ is undefined. Note that ASCII is a subset of UTF-8, so ASCII is fine. EBCDIC is not. `r` is not copied; a reference to it is taken. The lifetime of `_ch_(r)` must be within the lifetime of `r`. This overload of _ch_ does *not* take parse arguments. ]]
[[ _cp_ ]
[ Matches a single code point. ]
[ `char32_t` ]
[ Similar to _ch_, but with a fixed `char32_t` attribute type; _cp_ has all the same call operator overloads as _ch_, though they are not repeated here, for brevity. ]]
[[ _cu_ ]
[ Matches a single code point. ]
[ `char` ]
[ Similar to _ch_, but with a fixed `char` attribute type; _cu_ has all the same call operator overloads as _ch_, though they are not repeated here, for brevity. Even though the name "`cu`" suggests that this parser match at the code unit level, it does not. The name refers to the attribute type generated, much like the names _i_ versus _ui_. ]]
[[ `_blank_` ]
[ Equivalent to `_ws_ - _eol_`. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_control_` ]
[ Matches a single control-character code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_digit_` ]
[ Matches a single decimal digit code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_punct_` ]
[ Matches a single punctuation code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_hex_digit_` ]
[ Matches a single hexidecimal digit code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_lower_` ]
[ Matches a single lower-case code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ `_upper_` ]
[ Matches a single upper-case code point. ]
[ The code point type in Unicode parsing, or `char` in non-Unicode parsing. See the entry for _ch_. ]
[]]
[[ _lit_np_`(c)`]
[ Matches exactly the given code point `c`. ]
[ None. ]
[_lit_ does *not* take parse arguments. ]]
[[ `c_l` ]
[ Matches exactly the given code point `c`. ]
[ None. ]
[ This is a _udl_ that represents `_lit_np_(c)`, for example `'F'_l`. ]]
[[ _lit_np_`(r)`]
[ Matches exactly the given string `r`. ]
[ None. ]
[ _lit_ does *not* take parse arguments. ]]
[[ `str_l` ]
[ Matches exactly the given string `str`. ]
[ None. ]
[ This is a _udl_ that represents `_lit_np_(s)`, for example `"a string"_l`. ]]
[[ `_str_np_(r)`]
[ Matches exactly `r`, and generates the match as an attribute. ]
[ _std_str_ ]
[ _str_ does *not* take parse arguments. ]]
[[ `str_p`]
[ Matches exactly `str`, and generates the match as an attribute. ]
[ _std_str_ ]
[ This is a _udl_ that represents `_str_np_(s)`, for example `"a string"_p`. ]]
[[ _b_ ]
[ Matches `"true"` or `"false"`. ]
[ `bool` ]
[]]
[[ _bin_ ]
[ Matches a binary unsigned integral value. ]
[ `unsigned int` ]
[ For example, _bin_ would match `"101"`, and generate an attribute of `5u`. ]]
[[ `_bin_(arg0)` ]
[ Matches exactly the binary unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _oct_ ]
[ Matches an octal unsigned integral value. ]
[ `unsigned int` ]
[ For example, _oct_ would match `"31"`, and generate an attribute of `25u`. ]]
[[ `_oct_(arg0)` ]
[ Matches exactly the octal unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _hex_ ]
[ Matches a hexadecimal unsigned integral value. ]
[ `unsigned int` ]
[ For example, _hex_ would match `"ff"`, and generate an attribute of `255u`. ]]
[[ `_hex_(arg0)` ]
[ Matches exactly the hexadecimal unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _us_ ]
[ Matches an unsigned integral value. ]
[ `unsigned short` ]
[]]
[[ `_us_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned short` ]
[]]
[[ _ui_ ]
[ Matches an unsigned integral value. ]
[ `unsigned int` ]
[]]
[[ `_ui_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned int` ]
[]]
[[ _ul_ ]
[ Matches an unsigned integral value. ]
[ `unsigned long` ]
[]]
[[ `_ul_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned long` ]
[]]
[[ _ull_ ]
[ Matches an unsigned integral value. ]
[ `unsigned long long` ]
[]]
[[ `_ull_(arg0)` ]
[ Matches exactly the unsigned integral value `_RES_np_(arg0)`. ]
[ `unsigned long long` ]
[]]
[[ _s_ ]
[ Matches a signed integral value. ]
[ `short` ]
[]]
[[ `_s_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `short` ]
[]]
[[ _i_ ]
[ Matches a signed integral value. ]
[ `int` ]
[]]
[[ `_i_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `int` ]
[]]
[[ _l_ ]
[ Matches a signed integral value. ]
[ `long` ]
[]]
[[ `_l_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `long` ]
[]]
[[ _ll_ ]
[ Matches a signed integral value. ]
[ `long long` ]
[]]
[[ `_ll_(arg0)` ]
[ Matches exactly the signed integral value `_RES_np_(arg0)`. ]
[ `long long` ]
[]]
[[ _f_ ]
[ Matches a floating-point number. _f_ uses parsing implementation details from _Spirit_. The specifics of what formats are accepted can be found in their _spirit_reals_. Note that only the default `RealPolicies` is supported by _f_. ]
[ `float` ]
[]]
[[ _d_ ]
[ Matches a floating-point number. _d_ uses parsing implementation details from _Spirit_. The specifics of what formats are accepted can be found in their _spirit_reals_. Note that only the default `RealPolicies` is supported by _d_. ]
[ `double` ]
[]]
[[ `_rpt_np_(arg0)[p]` ]
[ Matches iff `p` matches exactly `_RES_np_(arg0)` times. ]
[ `std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>` ]
[ The special value _inf_ may be used; it indicates unlimited repetition. `decltype(_RES_np_(arg0))` must be implicitly convertible to `int64_t`. Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `_rpt_np_(_inf_)[_e_]` (this applies to unconditional _e_ only). ]]
[[ `_rpt_np_(arg0, arg1)[p]` ]
[ Matches iff `p` matches between `_RES_np_(arg0)` and `_RES_np_(arg1)` times, inclusively. ]
[ `std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>` ]
[ The special value _inf_ may be used for the upper bound; it indicates unlimited repetition. `decltype(_RES_np_(arg0))` and `decltype(_RES_np_(arg1))` each must be implicitly convertible to `int64_t`. Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `_rpt_np_(n, _inf_)[_e_]` (this applies to unconditional _e_ only). ]]
[[ `_if_np_(pred)[p]` ]
[ Equivalent to `_e_(pred) >> p`. ]
[ `std::optional<_ATTR_np_(p)>` ]
[ It is an error to write `_if_np_(pred)`. That is, it is an error to omit the conditionally matched parser `p`. ]]
[[ `_sw_np_(arg0)(arg1, p1)(arg2, p2) ...` ]
[ Equivalent to `p1` when `_RES_np_(arg0) == _RES_np_(arg1)`, `p2` when `_RES_np_(arg0) == _RES_np_(arg2)`, etc. If there is such no `argN`, the behavior of _sw_ is undefined. ]
[ `std::variant<_ATTR_np_(p1), _ATTR_np_(p2), ...>` ]
[ It is an error to write `_sw_np_(arg0)`. That is, it is an error to omit the conditionally matched parsers `p1`, `p2`, .... ]]
[[ _symbols_t_ ]
[ _symbols_ is an associative container of key, value pairs. Each key is a _std_str_ and each value has type `T`. In the Unicode parsing path, the strings are considered to be UTF-8 encoded; in the non-Unicode path, no encoding is assumed. _symbols_ Matches the longest prefix `pre` of the input that is equal to one of the keys `k`. If the length `len` of `pre` is zero, and there is no zero-length key, it does not match the input. If `len` is positive, the generated attribute is the value associated with `k`.]
[ `T` ]
[ Unlike the other entries in this table, _symbols_ is a type, not an object. ]]
]
[important All the character parsers, like _ch_, _cp_ and _cu_ produce either
`char` or `char32_t` attributes. So when you see "`std::string` if
`_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`"
in the table above, that effectively means that every sequences of character
attributes get turned into a `std::string`. The only time this does not
happen is when you introduce your own rules with attributes using another
character type (or use _attr_ to do so).]
]
[template table_combining_operations
Here are all the operator overloaded for parsers. In the tables below:
* `c` is a character of type `char` or `char32_t`;
* `a` is a semantic action;
* `r` is an object whose type models `parsable_range_like` (see _concepts_);
and
* `p`, `p1`, `p2`, ... are parsers.
[note Some of the expressions in this table consume no input. All parsers
consume the input they match unless otherwise stated in the table below.]
[table Combining Operations and Their Semantics
[[Expression] [Semantics] [Attribute Type] [Notes]]
[[`!p`] [ Matches iff `p` does not match; consumes no input. ] [None.] []]
[[`&p`] [ Matches iff `p` matches; consumes no input. ] [None.] []]
[[`*p`] [ Parses using `p` repeatedly until `p` no longer matches; always matches. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `*_e_` (this applies to unconditional _e_ only). ]]
[[`+p`] [ Parses using `p` repeatedly until `p` no longer matches; matches iff `p` matches at least once. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] [ Matching _e_ an unlimited number of times creates an infinite loop, which is undefined behavior in C++. _Parser_ will assert in debug mode when it encounters `+_e_` (this applies to unconditional _e_ only). ]]
[[`-p`] [ Equivalent to `p | _e_`. ] [`std::optional<_ATTR_np_(p)>`] []]
[[`p1 >> p2`] [ Matches iff `p1` matches and then `p2` matches. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>>` is associative; `p1 >> p2 >> p3`, `(p1 >> p2) >> p3`, and `p1 >> (p2 >> p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. ]]
[[`p >> c`] [ Equivalent to `p >> lit(c)`. ] [`_ATTR_np_(p)`] []]
[[`p >> r`] [ Equivalent to `p >> lit(r)`. ] [`_ATTR_np_(p)`] []]
[[`p1 > p2`] [ Matches iff `p1` matches and then `p2` matches. No back-tracking is allowed after `p1` matches; if `p1` matches but then `p2` does not, the top-level parse fails. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `>` is associative; `p1 > p2 > p3`, `(p1 > p2) > p3`, and `p1 > (p2 > p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes; see _attr_gen_ for the full rules. ]]
[[`p > c`] [ Equivalent to `p > lit(c)`. ] [`_ATTR_np_(p)`] []]
[[`p > r`] [ Equivalent to `p > lit(r)`. ] [`_ATTR_np_(p)`] []]
[[`p1 | p2`] [ Matches iff either `p1` matches or `p2` matches. ] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>` (See note.)] [ `|` is associative; `p1 | p2 | p3`, `(p1 | p2) | p3`, and `p1 | (p2 | p3)` are all equivalent. This attribute type only applies to the case where `p1` and `p2` both generate attributes, and where the attribute types are different; see _attr_gen_ for the full rules. ]]
[[`p | c`] [ Equivalent to `p | lit(c)`. ] [`_ATTR_np_(p)`] []]
[[`p | r`] [ Equivalent to `p | lit(r)`. ] [`_ATTR_np_(p)`] []]
[[`p1 || p2`] [ Matches iff `p1` matches and `p2` matches, regardless of the order they match in. ] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`] [ `||` is associative; `p1 || p2 || p3`, `(p1 || p2) || p3`, and `p1 || (p2 || p3)` are all equivalent. It is an error to include a _e_ (conditional or non-conditional) in an `operator||` expression. Though the parsers are matched in any order, the attribute elements are always in the order written in the `operator||` expression. ]]
[[`p1 - p2`] [ Equivalent to `!p2 >> p1`. ] [`_ATTR_np_(p1)`] []]
[[`p - c`] [ Equivalent to `p - lit(c)`. ] [`_ATTR_np_(p)`] []]
[[`p - r`] [ Equivalent to `p - lit(r)`. ] [`_ATTR_np_(p)`] []]
[[`p1 % p2`] [ Equivalent to `p1 >> *(p2 >> p1)`. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p1)>`] []]
[[`p % c`] [ Equivalent to `p % lit(c)`. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] []]
[[`p % r`] [ Equivalent to `p % lit(r)`. ] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`] []]
[[`p[a]`] [ Matches iff `p` matches. If `p` matches, the semantic action `a` is executed. ] [None.] []]
]
[important All the character parsers, like _ch_, _cp_ and _cu_ produce either
`char` or `char32_t` attributes. So when you see "`std::string` if
`_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`"
in the table above, that effectively means that every sequences of character
attributes get turned into a `std::string`. The only time this does not
happen is when you introduce your own rules with attributes using another
character type (or use _attr_ to do so).]
There are a couple of special rules not captured in the table above:
First, the zero-or-more and one-or-more repetitions (`operator*()` and
`operator+()`, respectively) may collapse when combined. For any parser `p`,
`+(+p)` collapses to `+p`; `**p`, `*+p`, and `+*p` each collapse to just `*p`.
Second, using _e_ in an alternative parser as any alternative *except* the
last one is a common source of errors; _Parser_ disallows it. This is true
because, for any parser `p`, `_e_ | p` is equivalent to _e_, since _e_ always
matches. This is not true for _e_ parameterized with a condition. For any
condition `cond`, `_e_(cond)` is allowed to appear anywhere within an
alternative parser.
]
[template table_attribute_generation
This table summarizes the attributes generated for all _Parser_ parsers. In
the table below:
* _RES_ is a notional macro that expands to the resolution of parse argument
or evaluation of a parse predicate (see _parsers_uses_); and
* `x` and `y` represent arbitrary objects.
[table Parsers and Their Attributes
[[Parser] [Attribute Type] [Notes]]
[[ _e_ ] [ None. ] []]
[[ _eol_ ] [ None. ] []]
[[ _eoi_ ] [ None. ] []]
[[ `_attr_np_(x)` ] [ `decltype(_RES_np_(x))` ][]]
[[ _ch_ ] [ The code point type in Unicode parsing, or `char` in non-Unicode parsing; see below. ]
[Includes all the `_p` _udls_ that take a single character, and all character class parsers like `control` and `lower`.]]
[[ _cp_ ] [ `char32_t` ] []]
[[ _cu_ ] [ `char` ] []]
[[ `_lit_np_(x)`] [ None. ]
[Includes all the `_l` _udls_.]]
[[ `_str_np_(x)`] [ _std_str_ ]
[Includes all the `_p` _udls_ that take a string.]]
[[ _b_ ] [ `bool` ] []]
[[ _bin_ ] [ `unsigned int` ] []]
[[ _oct_ ] [ `unsigned int` ] []]
[[ _hex_ ] [ `unsigned int` ] []]
[[ _us_ ] [ `unsigned short` ] []]
[[ _ui_ ] [ `unsigned int` ] []]
[[ _ul_ ] [ `unsigned long` ] []]
[[ _ull_ ] [ `unsigned long long` ] []]
[[ _s_ ] [ `short` ] []]
[[ _i_ ] [ `int` ] []]
[[ _l_ ] [ `long` ] []]
[[ _ll_ ] [ `long long` ] []]
[[ _f_ ] [ `float` ] []]
[[ _d_ ] [ `double` ] []]
[[ _symbols_t_ ] [ `T` ] []]
]
_ch_ is a bit odd, since its attribute type is polymorphic. When you use _ch_
to parse text in the non-Unicode code path (i.e. a string of `char`), the
attribute is `char`. When you use the exact same _ch_ to parse in the
Unicode-aware code path, all matching is code point based, and so the
attribute type is the type used to represent code points, `char32_t`. All
parsing of UTF-8 falls under this case.
Here, we're parsing plain `char`s, meaning that the parsing is in the
non-Unicode code path, the attribute of _ch_ is `char`:
auto result = parse("some text", boost::parser::char_);
static_assert(std::is_same_v<decltype(result), std::optional<char>>));
When you parse UTF-8, the matching is done on a code point basis, so the
attribute type is `char32_t`:
auto result = parse("some text" | boost::parser::as_utf8, boost::parser::char_);
static_assert(std::is_same_v<decltype(result), std::optional<char32_t>>));
The good news is that usually you don't parse characters individually. When
you parse with _ch_, you usually parse repetition of then, which will produce
a _std_str_, regardless of whether you're in Unicode parsing mode or not. If
you do need to parse individual characters, and want to lock down their
attribute type, you can use _cp_ and/or _cu_ to enforce a non-polymorphic
attribute type.
]
[template table_attribute_combinations
Combining operations of course affect the generation of attributes. In the
tables below:
* `m` and `n` are parse arguments that resolve to integral values;
* `pred` is a parse predicate;
* `arg0`, `arg1`, `arg2`, ... are parse arguments;
* `a` is a semantic action; and
* `p`, `p1`, `p2`, ... are parsers that generate attributes.
[table Combining Operations and Their Attributes
[[Parser] [Attribute Type]]
[[`!p`] [None.]]
[[`&p`] [None.]]
[[`*p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`+p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`+*p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`*+p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`-p`] [`std::optional<_ATTR_np_(p)>`]]
[[`p1 >> p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 > p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 >> p2 >> p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 > p2 >> p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 >> p2 > p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 > p2 > p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 | p2`] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 | p2 | p3`] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 || p2`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p1 || p2 || p3`] [`_bp_tup_<_ATTR_np_(p1), _ATTR_np_(p2), _ATTR_np_(p3)>`]]
[[`p1 % p2`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p1)>`]]
[[`p[a]`] [None.]]
[[`_rpt_np_(arg0)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`_rpt_np_(arg0, arg1)[p]`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`_if_np_(pred)[p]`] [`std::optional<_ATTR_np_(p)>`]]
[[`_sw_np_(arg0)(arg1, p1)(arg2, p2)...`]
[`std::variant<_ATTR_np_(p1), _ATTR_np_(p2), ...>`]]
]
[important All the character parsers, like _ch_, _cp_ and _cu_ produce either
`char` or `char32_t` attributes. So when you see "`std::string` if
`_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`"
in the table above, that effectively means that every sequences of character
attributes get turned into a `std::string`. The only time this does not
happen is when you introduce your own rules with attributes using another
character type (or use _attr_ to do so).]
[important In case you did not notice it above, adding a semantic action to a
parser erases the parser's attribute. The attribute is still available inside
the semantic action as `_attr(ctx)`.]
]
[template table_seq_or_attribute_combinations
In the table: `a` is a semantic action; and `p`, `p1`, `p2`, ... are parsers
that generate attributes. Note that only `>>` is used here; `>` has the exact
same attribute generation rules.
[table Sequence and Alternative Combining Operations and Their Attributes
[[Expression] [Attribute Type]]
[[`_e_ >> _e_`] [None.]]
[[`p >> _e_`] [`_ATTR_np_(p)`]]
[[`_e_ >> p`] [`_ATTR_np_(p)`]]
[[`_cu_ >> _str_np_("str")`] [_std_str_]]
[[`_str_np_("str") >> _cu_`] [_std_str_]]
[[`*_cu_ >> _str_np_("str")`] [`_bp_tup_<std::string, std::string>`]]
[[`_str_np_("str") >> *_cu_`] [`_bp_tup_<std::string, std::string>`]]
[[`p >> p`] [`_bp_tup_<_ATTR_np_(p), _ATTR_np_(p)>`]]
[[`*p >> p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`p >> *p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`*p >> -p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`-p >> *p`] [`std::string` if `_ATTR_np_(p)` is `char` or `char32_t`, otherwise `std::vector<_ATTR_np_(p)>`]]
[[`_str_np_("str") >> -_cu_`] [_std_str_]]
[[`-_cu_ >> _str_np_("str")`] [_std_str_]]
[[`!p1 | p2[a]`] [None.]]
[[`p | p`] [`_ATTR_np_(p)`]]
[[`p1 | p2`] [`std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>`]]
[[`p | `_e_] [`std::optional<_ATTR_np_(p)>`]]
[[`p1 | p2 | _e_`] [`std::optional<std::variant<_ATTR_np_(p1), _ATTR_np_(p2)>>`]]
[[`p1 | p2[a] | p3`] [`std::optional<std::variant<_ATTR_np_(p1), _ATTR_np_(p3)>>`]]
]
]

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,6 @@ 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)

View File

@@ -172,13 +172,13 @@ namespace json {
}
};
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];
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];
// 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

View File

@@ -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::digit | bp::char_('0')) >>
-(bp::char_('.') >> +bp::digit) >>
-(bp::char_("eE") >> -bp::char_("+-") >> +bp::digit)]]
[parse_double];
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];
// Note how, in the next three parsers, we turn off backtracking by using
// > instead of >>, once we know that there is no backtracking alternative

View File

@@ -1,48 +0,0 @@
// 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";
}
//]
}
//]

View File

@@ -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_RULES(doubles);
BOOST_PARSER_DEFINE_RULE(doubles);
//]
//]

View File

@@ -35,7 +35,6 @@ int main()
auto const result = parse("X 9 X", parser, bp::ws);
assert(result && *result == 9);
//]
(void)result;
//[ self_filling_symbol_table_after_parse
assert(!parse("X", symbols));

View File

@@ -1,102 +0,0 @@
// Copyright (C) 2020 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_CONCEPTS_HPP
#define BOOST_PARSER_CONCEPTS_HPP
#include <boost/parser/config.hpp>
#include <boost/parser/parser_fwd.hpp>
#include <boost/parser/detail/text/transcode_view.hpp>
#if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
#include <ranges>
namespace boost { namespace parser {
//[ all_concepts
template<typename T>
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> ||
std::same_as<std::remove_cv_t<T>, char16_t>||
std::same_as<std::remove_cv_t<T>, char32_t>;
template<typename T>
concept parsable_iter =
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> &&
code_unit<std::ranges::range_value_t<T>>;
template<typename T>
concept parsable_pointer = std::is_pointer_v<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,
typename ErrorHandler,
typename GlobalState>
using minimal_parse_context = decltype(detail::make_context<false, false>(
std::declval<I>(),
std::declval<S>(),
std::declval<bool &>(),
std::declval<int &>(),
std::declval<ErrorHandler const &>(),
std::declval<detail::nope &>(),
std::declval<detail::symbol_table_tries_t &>()));
template<typename T, typename I, typename S, typename GlobalState>
concept error_handler =
requires (
T const & t,
I first,
S last,
parse_error<I> const & e,
diagnostic_kind kind,
std::string_view message,
minimal_parse_context<
I, S, T, GlobalState> const & context) {
{ t(first, last, e) } -> std::same_as<error_handler_result>;
t.diagnose(kind, message, context, first);
t.diagnose(kind, message, context);
};
//[ container_concept
template<typename T>
concept container = std::ranges::common_range<T> && requires(T t) {
{ t.insert(t.begin(), *t.begin()) }
-> std::same_as<std::ranges::iterator_t<T>>;
};
//]
//]
namespace detail {
template<typename T, typename U>
concept container_and_value_type = container<T> &&
(std::is_same_v<std::ranges::range_value_t<T>, U> ||
(std::is_same_v<T, std::string> && std::is_same_v<U, char32_t>));
}
}}
#endif
#endif

View File

@@ -1,101 +0,0 @@
// Copyright (C) 2020 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_CONFIG_HPP
#define BOOST_PARSER_CONFIG_HPP
#include <boost/parser/detail/debug_assert.hpp>
// Included for definition of __cpp_lib_concepts.
#include <iterator>
#ifdef BOOST_PARSER_DOXYGEN
/** Boost.Parser uses assertions (`BOOST_ASSERT()`) in several places to
indicate that your use of the library has an error in it. All of those
places could heve instead been ill-formed code, caught at compile time.
It is far quicker and easier to determine exactly where in your code such
an error is located if this is a runtime failure; you can just look at the
stack in your favorite debugger. However, if you want to make thes kinds
of errors always ill-formed code, define this macro. */
# define BOOST_PARSER_NO_RUNTIME_ASSERTIONS
/** Asserts that the given condition is true. If
`BOOST_PARSER_NO_RUNTIME_ASSERTIONS` macro is defined by the user,
`BOOST_PARSER_ASSERT` expends to a compile-time `static_assert()`.
Otherwise, it expands to a run-time `BOOST_ASSERT()`. */
# define BOOST_PARSER_ASSERT(condition)
/** Boost.Parser will automatically use concepts to constrain templates when
building in C++20 mode, if the compiler defines `__cpp_lib_concepts`. To
disable the use of concepts, define this macro. */
# define BOOST_PARSER_DISABLE_CONCEPTS
/** Define this macro to use `std::tuple` instead of `boost::hana::tuple`
throughout Boost.Parser. */
# define BOOST_PARSER_DISABLE_HANA_TUPLE
/** Boost.Parser automatically treats aggregate structs as if they were
tuples. It uses some metaprogramming to do this. The technique used has
a hard limit on the number of data members a struct can have. Re-define
this macro to change the hard limit. Note that large values may increase
compile times. */
# define BOOST_PARSER_MAX_AGGREGATE_SIZE 25
/** The subrange template that is used throughout Boost.Parser. This will be
`boost::parser::subrange` in C++17 builds, and `std::ranges::subrange` in
all other builds. */
# define BOOST_PARSER_SUBRANGE
#else
# ifdef BOOST_PARSER_NO_RUNTIME_ASSERTIONS
# define BOOST_PARSER_ASSERT(condition) static_assert(condition)
# elif defined(BOOST_PARSER_HAVE_BOOST_ASSERT)
# define BOOST_PARSER_ASSERT(condition) BOOST_ASSERT(condition)
# else
# define BOOST_PARSER_ASSERT(condition) assert(condition)
# endif
#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
# define BOOST_PARSER_USE_CONCEPTS 0
#endif
#if defined(__cpp_lib_ranges)
# define BOOST_PARSER_SUBRANGE std::ranges::subrange
#else
# include <boost/parser/subrange.hpp>
# define BOOST_PARSER_SUBRANGE boost::parser::subrange
#endif
#if defined(BOOST_PARSER_DISABLE_HANA_TUPLE)
# define BOOST_PARSER_USE_STD_TUPLE 1
#else
# define BOOST_PARSER_USE_STD_TUPLE 0
#endif
#if !defined(BOOST_PARSER_MAX_AGGREGATE_SIZE)
#define BOOST_PARSER_MAX_AGGREGATE_SIZE 25
#endif
// VS2019 and VS2017 need conditional constexpr in some places, even in C++17 mode.
#if !defined(_MSC_VER) || 1930 <= _MSC_VER
#define BOOST_PARSER_CONSTEXPR constexpr
#else
#define BOOST_PARSER_CONSTEXPR
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,109 +0,0 @@
#ifndef BOOST_PARSER_DETAIL_CASE_FOLD_HPP
#define BOOST_PARSER_DETAIL_CASE_FOLD_HPP
#include <boost/parser/config.hpp>
#include <boost/parser/detail/text/transcode_iterator.hpp>
#include <boost/parser/detail/case_fold_data_generated.hpp>
#include <algorithm>
namespace boost::parser::detail {
template<typename I>
std::optional<I> do_short_mapping(
short_mapping_range const * first,
short_mapping_range const * last,
char32_t cp,
I out)
{
auto it = std::lower_bound(
first,
last,
cp,
[](short_mapping_range const & range, char32_t cp) {
return range.cp_first_ < cp;
});
if (it != first) {
auto const prev = it - 1;
if (prev->cp_first_ <= cp && cp < prev->cp_last_)
it = prev;
}
if (it != last && it->cp_first_ <= cp && cp < it->cp_last_) {
auto const offset = cp - it->cp_first_;
if (offset % it->stride_ == 0) {
*out++ =
single_mapping_cps[it->first_idx_ + offset / it->stride_];
return out;
}
}
return std::nullopt;
}
template<typename I>
I case_fold(char32_t cp, I out)
{
// One-byte fast path.
if (cp < 0x100) {
// ASCII letter fast path.
if (0x41 <= cp && cp < 0x5a) {
*out++ = cp + 0x20;
return out;
} else if (cp == 0x00DF) {
// The lone multi-mapping below 0x100.
*out++ = 0x0073;
*out++ = 0x0073;
return out;
} else {
// Skip [0x41, 0x5a), handled above.
auto const first = text::detail::begin(mapping_ranges) + 1;
// 7th entry starts with 0x100.
auto const last = text::detail::begin(mapping_ranges) + 7;
if (auto out_opt = do_short_mapping(first, last, cp, out))
return *out_opt;
}
*out++ = cp;
return out;
}
// Single-cp-mapping path (next most common case).
{
auto const first = text::detail::begin(mapping_ranges);
auto const last = text::detail::end(mapping_ranges);
if (auto out_opt = do_short_mapping(first, last, cp, out))
return *out_opt;
}
// Multi-cp mapping path.
{
auto const last = detail::text::detail::end(long_mappings);
auto const it = std::lower_bound(
detail::text::detail::begin(long_mappings),
last,
cp,
[](long_mapping const & mapping, char32_t cp) {
return mapping.cp_ < cp;
});
if (it != last && it->cp_ == cp) {
#if BOOST_PARSER_USE_CONCEPTS
return std::ranges::copy(it->mapping_, text::null_sentinel, out)
.out;
#else
return std::copy(
it->mapping_,
std::find(
text::detail::begin(it->mapping_),
text::detail::end(it->mapping_),
0),
out);
#endif
}
}
*out++ = cp;
return out;
}
}
#endif

View File

@@ -1,533 +0,0 @@
// 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)
// Warning: This header is auto-generated (see misc/generate_case_fold_data.py).
// The lack of include guards is intentional.
namespace boost::parser::detail {
struct short_mapping_range {
char32_t cp_first_;
char32_t cp_last_;
uint16_t stride_;
uint16_t first_idx_;
};
inline constexpr int longest_mapping = 3;
struct long_mapping {
char32_t cp_;
char32_t mapping_[longest_mapping + 1];
};
inline constexpr long_mapping long_mappings[104] = {
{0x00DF, {0x0073, 0x0073 , 0}},
{0x0130, {0x0069, 0x0307 , 0}},
{0x0149, {0x02BC, 0x006E , 0}},
{0x01F0, {0x006A, 0x030C , 0}},
{0x0390, {0x03B9, 0x0308, 0x0301 , 0}},
{0x03B0, {0x03C5, 0x0308, 0x0301 , 0}},
{0x0587, {0x0565, 0x0582 , 0}},
{0x1E96, {0x0068, 0x0331 , 0}},
{0x1E97, {0x0074, 0x0308 , 0}},
{0x1E98, {0x0077, 0x030A , 0}},
{0x1E99, {0x0079, 0x030A , 0}},
{0x1E9A, {0x0061, 0x02BE , 0}},
{0x1E9E, {0x0073, 0x0073 , 0}},
{0x1F50, {0x03C5, 0x0313 , 0}},
{0x1F52, {0x03C5, 0x0313, 0x0300 , 0}},
{0x1F54, {0x03C5, 0x0313, 0x0301 , 0}},
{0x1F56, {0x03C5, 0x0313, 0x0342 , 0}},
{0x1F80, {0x1F00, 0x03B9 , 0}},
{0x1F81, {0x1F01, 0x03B9 , 0}},
{0x1F82, {0x1F02, 0x03B9 , 0}},
{0x1F83, {0x1F03, 0x03B9 , 0}},
{0x1F84, {0x1F04, 0x03B9 , 0}},
{0x1F85, {0x1F05, 0x03B9 , 0}},
{0x1F86, {0x1F06, 0x03B9 , 0}},
{0x1F87, {0x1F07, 0x03B9 , 0}},
{0x1F88, {0x1F00, 0x03B9 , 0}},
{0x1F89, {0x1F01, 0x03B9 , 0}},
{0x1F8A, {0x1F02, 0x03B9 , 0}},
{0x1F8B, {0x1F03, 0x03B9 , 0}},
{0x1F8C, {0x1F04, 0x03B9 , 0}},
{0x1F8D, {0x1F05, 0x03B9 , 0}},
{0x1F8E, {0x1F06, 0x03B9 , 0}},
{0x1F8F, {0x1F07, 0x03B9 , 0}},
{0x1F90, {0x1F20, 0x03B9 , 0}},
{0x1F91, {0x1F21, 0x03B9 , 0}},
{0x1F92, {0x1F22, 0x03B9 , 0}},
{0x1F93, {0x1F23, 0x03B9 , 0}},
{0x1F94, {0x1F24, 0x03B9 , 0}},
{0x1F95, {0x1F25, 0x03B9 , 0}},
{0x1F96, {0x1F26, 0x03B9 , 0}},
{0x1F97, {0x1F27, 0x03B9 , 0}},
{0x1F98, {0x1F20, 0x03B9 , 0}},
{0x1F99, {0x1F21, 0x03B9 , 0}},
{0x1F9A, {0x1F22, 0x03B9 , 0}},
{0x1F9B, {0x1F23, 0x03B9 , 0}},
{0x1F9C, {0x1F24, 0x03B9 , 0}},
{0x1F9D, {0x1F25, 0x03B9 , 0}},
{0x1F9E, {0x1F26, 0x03B9 , 0}},
{0x1F9F, {0x1F27, 0x03B9 , 0}},
{0x1FA0, {0x1F60, 0x03B9 , 0}},
{0x1FA1, {0x1F61, 0x03B9 , 0}},
{0x1FA2, {0x1F62, 0x03B9 , 0}},
{0x1FA3, {0x1F63, 0x03B9 , 0}},
{0x1FA4, {0x1F64, 0x03B9 , 0}},
{0x1FA5, {0x1F65, 0x03B9 , 0}},
{0x1FA6, {0x1F66, 0x03B9 , 0}},
{0x1FA7, {0x1F67, 0x03B9 , 0}},
{0x1FA8, {0x1F60, 0x03B9 , 0}},
{0x1FA9, {0x1F61, 0x03B9 , 0}},
{0x1FAA, {0x1F62, 0x03B9 , 0}},
{0x1FAB, {0x1F63, 0x03B9 , 0}},
{0x1FAC, {0x1F64, 0x03B9 , 0}},
{0x1FAD, {0x1F65, 0x03B9 , 0}},
{0x1FAE, {0x1F66, 0x03B9 , 0}},
{0x1FAF, {0x1F67, 0x03B9 , 0}},
{0x1FB2, {0x1F70, 0x03B9 , 0}},
{0x1FB3, {0x03B1, 0x03B9 , 0}},
{0x1FB4, {0x03AC, 0x03B9 , 0}},
{0x1FB6, {0x03B1, 0x0342 , 0}},
{0x1FB7, {0x03B1, 0x0342, 0x03B9 , 0}},
{0x1FBC, {0x03B1, 0x03B9 , 0}},
{0x1FC2, {0x1F74, 0x03B9 , 0}},
{0x1FC3, {0x03B7, 0x03B9 , 0}},
{0x1FC4, {0x03AE, 0x03B9 , 0}},
{0x1FC6, {0x03B7, 0x0342 , 0}},
{0x1FC7, {0x03B7, 0x0342, 0x03B9 , 0}},
{0x1FCC, {0x03B7, 0x03B9 , 0}},
{0x1FD2, {0x03B9, 0x0308, 0x0300 , 0}},
{0x1FD3, {0x03B9, 0x0308, 0x0301 , 0}},
{0x1FD6, {0x03B9, 0x0342 , 0}},
{0x1FD7, {0x03B9, 0x0308, 0x0342 , 0}},
{0x1FE2, {0x03C5, 0x0308, 0x0300 , 0}},
{0x1FE3, {0x03C5, 0x0308, 0x0301 , 0}},
{0x1FE4, {0x03C1, 0x0313 , 0}},
{0x1FE6, {0x03C5, 0x0342 , 0}},
{0x1FE7, {0x03C5, 0x0308, 0x0342 , 0}},
{0x1FF2, {0x1F7C, 0x03B9 , 0}},
{0x1FF3, {0x03C9, 0x03B9 , 0}},
{0x1FF4, {0x03CE, 0x03B9 , 0}},
{0x1FF6, {0x03C9, 0x0342 , 0}},
{0x1FF7, {0x03C9, 0x0342, 0x03B9 , 0}},
{0x1FFC, {0x03C9, 0x03B9 , 0}},
{0xFB00, {0x0066, 0x0066 , 0}},
{0xFB01, {0x0066, 0x0069 , 0}},
{0xFB02, {0x0066, 0x006C , 0}},
{0xFB03, {0x0066, 0x0066, 0x0069 , 0}},
{0xFB04, {0x0066, 0x0066, 0x006C , 0}},
{0xFB05, {0x0073, 0x0074 , 0}},
{0xFB06, {0x0073, 0x0074 , 0}},
{0xFB13, {0x0574, 0x0576 , 0}},
{0xFB14, {0x0574, 0x0565 , 0}},
{0xFB15, {0x0574, 0x056B , 0}},
{0xFB16, {0x057E, 0x0576 , 0}},
{0xFB17, {0x0574, 0x056D , 0}},
};
inline constexpr short_mapping_range mapping_ranges[220] = {
{0x0041, 0x005A, 1, 0},
{0x005A, 0x00B5, 91, 25},
{0x00B5, 0x00C0, 11, 26},
{0x00C0, 0x00D6, 1, 27},
{0x00D6, 0x00D8, 2, 49},
{0x00D8, 0x00DE, 1, 50},
{0x00DE, 0x0100, 34, 56},
{0x0100, 0x012E, 2, 57},
{0x012E, 0x0132, 4, 80},
{0x0132, 0x0136, 2, 81},
{0x0136, 0x0139, 3, 83},
{0x0139, 0x0147, 2, 84},
{0x0147, 0x014A, 3, 91},
{0x014A, 0x0178, 2, 92},
{0x0178, 0x0179, 1, 115},
{0x0179, 0x0181, 2, 116},
{0x0181, 0x0182, 1, 120},
{0x0182, 0x0186, 2, 121},
{0x0186, 0x0187, 1, 123},
{0x0187, 0x0189, 2, 124},
{0x0189, 0x018B, 1, 125},
{0x018B, 0x018E, 3, 127},
{0x018E, 0x0191, 1, 128},
{0x0191, 0x0193, 2, 131},
{0x0193, 0x0194, 1, 132},
{0x0194, 0x0196, 2, 133},
{0x0196, 0x0198, 1, 134},
{0x0198, 0x019C, 4, 136},
{0x019C, 0x019D, 1, 137},
{0x019D, 0x019F, 2, 138},
{0x019F, 0x01A0, 1, 139},
{0x01A0, 0x01A6, 2, 140},
{0x01A6, 0x01A7, 1, 143},
{0x01A7, 0x01A9, 2, 144},
{0x01A9, 0x01AC, 3, 145},
{0x01AC, 0x01AE, 2, 146},
{0x01AE, 0x01AF, 1, 147},
{0x01AF, 0x01B1, 2, 148},
{0x01B1, 0x01B3, 1, 149},
{0x01B3, 0x01B7, 2, 151},
{0x01B7, 0x01B8, 1, 153},
{0x01B8, 0x01BC, 4, 154},
{0x01BC, 0x01C4, 8, 155},
{0x01C4, 0x01C5, 1, 156},
{0x01C5, 0x01C7, 2, 157},
{0x01C7, 0x01C8, 1, 158},
{0x01C8, 0x01CA, 2, 159},
{0x01CA, 0x01CB, 1, 160},
{0x01CB, 0x01DB, 2, 161},
{0x01DB, 0x01DE, 3, 169},
{0x01DE, 0x01EE, 2, 170},
{0x01EE, 0x01F1, 3, 178},
{0x01F1, 0x01F2, 1, 179},
{0x01F2, 0x01F6, 2, 180},
{0x01F6, 0x01F8, 1, 182},
{0x01F8, 0x0232, 2, 184},
{0x0232, 0x023A, 8, 213},
{0x023A, 0x023B, 1, 214},
{0x023B, 0x023D, 2, 215},
{0x023D, 0x023E, 1, 216},
{0x023E, 0x0241, 3, 217},
{0x0241, 0x0243, 2, 218},
{0x0243, 0x0246, 1, 219},
{0x0246, 0x024E, 2, 222},
{0x024E, 0x0345, 247, 226},
{0x0345, 0x0370, 43, 227},
{0x0370, 0x0372, 2, 228},
{0x0372, 0x0376, 4, 229},
{0x0376, 0x037F, 9, 230},
{0x037F, 0x0386, 7, 231},
{0x0386, 0x0388, 2, 232},
{0x0388, 0x038A, 1, 233},
{0x038A, 0x038E, 2, 235},
{0x038E, 0x038F, 1, 237},
{0x038F, 0x0391, 2, 238},
{0x0391, 0x03A1, 1, 239},
{0x03A1, 0x03A3, 2, 255},
{0x03A3, 0x03AB, 1, 256},
{0x03AB, 0x03C2, 23, 264},
{0x03C2, 0x03CF, 13, 265},
{0x03CF, 0x03D1, 1, 266},
{0x03D1, 0x03D5, 4, 268},
{0x03D5, 0x03D6, 1, 269},
{0x03D6, 0x03F0, 2, 270},
{0x03F0, 0x03F1, 1, 283},
{0x03F1, 0x03F4, 3, 284},
{0x03F4, 0x03F5, 1, 285},
{0x03F5, 0x03F9, 2, 286},
{0x03F9, 0x03FA, 1, 288},
{0x03FA, 0x03FD, 3, 289},
{0x03FD, 0x042F, 1, 290},
{0x042F, 0x0460, 49, 340},
{0x0460, 0x0480, 2, 341},
{0x0480, 0x048A, 10, 357},
{0x048A, 0x04C0, 2, 358},
{0x04C0, 0x04C1, 1, 385},
{0x04C1, 0x04CD, 2, 386},
{0x04CD, 0x04D0, 3, 392},
{0x04D0, 0x052E, 2, 393},
{0x052E, 0x0531, 3, 440},
{0x0531, 0x0556, 1, 441},
{0x0556, 0x10A0, 2890, 478},
{0x10A0, 0x10C5, 1, 479},
{0x10C5, 0x10C7, 2, 516},
{0x10C7, 0x10CD, 6, 517},
{0x10CD, 0x13F8, 811, 518},
{0x13F8, 0x13FD, 1, 519},
{0x13FD, 0x1C80, 2179, 524},
{0x1C80, 0x1C88, 1, 525},
{0x1C88, 0x1C90, 8, 533},
{0x1C90, 0x1CBA, 1, 534},
{0x1CBA, 0x1CBD, 3, 576},
{0x1CBD, 0x1CBF, 1, 577},
{0x1CBF, 0x1E00, 321, 579},
{0x1E00, 0x1E94, 2, 580},
{0x1E94, 0x1E9B, 7, 654},
{0x1E9B, 0x1EA0, 5, 655},
{0x1EA0, 0x1EFE, 2, 656},
{0x1EFE, 0x1F08, 10, 703},
{0x1F08, 0x1F0F, 1, 704},
{0x1F0F, 0x1F18, 9, 711},
{0x1F18, 0x1F1D, 1, 712},
{0x1F1D, 0x1F28, 11, 717},
{0x1F28, 0x1F2F, 1, 718},
{0x1F2F, 0x1F38, 9, 725},
{0x1F38, 0x1F3F, 1, 726},
{0x1F3F, 0x1F48, 9, 733},
{0x1F48, 0x1F4D, 1, 734},
{0x1F4D, 0x1F59, 12, 739},
{0x1F59, 0x1F5F, 2, 740},
{0x1F5F, 0x1F68, 9, 743},
{0x1F68, 0x1F6F, 1, 744},
{0x1F6F, 0x1FB8, 73, 751},
{0x1FB8, 0x1FBB, 1, 752},
{0x1FBB, 0x1FBE, 3, 755},
{0x1FBE, 0x1FC8, 10, 756},
{0x1FC8, 0x1FCB, 1, 757},
{0x1FCB, 0x1FD8, 13, 760},
{0x1FD8, 0x1FDB, 1, 761},
{0x1FDB, 0x1FE8, 13, 764},
{0x1FE8, 0x1FEC, 1, 765},
{0x1FEC, 0x1FF8, 12, 769},
{0x1FF8, 0x1FFB, 1, 770},
{0x1FFB, 0x2126, 299, 773},
{0x2126, 0x212A, 4, 774},
{0x212A, 0x212B, 1, 775},
{0x212B, 0x2132, 7, 776},
{0x2132, 0x2160, 46, 777},
{0x2160, 0x216F, 1, 778},
{0x216F, 0x2183, 20, 793},
{0x2183, 0x24B6, 819, 794},
{0x24B6, 0x24CF, 1, 795},
{0x24CF, 0x2C00, 1841, 820},
{0x2C00, 0x2C2F, 1, 821},
{0x2C2F, 0x2C60, 49, 868},
{0x2C60, 0x2C62, 2, 869},
{0x2C62, 0x2C64, 1, 870},
{0x2C64, 0x2C67, 3, 872},
{0x2C67, 0x2C6D, 2, 873},
{0x2C6D, 0x2C70, 1, 876},
{0x2C70, 0x2C72, 2, 879},
{0x2C72, 0x2C75, 3, 880},
{0x2C75, 0x2C7E, 9, 881},
{0x2C7E, 0x2C80, 1, 882},
{0x2C80, 0x2CE2, 2, 884},
{0x2CE2, 0x2CEB, 9, 933},
{0x2CEB, 0x2CED, 2, 934},
{0x2CED, 0x2CF2, 5, 935},
{0x2CF2, 0xA640, 31054, 936},
{0xA640, 0xA66C, 2, 937},
{0xA66C, 0xA680, 20, 959},
{0xA680, 0xA69A, 2, 960},
{0xA69A, 0xA722, 136, 973},
{0xA722, 0xA72E, 2, 974},
{0xA72E, 0xA732, 4, 980},
{0xA732, 0xA76E, 2, 981},
{0xA76E, 0xA779, 11, 1011},
{0xA779, 0xA77D, 2, 1012},
{0xA77D, 0xA77E, 1, 1014},
{0xA77E, 0xA786, 2, 1015},
{0xA786, 0xA78B, 5, 1019},
{0xA78B, 0xA78D, 2, 1020},
{0xA78D, 0xA790, 3, 1021},
{0xA790, 0xA792, 2, 1022},
{0xA792, 0xA796, 4, 1023},
{0xA796, 0xA7AA, 2, 1024},
{0xA7AA, 0xA7AE, 1, 1034},
{0xA7AE, 0xA7B0, 2, 1038},
{0xA7B0, 0xA7B4, 1, 1039},
{0xA7B4, 0xA7C4, 2, 1043},
{0xA7C4, 0xA7C7, 1, 1051},
{0xA7C7, 0xA7C9, 2, 1054},
{0xA7C9, 0xA7D0, 7, 1055},
{0xA7D0, 0xA7D6, 6, 1056},
{0xA7D6, 0xA7D8, 2, 1057},
{0xA7D8, 0xA7F5, 29, 1058},
{0xA7F5, 0xAB70, 891, 1059},
{0xAB70, 0xABBF, 1, 1060},
{0xABBF, 0xFF21, 21346, 1139},
{0xFF21, 0xFF3A, 1, 1140},
{0xFF3A, 0x10400, 1222, 1165},
{0x10400, 0x10427, 1, 1166},
{0x10427, 0x104B0, 137, 1205},
{0x104B0, 0x104D3, 1, 1206},
{0x104D3, 0x10570, 157, 1241},
{0x10570, 0x1057A, 1, 1242},
{0x1057A, 0x1057C, 2, 1252},
{0x1057C, 0x1058A, 1, 1253},
{0x1058A, 0x1058C, 2, 1267},
{0x1058C, 0x10592, 1, 1268},
{0x10592, 0x10594, 2, 1274},
{0x10594, 0x10595, 1, 1275},
{0x10595, 0x10C80, 1771, 1276},
{0x10C80, 0x10CB2, 1, 1277},
{0x10CB2, 0x118A0, 3054, 1327},
{0x118A0, 0x118BF, 1, 1328},
{0x118BF, 0x16E40, 21889, 1359},
{0x16E40, 0x16E5F, 1, 1360},
{0x16E5F, 0x1E900, 31393, 1391},
{0x1E900, 0x1E921 + 1, 1, 1392},
};
inline constexpr char32_t single_mapping_cps[1426] = {
0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068,
0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
0x0079, 0x007A, 0x03BC, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4,
0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC,
0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4,
0x00F5, 0x00F6, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD,
0x00FE, 0x0101, 0x0103, 0x0105, 0x0107, 0x0109, 0x010B, 0x010D,
0x010F, 0x0111, 0x0113, 0x0115, 0x0117, 0x0119, 0x011B, 0x011D,
0x011F, 0x0121, 0x0123, 0x0125, 0x0127, 0x0129, 0x012B, 0x012D,
0x012F, 0x0133, 0x0135, 0x0137, 0x013A, 0x013C, 0x013E, 0x0140,
0x0142, 0x0144, 0x0146, 0x0148, 0x014B, 0x014D, 0x014F, 0x0151,
0x0153, 0x0155, 0x0157, 0x0159, 0x015B, 0x015D, 0x015F, 0x0161,
0x0163, 0x0165, 0x0167, 0x0169, 0x016B, 0x016D, 0x016F, 0x0171,
0x0173, 0x0175, 0x0177, 0x00FF, 0x017A, 0x017C, 0x017E, 0x0073,
0x0253, 0x0183, 0x0185, 0x0254, 0x0188, 0x0256, 0x0257, 0x018C,
0x01DD, 0x0259, 0x025B, 0x0192, 0x0260, 0x0263, 0x0269, 0x0268,
0x0199, 0x026F, 0x0272, 0x0275, 0x01A1, 0x01A3, 0x01A5, 0x0280,
0x01A8, 0x0283, 0x01AD, 0x0288, 0x01B0, 0x028A, 0x028B, 0x01B4,
0x01B6, 0x0292, 0x01B9, 0x01BD, 0x01C6, 0x01C6, 0x01C9, 0x01C9,
0x01CC, 0x01CC, 0x01CE, 0x01D0, 0x01D2, 0x01D4, 0x01D6, 0x01D8,
0x01DA, 0x01DC, 0x01DF, 0x01E1, 0x01E3, 0x01E5, 0x01E7, 0x01E9,
0x01EB, 0x01ED, 0x01EF, 0x01F3, 0x01F3, 0x01F5, 0x0195, 0x01BF,
0x01F9, 0x01FB, 0x01FD, 0x01FF, 0x0201, 0x0203, 0x0205, 0x0207,
0x0209, 0x020B, 0x020D, 0x020F, 0x0211, 0x0213, 0x0215, 0x0217,
0x0219, 0x021B, 0x021D, 0x021F, 0x019E, 0x0223, 0x0225, 0x0227,
0x0229, 0x022B, 0x022D, 0x022F, 0x0231, 0x0233, 0x2C65, 0x023C,
0x019A, 0x2C66, 0x0242, 0x0180, 0x0289, 0x028C, 0x0247, 0x0249,
0x024B, 0x024D, 0x024F, 0x03B9, 0x0371, 0x0373, 0x0377, 0x03F3,
0x03AC, 0x03AD, 0x03AE, 0x03AF, 0x03CC, 0x03CD, 0x03CE, 0x03B1,
0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9,
0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1,
0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA,
0x03CB, 0x03C3, 0x03D7, 0x03B2, 0x03B8, 0x03C6, 0x03C0, 0x03D9,
0x03DB, 0x03DD, 0x03DF, 0x03E1, 0x03E3, 0x03E5, 0x03E7, 0x03E9,
0x03EB, 0x03ED, 0x03EF, 0x03BA, 0x03C1, 0x03B8, 0x03B5, 0x03F8,
0x03F2, 0x03FB, 0x037B, 0x037C, 0x037D, 0x0450, 0x0451, 0x0452,
0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A,
0x045B, 0x045C, 0x045D, 0x045E, 0x045F, 0x0430, 0x0431, 0x0432,
0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A,
0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442,
0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A,
0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0461, 0x0463, 0x0465,
0x0467, 0x0469, 0x046B, 0x046D, 0x046F, 0x0471, 0x0473, 0x0475,
0x0477, 0x0479, 0x047B, 0x047D, 0x047F, 0x0481, 0x048B, 0x048D,
0x048F, 0x0491, 0x0493, 0x0495, 0x0497, 0x0499, 0x049B, 0x049D,
0x049F, 0x04A1, 0x04A3, 0x04A5, 0x04A7, 0x04A9, 0x04AB, 0x04AD,
0x04AF, 0x04B1, 0x04B3, 0x04B5, 0x04B7, 0x04B9, 0x04BB, 0x04BD,
0x04BF, 0x04CF, 0x04C2, 0x04C4, 0x04C6, 0x04C8, 0x04CA, 0x04CC,
0x04CE, 0x04D1, 0x04D3, 0x04D5, 0x04D7, 0x04D9, 0x04DB, 0x04DD,
0x04DF, 0x04E1, 0x04E3, 0x04E5, 0x04E7, 0x04E9, 0x04EB, 0x04ED,
0x04EF, 0x04F1, 0x04F3, 0x04F5, 0x04F7, 0x04F9, 0x04FB, 0x04FD,
0x04FF, 0x0501, 0x0503, 0x0505, 0x0507, 0x0509, 0x050B, 0x050D,
0x050F, 0x0511, 0x0513, 0x0515, 0x0517, 0x0519, 0x051B, 0x051D,
0x051F, 0x0521, 0x0523, 0x0525, 0x0527, 0x0529, 0x052B, 0x052D,
0x052F, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 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, 0x13F0,
0x13F1, 0x13F2, 0x13F3, 0x13F4, 0x13F5, 0x0432, 0x0434, 0x043E,
0x0441, 0x0442, 0x0442, 0x044A, 0x0463, 0xA64B, 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, 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, 0x1E61,
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, 0x1F51, 0x1F53, 0x1F55, 0x1F57,
0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
0x1FB0, 0x1FB1, 0x1F70, 0x1F71, 0x03B9, 0x1F72, 0x1F73, 0x1F74,
0x1F75, 0x1FD0, 0x1FD1, 0x1F76, 0x1F77, 0x1FE0, 0x1FE1, 0x1F7A,
0x1F7B, 0x1FE5, 0x1F78, 0x1F79, 0x1F7C, 0x1F7D, 0x03C9, 0x006B,
0x00E5, 0x214E, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175,
0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D,
0x217E, 0x217F, 0x2184, 0x24D0, 0x24D1, 0x24D2, 0x24D3, 0x24D4,
0x24D5, 0x24D6, 0x24D7, 0x24D8, 0x24D9, 0x24DA, 0x24DB, 0x24DC,
0x24DD, 0x24DE, 0x24DF, 0x24E0, 0x24E1, 0x24E2, 0x24E3, 0x24E4,
0x24E5, 0x24E6, 0x24E7, 0x24E8, 0x24E9, 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, 0x026B, 0x1D7D,
0x027D, 0x2C68, 0x2C6A, 0x2C6C, 0x0251, 0x0271, 0x0250, 0x0252,
0x2C73, 0x2C76, 0x023F, 0x0240, 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, 0x2CEC, 0x2CEE,
0x2CF3, 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, 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, 0xA77A, 0xA77C, 0x1D79, 0xA77F,
0xA781, 0xA783, 0xA785, 0xA787, 0xA78C, 0x0265, 0xA791, 0xA793,
0xA797, 0xA799, 0xA79B, 0xA79D, 0xA79F, 0xA7A1, 0xA7A3, 0xA7A5,
0xA7A7, 0xA7A9, 0x0266, 0x025C, 0x0261, 0x026C, 0x026A, 0x029E,
0x0287, 0x029D, 0xAB53, 0xA7B5, 0xA7B7, 0xA7B9, 0xA7BB, 0xA7BD,
0xA7BF, 0xA7C1, 0xA7C3, 0xA794, 0x0282, 0x1D8E, 0xA7C8, 0xA7CA,
0xA7D1, 0xA7D7, 0xA7D9, 0xA7F6, 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, 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,
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,
};
}

View File

@@ -1,18 +0,0 @@
// Copyright (C) 2020 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_DEBUG_ASSERT_HPP
#define BOOST_PARSER_DETAIL_DEBUG_ASSERT_HPP
#if __has_include(<boost/assert.hpp>)
#include <boost/assert.hpp>
#define BOOST_PARSER_DEBUG_ASSERT(condition) BOOST_ASSERT(condition)
#define BOOST_PARSER_HAVE_BOOST_ASSERT
#else
#include <cassert>
#define BOOST_PARSER_DEBUG_ASSERT(condition) assert(condition)
#endif
#endif

View File

@@ -1,90 +0,0 @@
// Copyright (C) 2020 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_DETECTION_HPP
#define BOOST_PARSER_DETAIL_DETECTION_HPP
#include <type_traits>
namespace boost::parser::detail {
template<typename...>
struct void_
{
using type = void;
static constexpr bool value = true;
};
template<typename... T>
using void_t = typename void_<T...>::type;
template<typename T>
struct fixup_ptr
{
using type = T;
};
template<typename T>
using remove_v_t = typename std::remove_volatile<T>::type;
template<typename T>
struct fixup_ptr<T *>
{
using type = remove_v_t<T> const *;
};
template<typename T>
using fixup_ptr_t = typename fixup_ptr<T>::type;
template<typename T>
using remove_cv_ref_t =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
struct nonesuch
{};
template<
typename Default,
typename AlwaysVoid,
template<typename...> class Template,
typename... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
template<
typename Default,
template<typename...> class Template,
typename... Args>
struct detector<Default, void_t<Template<Args...>>, Template, Args...>
{
using value_t = std::true_type;
using type = Template<Args...>;
};
template<template<typename...> class Template, typename... Args>
using is_detected =
typename detector<nonesuch, void, Template, Args...>::value_t;
template<template<typename...> class Template, typename... Args>
constexpr bool is_detected_v = is_detected<Template, Args...>::value;
template<template<typename...> class Template, typename... Args>
using detected_t =
typename detector<nonesuch, void, Template, Args...>::type;
template<
typename Default,
template<typename...> class Template,
typename... Args>
using detected_or_t =
typename detector<Default, void, Template, Args...>::type;
}
#endif

View File

@@ -1,417 +0,0 @@
// Copyright (C) 2020 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_HL_HPP
#define BOOST_PARSER_DETAIL_HL_HPP
#include <boost/parser/config.hpp>
#include <boost/parser/tuple.hpp>
#include <boost/parser/detail/detection.hpp>
#include <type_traits>
#include <utility>
namespace boost { namespace parser { namespace detail::hl {
// Boost.Hana lite. These functions work with boost::hana::tuple and
// std::tuple.
struct forward
{
template<typename T>
decltype(auto) operator()(T && t)
{
return (T &&) t;
}
};
template<typename... Args>
constexpr auto make_tuple(Args &&... args)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::make_tuple((Args &&) args...);
#else
return hana::make_tuple((Args &&) args...);
#endif
}
template<typename T, typename U>
constexpr auto make_pair(T && t, U && u)
{
return hl::make_tuple((T &&) t, (U &&) u);
}
template<typename Tuple1, typename Tuple2>
constexpr auto concat(Tuple1 const & t1, Tuple2 const & t2)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::tuple_cat(t1, t2);
#else
// Hana's concat does not seem to do what it says on the tin.
// Concatenating (int, string) with (double, int) yields (int, string,
// double). I maybe don't understand it well enough.
return hana::insert_range(t1, hana::size(t1), t2);
#endif
}
// apply
template<typename F, typename Tuple, std::size_t... I>
constexpr auto
apply_impl(F && f, Tuple && t, std::integer_sequence<std::size_t, I...>)
-> decltype(((F &&) f)(parser::get((Tuple &&) t, llong<I>{})...))
{
return ((F &&) f)(parser::get((Tuple &&) t, llong<I>{})...);
}
template<
typename F,
typename Tuple,
typename Enable = std::enable_if_t<detail::is_tuple<
std::remove_cv_t<std::remove_reference_t<Tuple>>>{}>>
constexpr auto apply(F && f, Tuple && t) -> decltype(hl::apply_impl(
(F &&) f,
(Tuple &&) t,
std::make_integer_sequence<std::size_t, tuple_size_<Tuple>>{}))
{
return hl::apply_impl(
(F &&) f,
(Tuple &&) t,
std::make_integer_sequence<std::size_t, tuple_size_<Tuple>>{});
}
// for_each
template<typename F, typename Tuple, std::size_t... I>
constexpr void for_each_impl(
Tuple const & t, F && f, std::integer_sequence<std::size_t, I...>)
{
int _[] = {0, (f(parser::get(t, llong<I>{})), 0)...};
(void)_;
}
template<
typename F,
typename Tuple,
std::size_t... I,
typename Enable = std::enable_if_t<!std::is_reference_v<Tuple>>>
constexpr void
for_each_impl(Tuple && t, F && f, std::integer_sequence<std::size_t, I...>)
{
int _[] = {0, (f(std::move(parser::get(t, llong<I>{}))), 0)...};
(void)_;
}
template<typename F, typename... Args>
constexpr void for_each(tuple<Args...> && t, F && f)
{
hl::for_each_impl(
std::move(t),
(F &&) f,
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
template<typename F, typename... Args>
constexpr void for_each(tuple<Args...> const & t, F && f)
{
hl::for_each_impl(
t,
(F &&) f,
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
// transform
template<int offset, typename F, typename Tuple, std::size_t... I>
constexpr auto transform_impl(
Tuple const & t, F && f, std::integer_sequence<std::size_t, I...>)
{
return tuple<
std::decay_t<decltype(f(parser::get(t, llong<I + offset>{})))>...>{
f(parser::get(t, llong<I + offset>{}))...};
}
template<
int offset,
typename F,
typename Tuple,
std::size_t... I,
typename Enable = std::enable_if_t<!std::is_reference_v<Tuple>>>
auto constexpr transform_impl(
Tuple && t, F && f, std::integer_sequence<std::size_t, I...>)
{
return tuple<std::decay_t<decltype(
f(std::move(parser::get(t, llong<I + offset>{}))))>...>{
f(std::move(parser::get(t, llong<I + offset>{})))...};
}
template<typename F, typename... Args>
constexpr auto transform(tuple<Args...> && t, F && f)
{
return hl::transform_impl<0>(
std::move(t),
(F &&) f,
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
template<typename F, typename... Args>
constexpr auto transform(tuple<Args...> const & t, F && f)
{
return hl::transform_impl<0>(
t,
(F &&) f,
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
// fold_left
template<std::size_t I, std::size_t N>
struct fold_left_dispatch
{
template<typename F, typename State, typename... Args>
constexpr static auto
call(tuple<Args...> const & t, State && s, F const & f)
{
return fold_left_dispatch<I + 1, N>::call(
t, f((State &&) s, parser::get(t, llong<I>{})), f);
}
};
template<std::size_t I>
struct fold_left_dispatch<I, I>
{
template<typename F, typename State, typename... Args>
constexpr static auto
call(tuple<Args...> const & t, State && s, F const & f)
{
return (State &&) s;
}
};
template<typename F, typename State, typename... Args>
constexpr auto fold_left(tuple<Args...> const & t, State && s, F const & f)
{
return hl::fold_left_dispatch<0, sizeof...(Args)>::call(
t, (State &&) s, (F &&) f);
}
// size
template<typename... Args>
constexpr auto size(tuple<Args...> const & t)
{
return llong<sizeof...(Args)>{};
}
template<typename... Args>
constexpr auto size_minus_one(tuple<Args...> const & t)
{
return llong<sizeof...(Args) - 1>{};
}
// contains
template<typename T, typename U>
using comparable = decltype(std::declval<T>() == std::declval<U>());
struct typesafe_equals
{
template<typename T, typename U>
constexpr bool operator()(T const & t, U const & u)
{
if constexpr (detail::is_detected_v<comparable, T, U>) {
return t == u;
} else {
return false;
}
}
};
template<typename T, typename Tuple, std::size_t... I>
constexpr bool contains_impl(
Tuple const & t, T const & x, std::integer_sequence<std::size_t, I...>)
{
typesafe_equals eq;
(void)eq;
return (eq(parser::get(t, llong<I>{}), x) || ...);
}
template<typename T, typename... Args>
constexpr bool contains(tuple<Args...> & t, T const & x)
{
return contains_impl(
t, x, std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
// front, back
template<typename Arg, typename... Args>
constexpr decltype(auto) front(tuple<Arg, Args...> & t)
{
return parser::get(t, llong<0>{});
}
template<typename Arg, typename... Args>
constexpr decltype(auto) front(tuple<Arg, Args...> const & t)
{
return parser::get(t, llong<0>{});
}
template<typename Arg, typename... Args>
constexpr decltype(auto) back(tuple<Arg, Args...> & t)
{
return parser::get(t, llong<sizeof...(Args)>{});
}
template<typename Arg, typename... Args>
constexpr decltype(auto) back(tuple<Arg, Args...> const & t)
{
return parser::get(t, llong<sizeof...(Args)>{});
}
// drop_front
template<typename Arg, typename... Args>
constexpr auto drop_front(tuple<Arg, Args...> && t)
{
return hl::transform_impl<1>(
std::move(t),
forward{},
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
template<typename Arg, typename... Args>
constexpr auto drop_front(tuple<Arg, Args...> const & t)
{
return hl::transform_impl<1>(
t,
forward{},
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
// drop_back
template<typename Arg, typename... Args>
constexpr auto drop_back(tuple<Arg, Args...> && t)
{
return hl::transform_impl<0>(
std::move(t),
forward{},
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
template<typename Arg, typename... Args>
constexpr auto drop_back(tuple<Arg, Args...> const & t)
{
return hl::transform_impl<0>(
t,
forward{},
std::make_integer_sequence<std::size_t, sizeof...(Args)>());
}
// first, second
template<typename T, typename U>
constexpr decltype(auto) first(tuple<T, U> & t)
{
return parser::get(t, llong<0>{});
}
template<typename T, typename U>
constexpr decltype(auto) first(tuple<T, U> const & t)
{
return parser::get(t, llong<0>{});
}
template<typename T, typename U>
constexpr decltype(auto) second(tuple<T, U> & t)
{
return parser::get(t, llong<1>{});
}
template<typename T, typename U>
constexpr decltype(auto) second(tuple<T, U> const & t)
{
return parser::get(t, llong<1>{});
}
// zip
template<std::size_t I, typename... Tuples>
constexpr decltype(auto) make_zip_elem(Tuples const &... ts)
{
return hl::make_tuple(parser::get(ts, llong<I>{})...);
}
template<std::size_t... I, typename... Tuples>
constexpr auto zip_impl(std::index_sequence<I...>, Tuples const &... ts)
{
return hl::make_tuple(hl::make_zip_elem<I>(ts...)...);
}
template<typename T>
struct tuplesize;
template<typename... Args>
struct tuplesize<tuple<Args...>>
{
constexpr static std::size_t value = sizeof...(Args);
};
template<typename Tuple, typename... Tuples>
constexpr auto zip(Tuple const & t, Tuples const &... ts)
{
return hl::zip_impl(
std::make_integer_sequence<
std::size_t,
tuplesize<std::remove_reference_t<Tuple>>::value>(),
t,
ts...);
}
// append
template<typename... Args, typename T>
constexpr auto append(tuple<Args...> && t, T && x)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::tuple_cat(std::move(t), std::make_tuple((T &&) x));
#else
return hana::append(std::move(t), (T &&) x);
#endif
}
template<typename... Args, typename T>
constexpr auto append(tuple<Args...> const & t, T && x)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::tuple_cat(t, std::make_tuple((T &&) x));
#else
return hana::append(t, (T &&) x);
#endif
}
// prepend
template<typename... Args, typename T>
constexpr auto prepend(tuple<Args...> && t, T && x)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::tuple_cat(std::make_tuple((T &&) x), std::move(t));
#else
return hana::prepend(std::move(t), (T &&) x);
#endif
}
template<typename... Args, typename T>
constexpr auto prepend(tuple<Args...> const & t, T && x)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::tuple_cat(std::make_tuple((T &&) x), t);
#else
return hana::prepend(t, (T &&) x);
#endif
}
}}}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,123 +0,0 @@
#ifndef BOOST_PARSER_DETAIL_PP_FOR_EACH_HPP_INCLUDED
#define BOOST_PARSER_DETAIL_PP_FOR_EACH_HPP_INCLUDED
// Copyright 2020 Peter Dimov
// Copyright 2023 T. Zachary Laine
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/parser/detail/pp_utilities.hpp>
#define BOOST_PARSER_PP_FOR_EACH_0(F, a)
#define BOOST_PARSER_PP_FOR_EACH_1(F, a, x) BOOST_PARSER_PP_CALL(F, a, x)
#define BOOST_PARSER_PP_FOR_EACH_2(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_1(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_3(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_2(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_4(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_3(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_5(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_4(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_6(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_5(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_7(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_6(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_8(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_7(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_9(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_8(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_10(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_9(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_11(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_10(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_12(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_11(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_13(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_12(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_14(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_13(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_15(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_14(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_16(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_15(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_17(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_16(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_18(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_17(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_19(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_18(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_20(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_19(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_21(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_20(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_22(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_21(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_23(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_22(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_24(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_23(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_25(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_24(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_26(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_25(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_27(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_26(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_28(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_27(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_29(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_28(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_30(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_29(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_31(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_30(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_32(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_31(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_33(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_32(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_34(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_33(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_35(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_34(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_36(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_35(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_37(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_36(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_38(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_37(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_39(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_38(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_40(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_39(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_41(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_40(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_42(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_41(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_43(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_42(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_44(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_43(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_45(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_44(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_46(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_45(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_47(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_46(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_48(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_47(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_49(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_48(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_50(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_49(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_51(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_50(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FOR_EACH_52(F, a, x, ...) BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_FOR_EACH_51(F, a, __VA_ARGS__))
#define BOOST_PARSER_PP_FE_EXTRACT(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, V, ...) V
#define BOOST_PARSER_PP_FOR_EACH(F, ...) \
BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_EXPAND(BOOST_PARSER_PP_FE_EXTRACT(__VA_ARGS__, \
BOOST_PARSER_PP_FOR_EACH_52, \
BOOST_PARSER_PP_FOR_EACH_51, \
BOOST_PARSER_PP_FOR_EACH_50, \
BOOST_PARSER_PP_FOR_EACH_49, \
BOOST_PARSER_PP_FOR_EACH_48, \
BOOST_PARSER_PP_FOR_EACH_47, \
BOOST_PARSER_PP_FOR_EACH_46, \
BOOST_PARSER_PP_FOR_EACH_45, \
BOOST_PARSER_PP_FOR_EACH_44, \
BOOST_PARSER_PP_FOR_EACH_43, \
BOOST_PARSER_PP_FOR_EACH_42, \
BOOST_PARSER_PP_FOR_EACH_41, \
BOOST_PARSER_PP_FOR_EACH_40, \
BOOST_PARSER_PP_FOR_EACH_39, \
BOOST_PARSER_PP_FOR_EACH_38, \
BOOST_PARSER_PP_FOR_EACH_37, \
BOOST_PARSER_PP_FOR_EACH_36, \
BOOST_PARSER_PP_FOR_EACH_35, \
BOOST_PARSER_PP_FOR_EACH_34, \
BOOST_PARSER_PP_FOR_EACH_33, \
BOOST_PARSER_PP_FOR_EACH_32, \
BOOST_PARSER_PP_FOR_EACH_31, \
BOOST_PARSER_PP_FOR_EACH_30, \
BOOST_PARSER_PP_FOR_EACH_29, \
BOOST_PARSER_PP_FOR_EACH_28, \
BOOST_PARSER_PP_FOR_EACH_27, \
BOOST_PARSER_PP_FOR_EACH_26, \
BOOST_PARSER_PP_FOR_EACH_25, \
BOOST_PARSER_PP_FOR_EACH_24, \
BOOST_PARSER_PP_FOR_EACH_23, \
BOOST_PARSER_PP_FOR_EACH_22, \
BOOST_PARSER_PP_FOR_EACH_21, \
BOOST_PARSER_PP_FOR_EACH_20, \
BOOST_PARSER_PP_FOR_EACH_19, \
BOOST_PARSER_PP_FOR_EACH_18, \
BOOST_PARSER_PP_FOR_EACH_17, \
BOOST_PARSER_PP_FOR_EACH_16, \
BOOST_PARSER_PP_FOR_EACH_15, \
BOOST_PARSER_PP_FOR_EACH_14, \
BOOST_PARSER_PP_FOR_EACH_13, \
BOOST_PARSER_PP_FOR_EACH_12, \
BOOST_PARSER_PP_FOR_EACH_11, \
BOOST_PARSER_PP_FOR_EACH_10, \
BOOST_PARSER_PP_FOR_EACH_9, \
BOOST_PARSER_PP_FOR_EACH_8, \
BOOST_PARSER_PP_FOR_EACH_7, \
BOOST_PARSER_PP_FOR_EACH_6, \
BOOST_PARSER_PP_FOR_EACH_5, \
BOOST_PARSER_PP_FOR_EACH_4, \
BOOST_PARSER_PP_FOR_EACH_3, \
BOOST_PARSER_PP_FOR_EACH_2, \
BOOST_PARSER_PP_FOR_EACH_1, \
BOOST_PARSER_PP_FOR_EACH_0))(F, __VA_ARGS__))
#endif // #ifndef BOOST_PARSER_DETAIL_PP_FOR_EACH_HPP_INCLUDED

View File

@@ -1,93 +0,0 @@
#ifndef BOOST_PARSER_DETAIL_PP_UTILITIES_HPP_INCLUDED
#define BOOST_PARSER_DETAIL_PP_UTILITIES_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Copyright 2023 T. Zachary Laine
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define BOOST_PARSER_PP_EXPAND(x) x
#define BOOST_PARSER_PP_CAT(x, y) BOOST_PARSER_PP_CAT_I(x, y)
#define BOOST_PARSER_PP_CAT_I(x, ...) x ## __VA_ARGS__
#if defined(_MSC_VER) && !defined(__clang__)
#define BOOST_PARSER_PP_FIRST(x) BOOST_PARSER_PP_FIRST_I((x))
#define BOOST_PARSER_PP_FIRST_I(x) BOOST_PARSER_PP_FIRST_II x
#define BOOST_PARSER_PP_FIRST_II(x, ...) x
#else
#define BOOST_PARSER_PP_FIRST(x) BOOST_PARSER_PP_FIRST_I(x)
#define BOOST_PARSER_PP_FIRST_I(x, ...) x
#endif
#define BOOST_PARSER_PP_IS_PAREN_I(x) BOOST_PARSER_PP_CAT(BOOST_PARSER_PP_IS_PAREN_I_, BOOST_PARSER_PP_IS_PAREN_II x)
#define BOOST_PARSER_PP_IS_PAREN_II(...) 0
#define BOOST_PARSER_PP_IS_PAREN_I_0 1,
#define BOOST_PARSER_PP_IS_PAREN_I_BOOST_PARSER_PP_IS_PAREN_II 0,
#define BOOST_PARSER_PP_IS_PAREN(x) BOOST_PARSER_PP_FIRST(BOOST_PARSER_PP_IS_PAREN_I(x))
#define BOOST_PARSER_PP_EMPTY
#define BOOST_PARSER_PP_IS_EMPTY(x) BOOST_PARSER_PP_IS_EMPTY_I(BOOST_PARSER_PP_IS_PAREN(x), BOOST_PARSER_PP_IS_PAREN(x BOOST_PARSER_PP_EMPTY ()))
#define BOOST_PARSER_PP_IS_EMPTY_I(x, y) BOOST_PARSER_PP_IS_EMPTY_II(x, y)
#define BOOST_PARSER_PP_IS_EMPTY_II(x, y) BOOST_PARSER_PP_IS_EMPTY_III(x, y)
#define BOOST_PARSER_PP_IS_EMPTY_III(x, y) BOOST_PARSER_PP_IS_EMPTY_III_ ## x ## y
#define BOOST_PARSER_PP_IS_EMPTY_III_00 0
#define BOOST_PARSER_PP_IS_EMPTY_III_01 1
#define BOOST_PARSER_PP_IS_EMPTY_III_10 0
#define BOOST_PARSER_PP_IS_EMPTY_III_11 0
#define BOOST_PARSER_PP_CALL(F, a, x) BOOST_PARSER_PP_CAT(BOOST_PARSER_PP_CALL_I_, BOOST_PARSER_PP_IS_EMPTY(x))(F, a, x)
#define BOOST_PARSER_PP_CALL_I_0(F, a, x) F(a, x)
#define BOOST_PARSER_PP_CALL_I_1(F, a, x)
#define BOOST_PARSER_PP_PARSE(x) BOOST_PARSER_PP_CAT(BOOST_PARSER_PP_PARSE_I_, BOOST_PARSER_PP_PARSE_II x)
#define BOOST_PARSER_PP_PARSE_II(...) 0, (__VA_ARGS__),
#define BOOST_PARSER_PP_PARSE_I_BOOST_PARSER_PP_PARSE_II 0, ~,
#define BOOST_PARSER_PP_PARSE_I_0 1
#if defined(_MSC_VER) && !defined(__clang__)
#define BOOST_PARSER_PP_NAME(x) BOOST_PARSER_PP_NAME_I(BOOST_PARSER_PP_PARSE(x))
#define BOOST_PARSER_PP_NAME_I(x) BOOST_PARSER_PP_NAME_II((x))
#define BOOST_PARSER_PP_NAME_II(x) BOOST_PARSER_PP_NAME_III x
#define BOOST_PARSER_PP_NAME_III(x, y, z) #z
#else
#define BOOST_PARSER_PP_NAME(x) BOOST_PARSER_PP_NAME_I(BOOST_PARSER_PP_PARSE(x))
#define BOOST_PARSER_PP_NAME_I(x) BOOST_PARSER_PP_NAME_II(x)
#define BOOST_PARSER_PP_NAME_II(x, y, z) #z
#endif
// template<class C, class F> constexpr auto mfn( F C::* p ) { return p; }
// template<class C, class F> constexpr auto mfn( F * p ) { return p; }
#define BOOST_PARSER_PP_POINTER(C, x) BOOST_PARSER_PP_POINTER_I(C, BOOST_PARSER_PP_PARSE(x))
#define BOOST_PARSER_PP_EXPAND_V(...) __VA_ARGS__
#if defined(_MSC_VER) && !defined(__clang__)
#define BOOST_PARSER_PP_POINTER_I(C, x) BOOST_PARSER_PP_POINTER_II((C, x))
#define BOOST_PARSER_PP_POINTER_II(x) BOOST_PARSER_PP_POINTER_III x
#define BOOST_PARSER_PP_POINTER_III(C, x, y, z) BOOST_PARSER_PP_POINTER_III_##x(C, y, z)
#define BOOST_PARSER_PP_POINTER_III_0(C, y, z) &C::z
#define BOOST_PARSER_PP_POINTER_III_1(C, y, z) ::boost::describe::detail::mfn<C, BOOST_PARSER_PP_EXPAND_V y>(&C::z)
#else
#define BOOST_PARSER_PP_POINTER_I(C, x) BOOST_PARSER_PP_POINTER_II(C, x)
#define BOOST_PARSER_PP_POINTER_II(C, x, y, z) BOOST_PARSER_PP_POINTER_III_##x(C, y, z)
#define BOOST_PARSER_PP_POINTER_III_0(C, y, z) &C::z
#define BOOST_PARSER_PP_POINTER_III_1(C, y, z) ::boost::describe::detail::mfn<C, BOOST_PARSER_PP_EXPAND_V y>(&C::z)
#endif
#endif // #ifndef BOOST_PARSER_DETAIL_PP_UTILITIES_HPP_INCLUDED

View File

@@ -1,677 +0,0 @@
#ifndef BOOST_PARSER_DETAIL_PRINTING_HPP
#define BOOST_PARSER_DETAIL_PRINTING_HPP
#include <boost/parser/parser_fwd.hpp>
#include <boost/parser/tuple.hpp>
#include <boost/parser/detail/detection.hpp>
#include <boost/parser/detail/hl.hpp>
#include <boost/parser/detail/text/unpack.hpp>
#include <boost/parser/detail/text/transcode_view.hpp>
#include <iomanip>
#include <iostream>
#include <optional>
#include <sstream>
#include <string>
#include <variant>
#include <cctype>
namespace boost { namespace parser { namespace detail {
template<typename Context>
decltype(auto) _indent(Context const & context);
template<typename Char>
std::ostream & print_char(std::ostream & os, Char c)
{
if constexpr (
#if defined(__cpp_char8_t)
std::is_same_v<
char8_t,
std::remove_cv_t<std::remove_reference_t<Char>>>
#else
false
#endif
) {
os << char(c);
} else {
os << c;
}
return os;
}
enum { parser_component_limit = 4 };
template<
typename Context,
typename Parser,
typename DelimiterParser,
typename MinType,
typename MaxType>
void print_parser(
Context const & context,
repeat_parser<Parser, DelimiterParser, MinType, MaxType> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser>
void print_parser(
Context const & context,
opt_parser<Parser> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
or_parser<ParserTuple> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
perm_parser<ParserTuple> const & parser,
std::ostream & os,
int components = 0);
template<
typename Context,
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups>
void print_parser(
Context const & context,
seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups> const &
parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser, typename Action>
void print_parser(
Context const & context,
action_parser<Parser, Action> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser, typename F>
void print_parser(
Context const & context,
transform_parser<Parser, F> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser>
void print_parser(
Context const & context,
omit_parser<Parser> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser>
void print_parser(
Context const & context,
raw_parser<Parser> const & parser,
std::ostream & os,
int components = 0);
#if defined(BOOST_PARSER_DOXYGEN) || defined(__cpp_lib_concepts)
template<typename Context, typename Parser>
void print_parser(
Context const & context,
string_view_parser<Parser> const & parser,
std::ostream & os,
int components = 0);
#endif
template<typename Context, typename Parser>
void print_parser(
Context const & context,
lexeme_parser<Parser> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser>
void print_parser(
Context const & context,
no_case_parser<Parser> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser, typename SkipParser>
void print_parser(
Context const & context,
skip_parser<Parser, SkipParser> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Parser, typename ParserConfig>
void print_parser(
Context const & context,
expect_parser_t<Parser, ParserConfig> const & parser,
std::ostream & os,
int components = 0);
template<
typename Context,
bool UseCallbacks,
typename Parser,
typename Attribute,
typename LocalState,
typename ParamsTuple>
void print_parser(
Context const & context,
rule_parser<
UseCallbacks,
Parser,
Attribute,
LocalState,
ParamsTuple> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename T>
void print_parser(
Context const & context,
symbol_parser<T> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Predicate>
void print_parser(
Context const & context,
eps_parser<Predicate> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
eps_parser<nope> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
eoi_parser const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Atribute>
void print_parser(
Context const & context,
attr_parser<Atribute> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename Expected, typename AttributeType>
void print_parser(
Context const & context,
char_parser<Expected, AttributeType> const & parser,
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,
omit_parser<char_parser<Expected, AttributeType>> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename StrIter, typename StrSentinel>
void print_parser(
Context const & context,
string_parser<StrIter, StrSentinel> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename StrIter, typename StrSentinel>
void print_parser(
Context const & context,
omit_parser<string_parser<StrIter, StrSentinel>> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
Context const & context,
ws_parser<NewlinesOnly, NoNewlines> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
bool_parser const & parser,
std::ostream & os,
int components = 0);
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
Context const & context,
uint_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
std::ostream & os,
int components = 0);
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
Context const & context,
int_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename T>
void print_parser(
Context const & context,
float_parser<T> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
float_parser<float> const & parser,
std::ostream & os,
int components = 0);
template<typename Context>
void print_parser(
Context const & context,
float_parser<double> const & parser,
std::ostream & os,
int components = 0);
template<typename Context, typename SwitchValue, typename OrParser>
void print_parser(
Context const & context,
switch_parser<SwitchValue, OrParser> const & parser,
std::ostream & os,
int components = 0);
enum { trace_indent_factor = 2 };
inline void trace_indent(int indent)
{
for (int i = 0, end = trace_indent_factor * indent; i != end; ++i) {
std::cout << ' ';
}
}
template<typename Iter, typename Sentinel, int SizeofValueType>
struct trace_input_impl
{
static void call(
std::ostream & os,
Iter first_,
Sentinel last_,
bool quote,
int64_t trace_input_cps)
{
auto utf8 = BOOST_PARSER_DETAIL_TEXT_SUBRANGE(first_, last_) | text::as_utf8;
auto first = utf8.begin();
auto last = utf8.end();
if (quote)
os << '"';
for (int64_t i = 0; i < trace_input_cps && first != last;
++i, ++first) {
detail::print_char(os, *first);
}
if (quote)
os << '"';
}
};
template<typename Iter, typename Sentinel>
struct trace_input_impl<Iter, Sentinel, 1>
{
static void call(
std::ostream & os,
Iter first_,
Sentinel last_,
bool quote,
int64_t trace_input_cps)
{
auto r = BOOST_PARSER_DETAIL_TEXT_SUBRANGE(first_, last_);
auto r_unpacked =
detail::text::unpack_iterator_and_sentinel(first_, last_);
auto utf32 = r | text::as_utf32;
auto first = utf32.begin();
auto const last = utf32.end();
for (int64_t i = 0; i < trace_input_cps && first != last; ++i) {
++first;
}
if (quote)
os << '"';
auto first_repacked = r_unpacked.repack(first.base());
for (Iter it = first_, end = first_repacked; it != end; ++it) {
detail::print_char(os, *it);
}
if (quote)
os << '"';
}
};
template<typename Iter, typename Sentinel>
inline void trace_input(
std::ostream & os,
Iter first,
Sentinel last,
bool quote = true,
int64_t trace_input_cps = 8)
{
trace_input_impl<Iter, Sentinel, sizeof(*first)>::call(
os, first, last, quote, trace_input_cps);
}
template<typename Iter, typename Sentinel>
inline void trace_begin_match(
Iter first, Sentinel last, int indent, std::string_view name)
{
detail::trace_indent(indent);
std::cout << "[begin " << name << "; input=";
detail::trace_input(std::cout, first, last);
std::cout << "]" << std::endl;
}
template<typename Iter, typename Sentinel>
inline void trace_end_match(
Iter first, Sentinel last, int indent, std::string_view name)
{
detail::trace_indent(indent);
std::cout << "[end " << name << "; input=";
detail::trace_input(std::cout, first, last);
std::cout << "]" << std::endl;
}
template<typename Iter, typename Sentinel, typename Context>
void trace_prefix(
Iter first,
Sentinel last,
Context const & context,
std::string_view name)
{
int & indent = detail::_indent(context);
detail::trace_begin_match(first, last, indent, name);
++indent;
}
template<typename Iter, typename Sentinel, typename Context>
void trace_suffix(
Iter first,
Sentinel last,
Context const & context,
std::string_view name)
{
int & indent = detail::_indent(context);
--indent;
detail::trace_end_match(first, last, indent, name);
}
template<typename T>
using streamable =
decltype(std::declval<std::ostream &>() << std::declval<T const &>());
template<typename T, bool Streamable = is_detected_v<streamable, T>>
struct printer
{
std::ostream & operator()(std::ostream & os, T const &)
{
return os << "<<unprintable-value>>";
}
};
template<typename T>
void print_printable(std::ostream & os, T const & x)
{
os << x;
}
inline void print_printable(std::ostream & os, char c)
{
if (std::isprint(c)) {
os << "'" << c << "'";
} else {
os << "'\\x" << std::hex << std::setw(2) << std::setfill('0')
<< (uint32_t)c << "'";
}
}
inline void print_printable(std::ostream & os, char32_t c)
{
if (c < 256) {
os << "U";
detail::print_printable(os, (char)c);
} else {
os << "U'\\U" << std::hex << std::setw(8) << std::setfill('0')
<< (uint32_t)c << "'";
}
}
template<typename T>
struct printer<T, true>
{
std::ostream & operator()(std::ostream & os, T const & x)
{
detail::print_printable(os, x);
return os;
}
};
template<typename T>
constexpr bool is_variant_v = enable_variant<T>;
template<typename Attribute>
inline void print(std::ostream & os, Attribute const & attr)
{
using just_attribute =
std::remove_cv_t<std::remove_reference_t<Attribute>>;
if constexpr (is_tuple<just_attribute>{}) {
os << "(";
bool first = false;
hl::for_each(attr, [&](auto const & a) {
if (first)
os << ", ";
detail::print(os, a);
first = false;
});
os << ")\n";
} else if constexpr (is_optional_v<just_attribute>) {
if (!attr)
os << "<<empty>>";
else
detail::print(os, *attr);
} else if constexpr (is_variant_v<just_attribute>) {
os << "<<variant>>";
} else {
printer<just_attribute>{}(os, attr);
}
}
template<typename Attribute>
inline void print_attribute(Attribute const & attr, int indent)
{
detail::trace_indent(indent);
std::cout << "attribute: ";
detail::print(std::cout, attr);
std::cout << "\n";
}
inline void print_attribute(nope const &, int) {}
constexpr inline bool do_trace(flags f)
{
return (uint32_t(f) & uint32_t(flags::trace)) == uint32_t(flags::trace);
}
template<typename Context, typename T>
auto resolve(Context const & context, T const & x);
template<typename Context>
auto resolve(Context const &, nope n);
template<
bool DoTrace,
typename Iter,
typename Sentinel,
typename Context,
typename Attribute>
struct scoped_trace_t
{
scoped_trace_t(
Iter & first,
Sentinel last,
Context const & context,
flags f,
Attribute const & attr,
std::string name) :
initial_first_(first),
first_(first),
last_(last),
context_(context),
flags_(f),
attr_(attr),
name_(std::move(name))
{
if (!detail::do_trace(flags_))
return;
detail::trace_prefix(first_, last_, context_, name_);
}
~scoped_trace_t()
{
if (!detail::do_trace(flags_))
return;
detail::trace_indent(detail::_indent(context_));
if (*context_.pass_) {
std::cout << "matched ";
detail::trace_input(std::cout, initial_first_, first_);
std::cout << "\n";
detail::print_attribute(
detail::resolve(context_, attr_),
detail::_indent(context_));
} else {
std::cout << "no match\n";
}
detail::trace_suffix(first_, last_, context_, name_);
}
Iter initial_first_;
Iter & first_;
Sentinel last_;
Context const & context_;
flags flags_;
Attribute const & attr_;
std::string name_;
};
template<
typename Iter,
typename Sentinel,
typename Context,
typename Attribute>
struct scoped_trace_t<false, Iter, Sentinel, Context, Attribute>
{
scoped_trace_t() {}
};
template<
typename Parser,
typename Iter,
typename Sentinel,
typename Context,
typename Attribute>
auto scoped_trace(
Parser const & parser,
Iter & first,
Sentinel last,
Context const & context,
flags f,
Attribute const & attr)
{
if constexpr (Context::do_trace) {
std::stringstream oss;
detail::print_parser(context, parser, oss);
return scoped_trace_t<true, Iter, Sentinel, Context, Attribute>(
first, last, context, f, attr, oss.str());
} else {
return scoped_trace_t<false, Iter, Sentinel, Context, Attribute>{};
}
}
template<typename Context, typename Attribute>
auto final_trace(Context const & context, flags f, Attribute const & attr)
{
if (!detail::do_trace(f))
return;
std::cout << "--------------------\n";
if (*context.pass_) {
std::cout << "parse succeeded\n";
detail::print_attribute(detail::resolve(context, attr), 0);
} else {
std::cout << "parse failed\n";
}
std::cout << "--------------------" << std::endl;
}
}}}
#endif

View File

@@ -1,920 +0,0 @@
#ifndef BOOST_PARSER_DETAIL_PRINTING_IMPL_HPP
#define BOOST_PARSER_DETAIL_PRINTING_IMPL_HPP
#include <boost/parser/detail/printing.hpp>
#if __has_include(<boost/type_index.hpp>)
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <boost/type_index.hpp>
#define BOOST_PARSER_HAVE_BOOST_TYPEINDEX 1
#define BOOST_PARSER_TYPE_NAME_NS boost_type_index
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#else
#include <typeinfo>
#define BOOST_PARSER_HAVE_BOOST_TYPEINDEX 0
#define BOOST_PARSER_TYPE_NAME_NS std_typeinfo
#endif
namespace boost { namespace parser { namespace detail {
inline namespace BOOST_PARSER_TYPE_NAME_NS {
template<typename T>
auto type_name()
{
#if BOOST_PARSER_HAVE_BOOST_TYPEINDEX
return typeindex::type_id<T>().pretty_name();
#else
return typeid(T).name();
#endif
}
}
template<typename Parser>
struct n_aray_parser : std::false_type
{};
template<
typename Parser,
typename DelimiterParser,
typename MinType,
typename MaxType>
struct n_aray_parser<
repeat_parser<Parser, DelimiterParser, MinType, MaxType>>
: std::true_type
{};
template<typename Parser, typename MinType, typename MaxType>
struct n_aray_parser<repeat_parser<Parser, detail::nope, MinType, MaxType>>
: std::false_type
{};
template<typename Parser, typename DelimiterParser>
struct n_aray_parser<delimited_seq_parser<Parser, DelimiterParser>>
: std::true_type
{};
template<typename ParserTuple>
struct n_aray_parser<or_parser<ParserTuple>> : std::true_type
{};
template<typename ParserTuple>
struct n_aray_parser<perm_parser<ParserTuple>> : std::true_type
{};
template<
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups>
struct n_aray_parser<
seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>>
: std::true_type
{};
// true iff Parser is an n-ary parser (contains N>2 subparsers).
template<typename Parser>
constexpr bool n_aray_parser_v = n_aray_parser<Parser>::value;
template<typename Context, typename Expected>
void print_expected(
Context const & context,
std::ostream & os,
Expected expected,
bool no_parens = false)
{
if (is_nope_v<Expected>)
return;
if (!no_parens)
os << "(";
detail::print(os, detail::resolve(context, expected));
if (!no_parens)
os << ")";
}
template<
typename Context,
typename Parser,
typename DelimiterParser,
typename MinType,
typename MaxType>
void print_parser(
Context const & context,
repeat_parser<Parser, DelimiterParser, MinType, MaxType> const & parser,
std::ostream & os,
int components)
{
if constexpr (is_nope_v<DelimiterParser>) {
auto const min_ = detail::resolve(context, parser.min_);
auto const max_ = detail::resolve(context, parser.max_);
constexpr bool n_ary_child = n_aray_parser_v<Parser>;
if (min_ == 0 && max_ == Inf) {
os << "*";
if (n_ary_child)
os << "(";
detail::print_parser(
context, parser.parser_, os, components + 1);
if (n_ary_child)
os << ")";
} else if (min_ == 1 && max_ == Inf) {
os << "+";
if (n_ary_child)
os << "(";
detail::print_parser(
context, parser.parser_, os, components + 1);
if (n_ary_child)
os << ")";
} else {
os << "repeat(";
detail::print(os, min_);
if (min_ == max_) {
os << ")[";
} else {
os << ", ";
if (max_ == unbounded)
os << "Inf";
else
detail::print(os, max_);
os << ")[";
}
detail::print_parser(
context, parser.parser_, os, components + 1);
os << "]";
}
} else {
detail::print_parser(context, parser.parser_, os, components + 1);
os << " % ";
detail::print_parser(
context, parser.delimiter_parser_, os, components + 2);
}
}
template<typename Context, typename Parser>
void print_parser(
Context const & context,
opt_parser<Parser> const & parser,
std::ostream & os,
int components)
{
os << "-";
constexpr bool n_ary_child = n_aray_parser_v<Parser>;
if (n_ary_child)
os << "(";
detail::print_parser(context, parser.parser_, os, components + 1);
if (n_ary_child)
os << ")";
}
template<typename Context, typename Parser>
void print_or_like_parser(
Context const & context,
Parser const & parser,
std::ostream & os,
int components,
std::string_view or_ellipsis,
std::string_view ws_or)
{
int i = 0;
bool printed_ellipsis = false;
hl::for_each(parser.parsers_, [&](auto const & parser) {
if (components == parser_component_limit) {
if (!printed_ellipsis)
os << or_ellipsis;
printed_ellipsis = true;
return;
}
if (i)
os << ws_or;
detail::print_parser(context, parser, os, components);
++components;
++i;
});
}
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
or_parser<ParserTuple> const & parser,
std::ostream & os,
int components)
{
detail::print_or_like_parser(
context, parser, os, components, " | ...", " | ");
}
template<typename Context, typename ParserTuple>
void print_parser(
Context const & context,
perm_parser<ParserTuple> const & parser,
std::ostream & os,
int components)
{
detail::print_or_like_parser(
context, parser, os, components, " || ...", " || ");
}
template<
typename Context,
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups>
void print_parser(
Context const & context,
seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups> const &
parser,
std::ostream & os,
int components)
{
int prev_group = 0;
int i = 0;
bool printed_ellipsis = false;
using combining_groups =
detail::combining_t<ParserTuple, CombiningGroups>;
hl::for_each(
hl::zip(parser.parsers_, BacktrackingTuple{}, combining_groups{}),
[&](auto const & parser_and_backtrack) {
using namespace literals;
auto const & parser = parser::get(parser_and_backtrack, 0_c);
auto const backtrack = parser::get(parser_and_backtrack, 1_c);
auto const group = parser::get(parser_and_backtrack, 2_c);
if (components == parser_component_limit) {
if (!printed_ellipsis) {
os << (backtrack ? " >> ..." : " > ...");
}
printed_ellipsis = true;
return;
}
if (group != prev_group && prev_group)
os << ']';
if (i)
os << (backtrack ? " >> " : " > ");
if (group != prev_group && group)
os << (group == -1 ? "separate[" : "merge[");
detail::print_parser(context, parser, os, components);
++components;
++i;
prev_group = (int)group;
});
if (prev_group && !printed_ellipsis)
os << ']';
}
template<typename Context, typename Parser, typename Action>
void print_parser(
Context const & context,
action_parser<Parser, Action> const & parser,
std::ostream & os,
int components)
{
detail::print_parser(context, parser.parser_, os, components);
os << "[<<action>>]";
}
template<typename Context, typename Parser>
void print_directive(
Context const & context,
std::string_view name,
Parser const & parser,
std::ostream & os,
int components)
{
os << name << "[";
if (++components == parser_component_limit)
os << "...";
else
detail::print_parser(context, parser, os, components + 1);
os << "]";
}
template<typename Context, typename Parser, typename F>
void print_parser(
Context const & context,
transform_parser<Parser, F> const & parser,
std::ostream & os,
int components)
{
detail::print_directive(
context, "transform(<<f>>)", parser.parser_, os, components);
}
template<typename Context, typename Parser>
void print_parser(
Context const & context,
omit_parser<Parser> const & parser,
std::ostream & os,
int components)
{
detail::print_directive(
context, "omit", parser.parser_, os, components);
}
template<typename Context, typename Parser>
void print_parser(
Context const & context,
raw_parser<Parser> const & parser,
std::ostream & os,
int components)
{
detail::print_directive(context, "raw", parser.parser_, os, components);
}
#if defined(BOOST_PARSER_DOXYGEN) || defined(__cpp_lib_concepts)
template<typename Context, typename Parser>
void print_parser(
Context const & context,
string_view_parser<Parser> const & parser,
std::ostream & os,
int components)
{
detail::print_directive(
context, "string_view", parser.parser_, os, components);
}
#endif
template<typename Context, typename Parser>
void print_parser(
Context const & context,
lexeme_parser<Parser> const & parser,
std::ostream & os,
int components)
{
detail::print_directive(
context, "lexeme", parser.parser_, os, components);
}
template<typename Context, typename Parser>
void print_parser(
Context const & context,
no_case_parser<Parser> const & parser,
std::ostream & os,
int components)
{
detail::print_directive(
context, "no_case", parser.parser_, os, components);
}
template<typename Context, typename Parser, typename SkipParser>
void print_parser(
Context const & context,
skip_parser<Parser, SkipParser> const & parser,
std::ostream & os,
int components)
{
if constexpr (is_nope_v<SkipParser>) {
detail::print_directive(
context, "skip", parser.parser_, os, components);
} else {
os << "skip(";
detail::print_parser(
context, parser.skip_parser_.parser_, os, components);
os << ")";
detail::print_directive(
context, "", parser.parser_, os, components + 1);
}
}
template<typename Context, typename Parser, typename ParserConfig>
void print_parser(
Context const & context,
expect_parser_t<Parser, ParserConfig> const & parser,
std::ostream & os,
int components)
{
if (ParserConfig::fail_on_match)
os << "!";
else
os << "&";
constexpr bool n_ary_child = n_aray_parser_v<Parser>;
if (n_ary_child)
os << "(";
detail::print_parser(context, parser.parser_, os, components + 1);
if (n_ary_child)
os << ")";
}
template<
typename Context,
bool UseCallbacks,
typename Parser,
typename Attribute,
typename LocalState,
typename ParamsTuple>
void print_parser(
Context const & context,
rule_parser<
UseCallbacks,
Parser,
Attribute,
LocalState,
ParamsTuple> const & parser,
std::ostream & os,
int components)
{
os << parser.diagnostic_text_;
if constexpr (!is_nope_v<ParamsTuple>) {
os << ".with(";
int i = 0;
hl::for_each(parser.params_, [&](auto const & param) {
if (i++)
os << ", ";
detail::print_expected(context, os, param, true);
});
os << ")";
}
}
template<typename Context, typename T>
void print_parser(
Context const & context,
symbol_parser<T> const & parser,
std::ostream & os,
int components)
{
os << "symbols<" << detail::type_name<T>() << ">";
}
template<typename Context, typename Predicate>
void print_parser(
Context const & context,
eps_parser<Predicate> const & parser,
std::ostream & os,
int components)
{
os << "eps(<<pred>>)";
}
template<typename Context>
void print_parser(
Context const & context,
eps_parser<nope> const & parser,
std::ostream & os,
int components)
{
os << "eps";
}
template<typename Context>
void print_parser(
Context const & context,
eoi_parser const & parser,
std::ostream & os,
int components)
{
os << "eoi";
}
template<typename Context, typename Atribute>
void print_parser(
Context const & context,
attr_parser<Atribute> const & parser,
std::ostream & os,
int components)
{
os << "attr";
detail::print_expected(context, os, parser.attr_);
}
template<
typename Context,
typename ResolvedExpected,
bool Integral = std::is_integral<ResolvedExpected>{},
int SizeofExpected = sizeof(ResolvedExpected)>
struct print_expected_char_impl
{
static void call(
Context const & context,
std::ostream & os,
ResolvedExpected expected)
{
detail::print(os, expected);
}
};
template<typename Context, typename Expected>
struct print_expected_char_impl<Context, Expected, true, 4>
{
static void
call(Context const & context, std::ostream & os, Expected expected)
{
std::array<char32_t, 1> cps = {{(char32_t)expected}};
auto const r = cps | text::as_utf8;
os << "'";
for (auto c : r) {
detail::print_char(os, c);
}
os << "'";
}
};
template<typename Context, typename Expected>
void print_expected_char(
Context const & context, std::ostream & os, Expected expected)
{
auto resolved_expected = detail::resolve(context, expected);
detail::print_expected_char_impl<Context, decltype(resolved_expected)>::
call(context, os, resolved_expected);
}
template<typename Context, typename T>
struct char_print_parser_impl
{
static void call(Context const & context, std::ostream & os, T expected)
{
detail::print_expected_char(context, os, expected);
}
};
template<typename Context, typename T, typename U>
struct char_print_parser_impl<Context, char_pair<T, U>>
{
static void call(
Context const & context,
std::ostream & os,
char_pair<T, U> expected)
{
detail::print_expected_char(context, os, expected.lo_);
os << ", ";
detail::print_expected_char(context, os, expected.hi_);
}
};
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, B> expected)
{
os << "\"";
auto const r = expected.chars_ | text::as_utf8;
for (auto c : r) {
detail::print_char(os, c);
}
os << "\"";
}
};
template<typename Context, typename Expected, typename AttributeType>
void print_parser(
Context const & context,
char_parser<Expected, AttributeType> const & parser,
std::ostream & os,
int components)
{
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,
omit_parser<char_parser<Expected, AttributeType>> const & parser,
std::ostream & os,
int components)
{
if constexpr (is_nope_v<Expected>) {
os << "omit[char_]";
} else {
char_print_parser_impl<Context, Expected>::call(
context, os, parser.parser_.expected_);
}
}
template<typename Context, typename StrIter, typename StrSentinel>
void print_parser(
Context const & context,
string_parser<StrIter, StrSentinel> const & parser,
std::ostream & os,
int components)
{
os << "string(\"";
for (auto c : BOOST_PARSER_DETAIL_TEXT_SUBRANGE(
parser.expected_first_, parser.expected_last_) |
text::as_utf8) {
detail::print_char(os, c);
}
os << "\")";
}
template<typename Context, typename StrIter, typename StrSentinel>
void print_parser(
Context const & context,
omit_parser<string_parser<StrIter, StrSentinel>> const & parser,
std::ostream & os,
int components)
{
os << "\"";
for (auto c : BOOST_PARSER_DETAIL_TEXT_SUBRANGE(
parser.parser_.expected_first_,
parser.parser_.expected_last_) |
text::as_utf8) {
detail::print_char(os, c);
}
os << "\"";
}
template<typename Context, bool NewlinesOnly, bool NoNewlines>
void print_parser(
Context const & context,
ws_parser<NewlinesOnly, NoNewlines> const & parser,
std::ostream & os,
int components)
{
if constexpr (NoNewlines)
os << "blank";
else if constexpr (NewlinesOnly)
os << "eol";
else
os << "ws";
}
template<typename Context>
void print_parser(
Context const & context,
bool_parser const & parser,
std::ostream & os,
int components)
{
os << "bool_";
}
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
Context const & context,
uint_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
std::ostream & os,
int components)
{
if (MinDigits == 1 && MaxDigits == -1) {
if (std::is_same_v<T, unsigned short>) {
os << "ushort_";
detail::print_expected(context, os, parser.expected_);
return;
} else if (std::is_same_v<T, unsigned int>) {
if (Radix == 2)
os << "bin";
else if (Radix == 8)
os << "oct";
else if (Radix == 16)
os << "hex";
else if (Radix == 10)
os << "uint_";
detail::print_expected(context, os, parser.expected_);
return;
} else if (Radix == 10 && std::is_same_v<T, unsigned long>) {
os << "ulong_";
detail::print_expected(context, os, parser.expected_);
return;
} else if (Radix == 10 && std::is_same_v<T, unsigned long long>) {
os << "ulong_long";
detail::print_expected(context, os, parser.expected_);
return;
}
}
os << "uint<" << detail::type_name<T>() << ", " << Radix << ", "
<< MinDigits << ", " << MaxDigits << ">";
detail::print_expected(context, os, parser.expected_);
}
template<
typename Context,
typename T,
int Radix,
int MinDigits,
int MaxDigits,
typename Expected>
void print_parser(
Context const & context,
int_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
std::ostream & os,
int components)
{
if (Radix == 10 && MinDigits == 1 && MaxDigits == -1) {
if (std::is_same_v<T, short>) {
os << "short_";
detail::print_expected(context, os, parser.expected_);
return;
} else if (std::is_same_v<T, int>) {
os << "int_";
detail::print_expected(context, os, parser.expected_);
return;
} else if (std::is_same_v<T, long>) {
os << "long_";
detail::print_expected(context, os, parser.expected_);
return;
} else if (std::is_same_v<T, long long>) {
os << "long_long";
detail::print_expected(context, os, parser.expected_);
return;
}
}
os << "int<" << detail::type_name<T>() << ", " << Radix << ", "
<< MinDigits << ", " << MaxDigits << ">";
detail::print_expected(context, os, parser.expected_);
}
template<typename Context>
void print_parser(
Context const & context,
int_parser<short> const & parser,
std::ostream & os,
int components)
{
os << "short_";
}
template<typename Context>
void print_parser(
Context const & context,
int_parser<long> const & parser,
std::ostream & os,
int components)
{
os << "long_";
}
template<typename Context>
void print_parser(
Context const & context,
int_parser<long long> const & parser,
std::ostream & os,
int components)
{
os << "long_long";
}
template<typename Context, typename T>
void print_parser(
Context const & context,
float_parser<T> const & parser,
std::ostream & os,
int components)
{
os << "float<" << detail::type_name<T>() << ">";
}
template<typename Context>
void print_parser(
Context const & context,
float_parser<float> const & parser,
std::ostream & os,
int components)
{
os << "float_";
}
template<typename Context>
void print_parser(
Context const & context,
float_parser<double> const & parser,
std::ostream & os,
int components)
{
os << "double_";
}
template<
typename Context,
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups>
void print_switch_matchers(
Context const & context,
seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups> const &
parser,
std::ostream & os,
int components)
{
using namespace literals;
os << "(";
detail::print(
os,
detail::resolve(
context, parser::get(parser.parsers_, 0_c).pred_.value_));
os << ", ";
detail::print_parser(
context, parser::get(parser.parsers_, 1_c), os, components);
os << ")";
}
template<typename Context, typename ParserTuple>
void print_switch_matchers(
Context const & context,
or_parser<ParserTuple> const & parser,
std::ostream & os,
int components)
{
using namespace literals;
bool printed_ellipsis = false;
hl::for_each(parser.parsers_, [&](auto const & parser) {
if (components == parser_component_limit) {
if (!printed_ellipsis)
os << "...";
printed_ellipsis = true;
return;
}
detail::print_switch_matchers(context, parser, os, components);
++components;
});
}
template<typename Context, typename SwitchValue, typename OrParser>
void print_parser(
Context const & context,
switch_parser<SwitchValue, OrParser> const & parser,
std::ostream & os,
int components)
{
os << "switch_(";
detail::print(os, detail::resolve(context, parser.switch_value_));
os << ")";
detail::print_switch_matchers(
context, parser.or_parser_, os, components);
}
}}}
#endif

View File

@@ -1,47 +0,0 @@
// Copyright (C) 2020 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_STL_INTERFACES_CONFIG_HPP
#define BOOST_PARSER_DETAIL_STL_INTERFACES_CONFIG_HPP
#include <boost/parser/config.hpp>
#if !BOOST_PARSER_USE_CONCEPTS
# define BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS 0
#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.
# define BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS 0
#endif
#if defined(__cpp_explicit_this_parameter) && BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
#define BOOST_PARSER_USE_DEDUCED_THIS 1
#else
#define BOOST_PARSER_USE_DEDUCED_THIS 0
#endif
// The inline namespaces v1, v2, and v3 represent C++14, C++20, and C++23 and
// later, respectively. v1 is inline for standards before C++20, and v2 is
// inline for C++20 and later. Note that this only applies to code for which
// multiple vI namespace alternatives exist. For example, some instances of
// the v1 namespace may still be inline, if there is no v2 version of its
// contents.
#if !BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && !BOOST_PARSER_USE_DEDUCED_THIS
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V1 inline namespace v1
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V2 namespace v2
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V3 namespace v3
#elif BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && !BOOST_PARSER_USE_DEDUCED_THIS
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V1 namespace v1
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V2 inline namespace v2
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V3 namespace v3
#else
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V1 namespace v1
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V2 namespace v2
# define BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V3 inline namespace v3
#endif
#endif

View File

@@ -1,152 +0,0 @@
// Copyright (C) 2022 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_STL_INTERFACES_DETAIL_PIPEABLE_VIEW_HPP
#define BOOST_PARSER_DETAIL_STL_INTERFACES_DETAIL_PIPEABLE_VIEW_HPP
#include <boost/parser/config.hpp>
#include <type_traits>
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
#include <ranges>
#endif
namespace boost::parser::detail { namespace stl_interfaces { namespace detail {
template<typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
struct pipeable_base;
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename T>
concept pipeable_ = std::derived_from<T, pipeable_base> &&
std::is_object_v<T> && std::copy_constructible<T>;
#else
template<typename T>
constexpr bool pipeable_ = std::is_base_of<pipeable_base, T>::value &&
std::is_object<T>::value && std::is_copy_constructible<T>::value;
#endif
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<pipeable_ T, pipeable_ U>
#else
template<
typename T,
typename U,
typename Enable = std::enable_if_t<pipeable_<T> && pipeable_<U>>>
#endif
struct view_pipeline;
struct pipeable_base
{
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<pipeable_ T, pipeable_ U>
requires std::constructible_from<std::remove_cvref_t<T>, T> &&
std::constructible_from<std::remove_cvref_t<U>, U>
#else
template<
typename T,
typename U,
typename Enable = std::enable_if_t<
pipeable_<T> && pipeable_<U> &&
std::is_constructible<remove_cvref_t<T>, T>::value &&
std::is_constructible<remove_cvref_t<U>, U>::value>>
#endif
friend constexpr auto operator|(T && t, U && u)
{
return view_pipeline<T, U>{(T &&) t, (U &&) u};
}
};
template<typename Derived>
struct pipeable : pipeable_base
{
template<typename R>
friend constexpr auto operator|(R && r, Derived & d)
-> decltype(((Derived &&) d)((R &&) r))
{
return ((Derived &&) d)((R &&) r);
}
template<typename R>
friend constexpr auto operator|(R && r, Derived const & d)
-> decltype(((Derived &&) d)((R &&) r))
{
return ((Derived &&) d)((R &&) r);
}
template<typename R>
friend constexpr auto operator|(R && r, Derived && d)
-> decltype(((Derived &&) d)((R &&) r))
{
return ((Derived &&) d)((R &&) r);
}
};
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<pipeable_ T, pipeable_ U>
#else
template<typename T, typename U, typename>
#endif
struct view_pipeline : pipeable<view_pipeline<T, U>>
{
view_pipeline() = default;
constexpr view_pipeline(T && t, U && u) :
left_(std::move(t)), right_(std::move(u))
{}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<std::ranges::viewable_range R>
requires std::invocable<T &, R> &&
std::invocable<U &, std::invoke_result_t<T &, R>>
constexpr decltype(auto) operator()(R && r) &
#else
template<typename R>
constexpr auto
operator()(R && r) & -> decltype(this->right_(this->left_((R &&) r)))
#endif
{
return right_(left_((R &&) r));
}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<std::ranges::viewable_range R>
requires std::invocable<T const &, R> &&
std::invocable<U const &, std::invoke_result_t<T const &, R>>
constexpr decltype(auto) operator()(R && r) const &
#else
template<typename R>
constexpr auto operator()(
R && r) const & -> decltype(this->right_(this->left_((R &&) r)))
#endif
{
return right_(left_((R &&) r));
}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<std::ranges::viewable_range R>
requires std::invocable<T, R> &&
std::invocable<U, std::invoke_result_t<T, R>>
constexpr decltype(auto) operator()(R && r) &&
#else
template<typename R>
constexpr auto operator()(R && r) && -> decltype(std::move(
this->right_)(std::move(this->left_)((R &&) r)))
#endif
{
return std::move(right_)(std::move(left_)((R &&) r));
}
T left_;
U right_;
};
}}}
#endif

View File

@@ -1,107 +0,0 @@
// Copyright (C) 2022 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_STL_INTERFACES_DETAIL_VIEW_CLOSURE_HPP
#define BOOST_PARSER_DETAIL_STL_INTERFACES_DETAIL_VIEW_CLOSURE_HPP
#include <boost/parser/detail/stl_interfaces/detail/pipeable_view.hpp>
#include <utility>
namespace boost::parser::detail { namespace stl_interfaces { namespace detail {
template<std::size_t I, typename T>
struct box
{
T value_;
};
template<typename Indices, typename Func, typename... T>
struct view_closure_impl;
template<std::size_t... I, typename Func, typename... T>
struct view_closure_impl<std::index_sequence<I...>, Func, T...>
: box<I, T>...
{
view_closure_impl() = default;
constexpr explicit view_closure_impl(Func, T &&... x) :
box<I, T>{std::move(x)}...
{}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<std::ranges::input_range R>
requires std::ranges::viewable_range<R> &&
std::invocable<Func, R, T &...> &&
std::ranges::view<std::invoke_result_t<Func, R, T &...>>
constexpr auto operator()(R && r) &
#else
template<typename R>
constexpr auto operator()(R && r) & -> decltype(
Func{}((R &&) r, std::declval<box<I, T> &>().value_...))
#endif
{
return Func{}((R &&) r, static_cast<box<I, T> &>(*this).value_...);
}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<std::ranges::input_range R>
requires std::ranges::viewable_range<R> &&
std::invocable<Func, R, T const &...> &&
std::ranges::view<std::invoke_result_t<Func, R, T const &...>>
constexpr auto operator()(R && r) const &
#else
template<typename R>
constexpr auto operator()(R && r) const & -> decltype(
Func{}((R &&) r, std::declval<box<I, T> const &>().value_...))
#endif
{
return Func{}(
(R &&) r, static_cast<box<I, T> const &>(*this).value_...);
}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<std::ranges::input_range R>
requires std::ranges::viewable_range<R> &&
std::invocable<Func, R, T...> &&
std::ranges::view<std::invoke_result_t<Func, R, T...>>
constexpr auto operator()(R && r) &&
#else
template<typename R>
constexpr auto operator()(R && r) && -> decltype(
Func{}((R &&) r, std::declval<box<I, T> &&>().value_...))
#endif
{
return Func{}((R &&) r, static_cast<box<I, T> &&>(*this).value_...);
}
};
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<std::semiregular Func, std::copy_constructible... T>
#else
template<typename Func, typename... T>
#endif
struct view_closure
: pipeable<view_closure<Func, T...>>,
view_closure_impl<std::index_sequence_for<T...>, Func, T...>
{
using base_type =
view_closure_impl<std::index_sequence_for<T...>, Func, T...>;
view_closure() = default;
constexpr explicit view_closure(Func func, T &&... x) :
base_type{func, std::move(x)...}
{}
};
#if defined(__cpp_deduction_guides)
template<typename Func, typename... T>
view_closure(Func, T...) -> view_closure<Func, T...>;
#endif
}}}
#endif

View File

@@ -1,86 +0,0 @@
// Copyright (C) 2019 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_STL_INTERFACES_FWD_HPP
#define BOOST_PARSER_DETAIL_STL_INTERFACES_FWD_HPP
#include <boost/parser/detail/stl_interfaces/config.hpp>
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
#include <ranges>
#endif
#if defined(__cpp_lib_three_way_comparison)
#include <compare>
#endif
namespace boost::parser::detail { namespace stl_interfaces {
/** An enumeration used to indicate whether the underlying data have a
contiguous or discontiguous layout when instantiating `view_interface`
and `sequence_container_interface`. */
enum class element_layout : bool {
discontiguous = false,
contiguous = true
};
BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V1 {
namespace v1_dtl {
template<typename... T>
using void_t = void;
template<typename Iter>
using iter_difference_t =
typename std::iterator_traits<Iter>::difference_type;
template<typename Range, typename = void>
struct iterator;
template<typename Range>
struct iterator<
Range,
void_t<decltype(std::declval<Range &>().begin())>>
{
using type = decltype(std::declval<Range &>().begin());
};
template<typename Range>
using iterator_t = typename iterator<Range>::type;
template<typename Range, typename = void>
struct sentinel;
template<typename Range>
struct sentinel<
Range,
void_t<decltype(std::declval<Range &>().end())>>
{
using type = decltype(std::declval<Range &>().end());
};
template<typename Range>
using sentinel_t = typename sentinel<Range>::type;
template<typename Range>
using range_difference_t = iter_difference_t<iterator_t<Range>>;
template<typename Range>
using common_range =
std::is_same<iterator_t<Range>, sentinel_t<Range>>;
template<typename Range, typename = void>
struct decrementable_sentinel : std::false_type
{
};
template<typename Range>
struct decrementable_sentinel<
Range,
void_t<decltype(--std::declval<sentinel_t<Range> &>())>>
: std::true_type
{
};
}
}
}}
#endif

View File

@@ -1,221 +0,0 @@
// Copyright (C) 2019 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_STL_INTERFACES_REVERSE_ITERATOR_HPP
#define BOOST_PARSER_DETAIL_STL_INTERFACES_REVERSE_ITERATOR_HPP
#include <boost/parser/detail/stl_interfaces/iterator_interface.hpp>
namespace boost::parser::detail { namespace stl_interfaces { BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V1 {
namespace v1_dtl {
template<typename Iter>
constexpr auto ce_dist(Iter f, Iter l, std::random_access_iterator_tag)
-> decltype(l - f)
{
return l - f;
}
template<typename Iter, typename Tag>
constexpr auto ce_dist(Iter f, Iter l, Tag)
-> decltype(std::distance(f, l))
{
decltype(std::distance(f, l)) retval = 0;
for (; f != l; ++f) {
++retval;
}
return retval;
}
template<typename Iter>
constexpr Iter ce_prev(Iter it)
{
return --it;
}
template<typename Iter, typename Offset>
constexpr void
ce_adv(Iter & f, Offset n, std::random_access_iterator_tag)
{
f += n;
}
template<typename Iter, typename Offset, typename Tag>
constexpr void ce_adv(Iter & f, Offset n, Tag)
{
if (0 < n) {
for (Offset i = 0; i < n; ++i) {
++f;
}
} else {
for (Offset i = 0; i < -n; ++i) {
--f;
}
}
}
}
/** This type is very similar to the C++20 version of
`std::reverse_iterator`; it is `constexpr`-, `noexcept`-, and
proxy-friendly. */
template<typename BidiIter>
struct reverse_iterator
: iterator_interface<
#if !BOOST_PARSER_USE_DEDUCED_THIS
reverse_iterator<BidiIter>,
#endif
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
typename boost::parser::detail::stl_interfaces::v2::v2_dtl::iter_concept_t<
BidiIter>,
#else
typename std::iterator_traits<BidiIter>::iterator_category,
#endif
typename std::iterator_traits<BidiIter>::value_type,
typename std::iterator_traits<BidiIter>::reference,
typename std::iterator_traits<BidiIter>::pointer,
typename std::iterator_traits<BidiIter>::difference_type>
{
constexpr reverse_iterator() noexcept(noexcept(BidiIter())) : it_() {}
constexpr reverse_iterator(BidiIter it) noexcept(
noexcept(BidiIter(it))) :
it_(it)
{}
template<
typename BidiIter2,
typename E = std::enable_if_t<
std::is_convertible<BidiIter2, BidiIter>::value>>
reverse_iterator(reverse_iterator<BidiIter2> const & it) : it_(it.it_)
{}
friend constexpr auto
operator-(reverse_iterator lhs, reverse_iterator rhs) noexcept(
noexcept(v1_dtl::ce_dist(
lhs.it_,
rhs.it_,
typename std::iterator_traits<BidiIter>::iterator_category{})))
{
return -v1_dtl::ce_dist(
rhs.it_,
lhs.it_,
typename std::iterator_traits<BidiIter>::iterator_category{});
}
constexpr typename std::iterator_traits<BidiIter>::reference
operator*() const noexcept(
noexcept(std::prev(v1_dtl::ce_prev(std::declval<BidiIter &>()))))
{
return *v1_dtl::ce_prev(it_);
}
constexpr reverse_iterator & operator+=(
typename std::iterator_traits<BidiIter>::difference_type
n) noexcept(noexcept(v1_dtl::
ce_adv(
std::declval<BidiIter &>(),
-n,
typename std::iterator_traits<
BidiIter>::
iterator_category{})))
{
v1_dtl::ce_adv(
it_,
-n,
typename std::iterator_traits<BidiIter>::iterator_category{});
return *this;
}
constexpr BidiIter base() const noexcept { return it_; }
private:
friend access;
constexpr BidiIter & base_reference() noexcept { return it_; }
constexpr BidiIter const & base_reference() const noexcept
{
return it_;
}
template<typename BidiIter2>
friend struct reverse_iterator;
BidiIter it_;
};
template<typename BidiIter>
constexpr auto operator==(
reverse_iterator<BidiIter> lhs,
reverse_iterator<BidiIter>
rhs) noexcept(noexcept(lhs.base() == rhs.base()))
-> decltype(rhs.base() == lhs.base())
{
return lhs.base() == rhs.base();
}
template<typename BidiIter1, typename BidiIter2>
constexpr auto operator==(
reverse_iterator<BidiIter1> lhs,
reverse_iterator<BidiIter2>
rhs) noexcept(noexcept(lhs.base() == rhs.base()))
-> decltype(rhs.base() == lhs.base())
{
return lhs.base() == rhs.base();
}
/** Makes a `reverse_iterator<BidiIter>` from an iterator of type
`BidiIter`. */
template<typename BidiIter>
auto make_reverse_iterator(BidiIter it)
{
return reverse_iterator<BidiIter>(it);
}
}}}
#if defined(BOOST_STL_INTERFACES_DOXYGEN) || BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
namespace boost::parser::detail { namespace stl_interfaces { BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V2 {
/** A template alias for `std::reverse_iterator`. This only exists to
make migration from Boost.STLInterfaces to C++20 easier; switch to the
one in `std` as soon as you can. */
template<typename BidiIter>
using reverse_iterator = std::reverse_iterator<BidiIter>;
/** Makes a `reverse_iterator<BidiIter>` from an iterator of type
`BidiIter`. This only exists to make migration from
Boost.STLInterfaces to C++20 easier; switch to the one in `std` as
soon as you can. */
template<typename BidiIter>
auto make_reverse_iterator(BidiIter it)
{
return reverse_iterator<BidiIter>(it);
}
}}}
namespace boost::parser::detail { namespace stl_interfaces { BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V3 {
/** A template alias for `std::reverse_iterator`. This only exists to
make migration from Boost.STLInterfaces to C++20 easier; switch to the
one in `std` as soon as you can. */
template<typename BidiIter>
using reverse_iterator = std::reverse_iterator<BidiIter>;
/** Makes a `reverse_iterator<BidiIter>` from an iterator of type
`BidiIter`. This only exists to make migration from
Boost.STLInterfaces to C++20 easier; switch to the one in `std` as
soon as you can. */
template<typename BidiIter>
auto make_reverse_iterator(BidiIter it)
{
return reverse_iterator<BidiIter>(it);
}
}}}
#endif
#endif

View File

@@ -1,331 +0,0 @@
// Copyright (C) 2022 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_STL_INTERFACES_VIEW_ADAPTOR_HPP
#define BOOST_PARSER_DETAIL_STL_INTERFACES_VIEW_ADAPTOR_HPP
#include <boost/parser/detail/stl_interfaces/config.hpp>
#include <boost/parser/detail/stl_interfaces/detail/view_closure.hpp>
#include <boost/parser/detail/detection.hpp>
#include <tuple>
#include <type_traits>
#if !defined(BOOST_STL_INTERFACES_DOXYGEN)
#if defined(__cpp_lib_ranges) && 202202L <= __cpp_lib_ranges
#define BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 1
#else
#define BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 0
#endif
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS && defined(__GNUC__) && 12 <= __GNUC__
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 1
#else
#define BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 0
#endif
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
defined(_MSC_VER) && _MSC_VER <= 1929
#define BOOST_PARSER_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE 1
#else
#define BOOST_PARSER_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE 0
#endif
#if !BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
!BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE && \
!BOOST_PARSER_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE
#define BOOST_PARSER_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE 1
#else
#define BOOST_PARSER_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE 0
#endif
#endif
namespace boost::parser::detail { namespace stl_interfaces {
namespace detail {
template<typename F, typename... Args>
using invocable_expr =
decltype(std::declval<F>()(std::declval<Args>()...));
template<typename F, typename... Args>
constexpr bool is_invocable_v =
is_detected_v<invocable_expr, F, Args...>;
template<typename Func, typename... CapturedArgs>
struct bind_back_t
{
static_assert(std::is_move_constructible<Func>::value, "");
#if defined(__cpp_fold_expressions)
static_assert(
(std::is_move_constructible<CapturedArgs>::value && ...), "");
#endif
template<typename F, typename... Args>
explicit constexpr bind_back_t(int, F && f, Args &&... args) :
f_((F &&) f), bound_args_((Args &&) args...)
{
static_assert(sizeof...(Args) == sizeof...(CapturedArgs), "");
}
template<typename... Args>
constexpr decltype(auto) operator()(Args &&... args) &
{
return call_impl(*this, indices(), (Args &&) args...);
}
template<typename... Args>
constexpr decltype(auto) operator()(Args &&... args) const &
{
return call_impl(*this, indices(), (Args &&) args...);
}
template<typename... Args>
constexpr decltype(auto) operator()(Args &&... args) &&
{
return call_impl(
std::move(*this), indices(), (Args &&) args...);
}
template<typename... Args>
constexpr decltype(auto) operator()(Args &&... args) const &&
{
return call_impl(
std::move(*this), indices(), (Args &&) args...);
}
private:
using indices = std::index_sequence_for<CapturedArgs...>;
template<typename T, size_t... I, typename... Args>
static constexpr decltype(auto)
call_impl(T && this_, std::index_sequence<I...>, Args &&... args)
{
return ((T &&) this_)
.f_((Args &&) args...,
std::get<I>(((T &&) this_).bound_args_)...);
}
Func f_;
std::tuple<CapturedArgs...> bound_args_;
};
template<typename Func, typename... Args>
using bind_back_result =
bind_back_t<std::decay_t<Func>, std::decay_t<Args>...>;
}
/** An implementation of `std::bind_back()` from C++23. */
template<typename Func, typename... Args>
constexpr auto bind_back(Func && f, Args &&... args)
{
return detail::bind_back_result<Func, Args...>(
0, (Func &&) f, (Args &&) args...);
}
#if BOOST_PARSER_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE || \
defined(BOOST_STL_INTERFACES_DOXYGEN)
/** A backwards-compatible implementation of C++23's
`std::ranges::range_adaptor_closure`. `range_adaptor_closure` may be
a struct template or may be an alias, as required to maintain
compatability with the standard library's view adaptors. */
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename D>
requires std::is_class_v<D> && std::same_as<D, std::remove_cv_t<D>>
#else
template<
typename D,
typename Enable = std::enable_if_t<
std::is_class<D>::value &&
std::is_same<D, std::remove_cv_t<D>>::value>>
#endif
struct range_adaptor_closure;
namespace detail {
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename T>
concept range_adaptor_closure_ = std::derived_from<
std::remove_cvref_t<T>,
range_adaptor_closure<std::remove_cvref_t<T>>>;
#else
template<typename T>
using range_adaptor_closure_tag_expr = typename range_adaptor_closure<
T>::inheritance_tag_with_an_unlikely_name_;
template<typename T>
constexpr bool range_adaptor_closure_ =
is_detected_v<range_adaptor_closure_tag_expr, remove_cvref_t<T>>;
#endif
}
#endif
#if BOOST_PARSER_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE
template<typename D>
using range_adaptor_closure = std::ranges::range_adaptor_closure<D>;
#elif BOOST_PARSER_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE
template<typename D>
using range_adaptor_closure = std::views::__adaptor::_RangeAdaptorClosure;
#elif BOOST_PARSER_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE
template<typename D>
using range_adaptor_closure = detail::pipeable<D>;
#else
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename D>
requires std::is_class_v<D> && std::same_as<D, std::remove_cv_t<D>>
#else
template<typename D, typename>
#endif
struct range_adaptor_closure
{
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename T>
requires std::invocable<D, T>
#else
template<
typename T,
typename Enable = std::enable_if_t<detail::is_invocable_v<D, T>>>
#endif
[[nodiscard]] friend constexpr decltype(auto) operator|(T && t, D && d)
{
return std::move(d)((T &&) t);
}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename T>
requires std::invocable<D const &, T>
#else
template<
typename T,
typename Enable =
std::enable_if_t<detail::is_invocable_v<D const &, T>>>
#endif
[[nodiscard]] friend constexpr decltype(auto)
operator|(T && t, D const & d)
{
return d((T &&) t);
}
using inheritance_tag_with_an_unlikely_name_ = int;
};
#endif
//[closure_defn
/** An invocable consisting of a contained invocable `f`. Calling
`operator()` with some argument `t` calls `f(t)` and returns the
result. This type is typically used to capture a the result of a call
to `bind_back()`. */
template<typename F>
struct closure : range_adaptor_closure<closure<F>>
{
constexpr closure(F f) : f_(f) {}
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename T>
requires std::invocable<F const &, T>
#else
template<
typename T,
typename Enable =
std::enable_if_t<detail::is_invocable_v<F const &, T>>>
#endif
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_;
};
//]
namespace detail {
#if !BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
template<typename F, bool Invocable, typename... Args>
struct adaptor_impl
{
static constexpr decltype(auto) call(F const & f, Args &&... args)
{
return f((Args &&) args...);
}
};
template<typename F, typename... Args>
struct adaptor_impl<F, false, Args...>
{
static constexpr auto call(F const & f, Args &&... args)
{
using closure_func =
std::decay_t<decltype(stl_interfaces::bind_back(
f, (Args &&) args...))>;
return closure<closure_func>(
stl_interfaces::bind_back(f, (Args &&) args...));
}
};
#endif
}
//[adaptor_defn
/** Adapts an invocable `f` as a view adaptor. Calling
`operator(args...)` will either: call `f(args...)` and return the
result, if `f(args...)` is well-formed; or return
`closure(stl_interfaces::bind_back(f, args...))` otherwise. */
template<typename F>
struct adaptor
{
constexpr adaptor(F f) : f_(f) {}
// clang-format off
template<typename... Args>
constexpr auto operator()(Args &&... args) const
// clang-format on
{
#if BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
if constexpr (std::is_invocable_v<F const &, Args...>) {
return f_((Args &&) args...);
} else {
return closure(
stl_interfaces::bind_back(f_, (Args &&) args...));
}
#else
return detail::adaptor_impl<
F const &,
detail::is_invocable_v<F const &, Args...>,
Args...>::call(f_, (Args &&) args...);
#endif
}
private:
F f_;
};
//]
}}
#endif

View File

@@ -1,228 +0,0 @@
// Copyright (C) 2019 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_STL_INTERFACES_VIEW_INTERFACE_HPP
#define BOOST_PARSER_DETAIL_STL_INTERFACES_VIEW_INTERFACE_HPP
#include <boost/parser/detail/stl_interfaces/fwd.hpp>
namespace boost::parser::detail { namespace stl_interfaces { BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V1 {
/** A CRTP template that one may derive from to make it easier to define
`std::ranges::view`-like types with a container-like interface. This
is a pre-C++20 version of C++20's `view_interface` (see
[view.interface] in the C++ standard).
The template parameter `D` for `view_interface` may be an incomplete
type. Before any member of the resulting specialization of
`view_interface` other than special member functions is referenced,
`D` shall be complete, and model both
`std::derived_from<view_interface<D>>` and `std::view`. */
template<
typename Derived,
element_layout Contiguity = element_layout::discontiguous
#ifndef BOOST_STL_INTERFACES_DOXYGEN
,
typename E = std::enable_if_t<
std::is_class<Derived>::value &&
std::is_same<Derived, std::remove_cv_t<Derived>>::value>
#endif
>
struct view_interface;
namespace v1_dtl {
template<typename D, element_layout Contiguity>
void derived_view(view_interface<D, Contiguity> const &);
}
template<
typename Derived,
element_layout Contiguity
#ifndef BOOST_STL_INTERFACES_DOXYGEN
,
typename E
#endif
>
struct view_interface
{
#ifndef BOOST_STL_INTERFACES_DOXYGEN
private:
constexpr Derived & derived() noexcept
{
return static_cast<Derived &>(*this);
}
constexpr const Derived & derived() const noexcept
{
return static_cast<Derived const &>(*this);
}
#endif
public:
template<typename D = Derived>
constexpr auto empty() noexcept(
noexcept(std::declval<D &>().begin() == std::declval<D &>().end()))
-> decltype(
std::declval<D &>().begin() == std::declval<D &>().end())
{
return derived().begin() == derived().end();
}
template<typename D = Derived>
constexpr auto empty() const noexcept(noexcept(
std::declval<D const &>().begin() ==
std::declval<D const &>().end()))
-> decltype(
std::declval<D const &>().begin() ==
std::declval<D const &>().end())
{
return derived().begin() == derived().end();
}
template<
typename D = Derived,
typename R = decltype(std::declval<D &>().empty())>
constexpr explicit
operator bool() noexcept(noexcept(std::declval<D &>().empty()))
{
return !derived().empty();
}
template<
typename D = Derived,
typename R = decltype(std::declval<D const &>().empty())>
constexpr explicit operator bool() const
noexcept(noexcept(std::declval<D const &>().empty()))
{
return !derived().empty();
}
template<
typename D = Derived,
element_layout C = Contiguity,
typename Enable = std::enable_if_t<C == element_layout::contiguous>>
constexpr auto data() noexcept(noexcept(std::declval<D &>().begin()))
-> decltype(std::addressof(*std::declval<D &>().begin()))
{
return std::addressof(*derived().begin());
}
template<
typename D = Derived,
element_layout C = Contiguity,
typename Enable = std::enable_if_t<C == element_layout::contiguous>>
constexpr auto data() const
noexcept(noexcept(std::declval<D const &>().begin()))
-> decltype(std::addressof(*std::declval<D const &>().begin()))
{
return std::addressof(*derived().begin());
}
template<typename D = Derived>
constexpr auto size() noexcept(
noexcept(std::declval<D &>().end() - std::declval<D &>().begin()))
-> decltype(std::declval<D &>().end() - std::declval<D &>().begin())
{
return derived().end() - derived().begin();
}
template<typename D = Derived>
constexpr auto size() const noexcept(noexcept(
std::declval<D const &>().end() -
std::declval<D const &>().begin()))
-> decltype(
std::declval<D const &>().end() -
std::declval<D const &>().begin())
{
return derived().end() - derived().begin();
}
template<typename D = Derived>
constexpr auto front() noexcept(noexcept(*std::declval<D &>().begin()))
-> decltype(*std::declval<D &>().begin())
{
return *derived().begin();
}
template<typename D = Derived>
constexpr auto front() const
noexcept(noexcept(*std::declval<D const &>().begin()))
-> decltype(*std::declval<D const &>().begin())
{
return *derived().begin();
}
template<
typename D = Derived,
typename Enable = std::enable_if_t<
v1_dtl::decrementable_sentinel<D>::value &&
v1_dtl::common_range<D>::value>>
constexpr auto
back() noexcept(noexcept(*std::prev(std::declval<D &>().end())))
-> decltype(*std::prev(std::declval<D &>().end()))
{
return *std::prev(derived().end());
}
template<
typename D = Derived,
typename Enable = std::enable_if_t<
v1_dtl::decrementable_sentinel<D>::value &&
v1_dtl::common_range<D>::value>>
constexpr auto back() const
noexcept(noexcept(*std::prev(std::declval<D const &>().end())))
-> decltype(*std::prev(std::declval<D const &>().end()))
{
return *std::prev(derived().end());
}
template<typename D = Derived>
constexpr auto operator[](v1_dtl::range_difference_t<D> n) noexcept(
noexcept(std::declval<D &>().begin()[n]))
-> decltype(std::declval<D &>().begin()[n])
{
return derived().begin()[n];
}
template<typename D = Derived>
constexpr auto operator[](v1_dtl::range_difference_t<D> n) const
noexcept(noexcept(std::declval<D const &>().begin()[n]))
-> decltype(std::declval<D const &>().begin()[n])
{
return derived().begin()[n];
}
};
/** Implementation of `operator!=()` for all views derived from
`view_interface`. */
template<typename ViewInterface>
constexpr auto operator!=(ViewInterface lhs, ViewInterface rhs) noexcept(
noexcept(lhs == rhs))
-> decltype(v1_dtl::derived_view(lhs), !(lhs == rhs))
{
return !(lhs == rhs);
}
}}}
#if defined(BOOST_STL_INTERFACES_DOXYGEN) || BOOST_PARSER_DETAIL_STL_INTERFACES_USE_CONCEPTS
namespace boost::parser::detail { namespace stl_interfaces { BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V2 {
/** A template alias for `std::ranges::view_interface`. This only exists
to make migration from Boost.STLInterfaces to C++20 easier; switch to
the one in `std` as soon as you can. */
template<typename D, element_layout = element_layout::discontiguous>
using view_interface = std::ranges::view_interface<D>;
}}}
namespace boost::parser::detail { namespace stl_interfaces { BOOST_PARSER_DETAIL_STL_INTERFACES_NAMESPACE_V3 {
/** A template alias for `std::ranges::view_interface`. This only exists
to make migration from Boost.STLInterfaces to C++20 easier; switch to
the one in `std` as soon as you can. */
template<typename D, element_layout = element_layout::discontiguous>
using view_interface = std::ranges::view_interface<D>;
}}}
#endif
#endif

View File

@@ -1,389 +0,0 @@
// Copyright (C) 2020 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_ALGORITHM_HPP
#define BOOST_PARSER_DETAIL_TEXT_ALGORITHM_HPP
#include <boost/parser/detail/text/config.hpp>
#include <boost/parser/detail/text/detail/algorithm.hpp>
#include <boost/parser/detail/text/detail/sentinel_tag.hpp>
#include <boost/parser/detail/stl_interfaces/view_interface.hpp>
#include <cstddef>
#include <iterator>
#include <utility>
namespace boost::parser::detail { namespace text {
namespace detail {
template<typename Iter>
std::ptrdiff_t distance(Iter first, Iter last, non_sentinel_tag)
{
return std::distance(first, last);
}
template<typename Iter, typename Sentinel>
std::ptrdiff_t distance(Iter first, Sentinel last, sentinel_tag)
{
std::ptrdiff_t retval = 0;
while (first != last) {
++retval;
++first;
}
return retval;
}
}
/** Range-friendly version of `std::distance()`, taking an iterator and a
sentinel. */
template<typename Iter, typename Sentinel>
std::ptrdiff_t distance(Iter first, Sentinel last)
{
return detail::distance(
first,
last,
typename std::conditional<
std::is_same<Iter, Sentinel>::value,
detail::non_sentinel_tag,
detail::sentinel_tag>::type());
}
/** Range-friendly version of `std::find()`, taking an iterator and a
sentinel. */
template<typename BidiIter, typename Sentinel, typename T>
BidiIter find(BidiIter first, Sentinel last, T const & x)
{
while (first != last) {
if (*first == x)
return first;
++first;
}
return first;
}
/** A range-friendly compliment to `std::find()`; returns an iterator to
the first element not equal to `x`. */
template<typename BidiIter, typename Sentinel, typename T>
BidiIter find_not(BidiIter first, Sentinel last, T const & x)
{
while (first != last) {
if (*first != x)
return first;
++first;
}
return first;
}
/** Range-friendly version of `std::find_if()`, taking an iterator and a
sentinel. */
template<typename BidiIter, typename Sentinel, typename Pred>
BidiIter find_if(BidiIter first, Sentinel last, Pred p)
{
while (first != last) {
if (p(*first))
return first;
++first;
}
return first;
}
/** Range-friendly version of `std::find_if_not()`, taking an iterator and
a sentinel. */
template<typename BidiIter, typename Sentinel, typename Pred>
BidiIter find_if_not(BidiIter first, Sentinel last, Pred p)
{
while (first != last) {
if (!p(*first))
return first;
++first;
}
return first;
}
/** Analogue of `std::find()` that finds the last value in `[first, last)`
equal to `x`. */
template<typename BidiIter, typename T>
BidiIter find_backward(BidiIter first, BidiIter last, T const & x)
{
auto it = last;
while (it != first) {
if (*--it == x)
return it;
}
return last;
}
/** Analogue of `std::find()` that finds the last value in `[first, last)`
not equal to `x`. */
template<typename BidiIter, typename T>
BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x)
{
auto it = last;
while (it != first) {
if (*--it != x)
return it;
}
return last;
}
/** Analogue of `std::find()` that finds the last value `v` in `[first,
last)` for which `p(v)` is true. */
template<typename BidiIter, typename Pred>
BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p)
{
auto it = last;
while (it != first) {
if (p(*--it))
return it;
}
return last;
}
/** Analogue of `std::find()` that finds the last value `v` in `[first,
last)` for which `p(v)` is false. */
template<typename BidiIter, typename Pred>
BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p)
{
auto it = last;
while (it != first) {
if (!p(*--it))
return it;
}
return last;
}
/** A utility range type returned by `foreach_subrange*()`. */
template<typename Iter, typename Sentinel = Iter>
using foreach_subrange_range =
BOOST_PARSER_DETAIL_TEXT_SUBRANGE<Iter, Sentinel>;
/** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
is a contiguous subsequence of elements that each compares equal to
the first element of the subsequence. Subranges passed to `f` are
non-overlapping. */
template<typename FwdIter, typename Sentinel, typename Func>
Func foreach_subrange(FwdIter first, Sentinel last, Func f)
{
while (first != last) {
auto const & x = *first;
auto const next = boost::parser::detail::text::find_not(first, last, x);
if (first != next) {
f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
first, next));
}
first = next;
}
return f;
}
/** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
is a contiguous subsequence of elements that for each element `e`,
`proj(e)` each compares equal to `proj()` of the first element of the
subsequence. Subranges passed to `f` are non-overlapping. */
template<typename FwdIter, typename Sentinel, typename Func, typename Proj>
Func foreach_subrange(FwdIter first, Sentinel last, Func f, Proj proj)
{
using value_type = typename std::iterator_traits<FwdIter>::value_type;
while (first != last) {
auto const & x = proj(*first);
auto const next = boost::parser::detail::text::find_if_not(
first, last, [&x, proj](const value_type & element) {
return proj(element) == x;
});
if (first != next) {
f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
first, next));
}
first = next;
}
return f;
}
/** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
is a contiguous subsequence of elements, each of which is equal to
`x`. Subranges passed to `f` are non-overlapping. */
template<typename FwdIter, typename Sentinel, typename T, typename Func>
Func foreach_subrange_of(FwdIter first, Sentinel last, T const & x, Func f)
{
while (first != last) {
first = boost::parser::detail::text::find(first, last, x);
auto const next = boost::parser::detail::text::find_not(first, last, x);
if (first != next) {
f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
first, next));
}
first = next;
}
return f;
}
/** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
is a contiguous subsequence of elements `ei` for which `p(ei)` is
true. Subranges passed to `f` are non-overlapping. */
template<typename FwdIter, typename Sentinel, typename Pred, typename Func>
Func foreach_subrange_if(FwdIter first, Sentinel last, Pred p, Func f)
{
while (first != last) {
first = boost::parser::detail::text::find_if(first, last, p);
auto const next = boost::parser::detail::text::find_if_not(first, last, p);
if (first != next) {
f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
first, next));
}
first = next;
}
return f;
}
/** Sentinel-friendly version of `std::all_of()`. */
template<typename Iter, typename Sentinel, typename Pred>
bool all_of(Iter first, Sentinel last, Pred p)
{
for (; first != last; ++first) {
if (!p(*first))
return false;
}
return true;
}
/** Sentinel-friendly version of `std::equal()`. */
template<
typename Iter1,
typename Sentinel1,
typename Iter2,
typename Sentinel2>
bool equal(Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
{
for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
if (*first1 != *first2)
return false;
}
return first1 == last1 && first2 == last2;
}
/** Sentinel-friendly version of `std::mismatch()`. */
template<
typename Iter1,
typename Sentinel1,
typename Iter2,
typename Sentinel2>
std::pair<Iter1, Iter2>
mismatch(Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
{
for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
if (*first1 != *first2)
break;
}
return {first1, first2};
}
/** Sentinel-friendly version of
`std::lexicographical_compare_three_way()`, except that it returns an
`int` instead of a `std::strong_ordering`. */
template<
typename Iter1,
typename Sentinel1,
typename Iter2,
typename Sentinel2>
int lexicographical_compare_three_way(
Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
{
auto const iters = boost::parser::detail::text::mismatch(first1, last1, first2, last2);
if (iters.first == last1) {
if (iters.second == last2)
return 0;
else
return -1;
} else if (iters.second == last2) {
return 1;
} else if (*iters.first < *iters.second) {
return -1;
} else {
return 1;
}
}
/** The view type returned by `boost::parser::detail::text::search()`. */
template<typename Iter>
using search_result = BOOST_PARSER_DETAIL_TEXT_SUBRANGE<Iter>;
/** Sentinel-friendly version of `std::search()`. */
template<
typename Iter1,
typename Sentinel1,
typename Iter2,
typename Sentinel2>
search_result<Iter1>
search(Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
{
if (first1 == last1 || first2 == last2)
return {first1, first1};
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)};
}
auto it = first1;
for (;;) {
first1 = parser::detail::text::find(first1, last1, *first2);
if (first1 == last1)
return {first1, first1};
auto it2 = detail::next(first2);
it = first1;
if (++it == last1)
return {it, it};
while (*it == *it2) {
if (++it2 == last2)
return {first1, ++it};
if (++it == last1)
return {it, it};
}
++first1;
}
return {first1, first1};
}
/** Sentinel-friendly version of `std::find_first_of()`. */
template<
typename Iter1,
typename Sentinel1,
typename Iter2,
typename Sentinel2,
typename Pred>
Iter1 find_first_of(
Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2, Pred pred)
{
for (; first1 != last1; ++first1) {
for (auto it = first2; it != last2; ++it) {
if (pred(*first1, *it))
return first1;
}
}
return first1;
}
}}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
namespace std::ranges {
template<typename Iter, typename Sentinel>
inline constexpr bool enable_borrowed_range<
boost::parser::detail::text::foreach_subrange_range<Iter, Sentinel>> = true;
}
#endif
#endif

View File

@@ -1,269 +0,0 @@
// Copyright (C) 2020 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_CONCEPTS_HPP
#define BOOST_PARSER_DETAIL_TEXT_CONCEPTS_HPP
#include <boost/parser/detail/text/config.hpp>
#include <boost/parser/detail/text/utf.hpp>
#include <boost/parser/detail/text/detail/begin_end.hpp>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
#include <ranges>
#include <string_view>
namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 {
//[ concepts_concepts
#ifdef _MSC_VER
inline constexpr format wchar_t_format = format::utf16;
#else
inline constexpr format wchar_t_format = format::utf32;
#endif
template<typename T, format F>
concept code_unit = (std::same_as<T, char8_t> && F == format::utf8) ||
(std::same_as<T, char16_t> && F == format::utf16) ||
(std::same_as<T, char32_t> && F == format::utf32) ||
(std::same_as<T, char> && F == format::utf8) ||
(std::same_as<T, wchar_t> && F == wchar_t_format);
template<typename T>
concept utf8_code_unit = code_unit<T, format::utf8>;
template<typename T>
concept utf16_code_unit = code_unit<T, format::utf16>;
template<typename T>
concept utf32_code_unit = code_unit<T, format::utf32>;
template<typename T, format F>
concept code_unit_iter =
std::input_iterator<T> && code_unit<std::iter_value_t<T>, F>;
template<typename T>
concept utf_code_unit =
utf8_code_unit<T> || utf16_code_unit<T> || utf32_code_unit<T>;
template<typename T, format F>
concept code_unit_pointer =
std::is_pointer_v<T> && code_unit<std::iter_value_t<T>, F>;
template<typename T, format F>
concept code_unit_range = std::ranges::input_range<T> &&
code_unit<std::ranges::range_value_t<T>, F>;
template<typename T, format F>
concept contiguous_code_unit_range = std::ranges::contiguous_range<T> &&
code_unit<std::ranges::range_value_t<T>, F>;
template<typename T>
concept utf8_iter = code_unit_iter<T, format::utf8>;
template<typename T>
concept utf8_pointer = code_unit_pointer<T, format::utf8>;
template<typename T>
concept utf8_range = code_unit_range<T, format::utf8>;
template<typename T>
concept contiguous_utf8_range = contiguous_code_unit_range<T, format::utf8>;
template<typename T>
concept utf16_iter = code_unit_iter<T, format::utf16>;
template<typename T>
concept utf16_pointer = code_unit_pointer<T, format::utf16>;
template<typename T>
concept utf16_range = code_unit_range<T, format::utf16>;
template<typename T>
concept contiguous_utf16_range =
contiguous_code_unit_range<T, format::utf16>;
template<typename T>
concept utf32_iter = code_unit_iter<T, format::utf32>;
template<typename T>
concept utf32_pointer = code_unit_pointer<T, format::utf32>;
template<typename T>
concept utf32_range = code_unit_range<T, format::utf32>;
template<typename T>
concept contiguous_utf32_range =
contiguous_code_unit_range<T, format::utf32>;
template<typename T>
concept code_point = utf32_code_unit<T>;
template<typename T>
concept code_point_iter = utf32_iter<T>;
template<typename T>
concept code_point_range = utf32_range<T>;
template<typename T>
concept utf_iter = utf8_iter<T> || utf16_iter<T> || utf32_iter<T>;
template<typename T>
concept utf_pointer =
utf8_pointer<T> || utf16_pointer<T> || utf32_pointer<T>;
template<typename T>
concept utf_range = utf8_range<T> || utf16_range<T> || utf32_range<T>;
template<typename T>
concept grapheme_iter =
// clang-format off
std::input_iterator<T> &&
code_point_range<std::iter_reference_t<T>> &&
requires(T t) {
{ t.base() } -> code_point_iter;
// clang-format on
};
template<typename T>
concept grapheme_range = std::ranges::input_range<T> &&
grapheme_iter<std::ranges::iterator_t<T>>;
template<typename R>
using code_point_iterator_t = decltype(std::declval<R>().begin().base());
template<typename R>
using code_point_sentinel_t = decltype(std::declval<R>().end().base());
template<typename T, format F>
concept grapheme_iter_code_unit =
// clang-format off
grapheme_iter<T> &&
requires(T t) {
{ t.base().base() } -> code_unit_iter<F>;
// clang-format on
};
template<typename T, format F>
concept grapheme_range_code_unit = grapheme_range<T> &&
grapheme_iter_code_unit<std::ranges::iterator_t<T>, F>;
namespace dtl {
template<typename T, class CodeUnit>
concept eraseable_insertable_sized_bidi_range =
// clang-format off
std::ranges::sized_range<T> &&
std::ranges::input_range<T> &&
requires(T t, CodeUnit const * it) {
{ t.erase(t.begin(), t.end()) } ->
std::same_as<std::ranges::iterator_t<T>>;
{ t.insert(t.end(), it, it) } ->
std::same_as<std::ranges::iterator_t<T>>;
};
// clang-format on
}
template<typename T>
concept utf8_string =
// clang-format off
utf8_code_unit<std::ranges::range_value_t<T>> &&
dtl::eraseable_insertable_sized_bidi_range<
T, std::ranges::range_value_t<T>>;
// clang-format on
template<typename T>
concept utf16_string =
// clang-format off
utf16_code_unit<std::ranges::range_value_t<T>> &&
dtl::eraseable_insertable_sized_bidi_range<
T, std::ranges::range_value_t<T>>;
// clang-format on
template<typename T>
concept utf_string = utf8_string<T> || utf16_string<T>;
template<typename T>
// clang-format off
concept transcoding_error_handler = requires(T t, std::string_view msg) {
{ t(msg) } -> std::same_as<char32_t>;
// clang-format on
};
template<typename T>
// clang-format off
concept utf_range_like =
utf_range<std::remove_reference_t<T>> ||
utf_pointer<std::remove_reference_t<T>>;
// clang-format on
template<typename T>
concept utf8_range_like = utf8_code_unit<std::iter_value_t<T>> ||
utf8_pointer<std::remove_reference_t<T>>;
template<typename T>
concept utf16_range_like = utf16_code_unit<std::iter_value_t<T>> ||
utf16_pointer<std::remove_reference_t<T>>;
template<typename T>
concept utf32_range_like = utf32_code_unit<std::iter_value_t<T>> ||
utf32_pointer<std::remove_reference_t<T>>;
//]
// Clang 13 defines __cpp_lib_concepts but not std::indirectly copyable.
#if defined(__clang_major__) && __clang_major__ == 13
template<typename In, typename Out>
// clang-format off
concept indirectly_copyable =
std::indirectly_readable<In> &&
std::indirectly_writable<Out, std::iter_reference_t<In>>;
// clang-format on
#else
template<typename In, typename Out>
concept indirectly_copyable = std::indirectly_copyable<In, Out>;
#endif
}}}
#endif
namespace boost::parser::detail { namespace text { namespace detail {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<typename T>
using iterator_t = std::ranges::iterator_t<T>;
template<typename T>
using sentinel_t = std::ranges::sentinel_t<T>;
template<typename T>
using iter_value_t = std::iter_value_t<T>;
template<typename T>
using iter_reference_t = std::iter_reference_t<T>;
template<typename T>
using range_value_t = std::ranges::range_value_t<T>;
template<typename T>
using range_reference_t = std::ranges::range_reference_t<T>;
template<typename T>
using range_difference_t = std::ranges::range_difference_t<T>;
#else
template<typename T>
using iterator_t = decltype(detail::begin(std::declval<T &>()));
template<typename T>
using sentinel_t = decltype(detail::end(std::declval<T &>()));
template<typename T>
using iter_value_t = typename std::iterator_traits<T>::value_type;
template<typename T>
using iter_reference_t = decltype(*std::declval<T &>());
template<typename T>
using range_value_t = iter_value_t<iterator_t<T>>;
template<typename T>
using range_reference_t = iter_reference_t<iterator_t<T>>;
template<typename T>
using range_difference_t = std::ptrdiff_t;
template<typename T>
constexpr bool code_unit_v =
#if defined(__cpp_char8_t)
std::is_same_v<T, char8_t> ||
#endif
std::is_same_v<T, char16_t> || std::is_same_v<T, char32_t> ||
std::is_same_v<T, char> || std::is_same_v<T, wchar_t>;
#endif
}}}
#endif

View File

@@ -1,67 +0,0 @@
// Copyright (C) 2020 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_CONFIG_HPP
#define BOOST_PARSER_DETAIL_TEXT_CONFIG_HPP
#include <boost/parser/config.hpp>
// Included for definition of __cpp_lib_concepts.
#include <iterator>
#if !BOOST_PARSER_USE_CONCEPTS
# define BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS 0
#else
# define BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS 1
#endif
// 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__) && \
!defined(_MSC_VER)
#define BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD 1
#else
#define BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD 0
#endif
#if defined(__cpp_lib_ranges)
namespace boost::parser::detail { namespace text { namespace detail {
inline constexpr auto begin = std::ranges::begin;
inline constexpr auto end = std::ranges::end;
}}}
#else
#include <boost/parser/detail/text/detail/begin_end.hpp>
#endif
#if defined(__cpp_lib_ranges)
# define BOOST_PARSER_DETAIL_TEXT_SUBRANGE std::ranges::subrange
#else
# include <boost/parser/subrange.hpp>
# define BOOST_PARSER_DETAIL_TEXT_SUBRANGE boost::parser::subrange
#endif
namespace boost::parser::detail { namespace text {
#if defined(__cpp_char8_t)
using char8_type = char8_t;
#else
using char8_type = char;
#endif
}}
// The inline namespaces v1 and v2 represent pre- and post-C++20. v1 is
// inline for standards before C++20, and v2 is inline for C++20 and later.
// Note that this only applies to code for which a v2 namespace alternative
// exists. Some instances of the v1 namespace may still be inline, if there
// is no v2 version of its contents.
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
# define BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V1 namespace v1
# define BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 inline namespace v2
#else
# define BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V1 inline namespace v1
# define BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 namespace v2
#endif
#endif

View File

@@ -1,917 +0,0 @@
// Copyright (C) 2020 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_ALGORITHM_HPP
#define BOOST_PARSER_DETAIL_TEXT_DETAIL_ALGORITHM_HPP
#include <boost/parser/detail/text/concepts.hpp>
#include <boost/parser/detail/detection.hpp>
#include <boost/parser/detail/text/detail/iterator.hpp>
#include <numeric>
#include <type_traits>
#include <utility>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
#include <ranges>
#endif
#include <cstdint>
namespace boost::parser::detail { namespace text { namespace detail {
template<typename I>
auto prev(I it)
{
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
return std::ranges::prev(it);
#else
return std::prev(it);
#endif
}
template<typename I>
auto next(I it)
{
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
return std::ranges::next(it);
#else
return std::next(it);
#endif
}
template<typename T>
using remove_cv_ref_t =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
// A grapheme_range that has a sentinel type that is not an iterator, but
// that is comparable with T's interator type.
template<typename T>
concept cp_sentinel_gr_rng =
// clang-format off
grapheme_range<T> &&
!grapheme_iter<sentinel_t<T>> &&
requires(iterator_t<T> first, sentinel_t<T> last) {
{ first.base() == last } -> std::convertible_to<bool>;
// clang-format on
};
template<typename T>
using gr_rng_cp_iter_t = decltype(std::declval<iterator_t<T>>().base());
template<typename T>
using gr_rng_cp_sent_t = std::conditional_t<
cp_sentinel_gr_rng<T>,
sentinel_t<T>,
gr_rng_cp_iter_t<T>>;
#else
template<typename T>
using has_base = decltype(std::declval<T>().base());
template<typename T>
using sentinel_comparable_to_iter_base =
decltype(std::declval<T>().begin().base() == std::declval<T>().end());
// A grapheme_range that has a sentinel type that is not an iterator, but
// that is comparable with T's interator type.
template<
typename T,
bool IsIt = is_detected_v<has_base, iterator_t<T>> &&
!is_detected_v<has_base, sentinel_t<T>> &&
is_detected_v<sentinel_comparable_to_iter_base, T>>
constexpr bool is_cp_sentinel_gr_rng_v = false;
template<typename T>
constexpr bool is_cp_sentinel_gr_rng_v<T, true> = true;
template<typename T>
using gr_rng_cp_iter_t =
decltype(detail::begin(std::declval<T &>()).base());
template<typename T>
using gr_rng_cp_sent_t = std::conditional_t<
is_cp_sentinel_gr_rng_v<T>,
sentinel_t<T>,
gr_rng_cp_iter_t<T>>;
#endif
template<typename T>
using has_begin = decltype(*detail::begin(std::declval<T &>()));
template<typename T>
using has_end = decltype(*detail::end(std::declval<T &>()));
template<typename T>
using value_type_ = typename std::remove_cv<
typename std::remove_reference<typename T::value_type>::type>::type;
template<typename T>
using nonpointer_iterator_category_ =
typename T::iterator::iterator_category;
template<typename T>
using iterator_pointer_expr = std::is_pointer<typename T::iterator>;
template<typename T>
using iterator_category_ = typename std::conditional<
detected_or_t<std::false_type, iterator_pointer_expr>::value,
std::random_access_iterator_tag,
detected_t<nonpointer_iterator_category_, T>>::type;
template<typename T, typename U, int N>
constexpr bool
is_convertible_and_n_bytes_v = std::is_convertible<T, U>::value &&
sizeof(T) == N;
template<typename T>
constexpr bool is_char_iter_v =
std::is_same<char *, typename std::remove_cv<T>::type>::value ||
std::is_same<char const *, typename std::remove_cv<T>::type>::value ||
#if defined(__cpp_char8_t)
std::is_same<char8_t *, typename std::remove_cv<T>::type>::value ||
std::is_same<char8_t const *, typename std::remove_cv<T>::type>::
value ||
#endif
is_convertible_and_n_bytes_v<detected_t<value_type_, T>, char, 1>;
// Needed for detected_or_t.
template<typename T>
using is_char_iter = std::integral_constant<bool, is_char_iter_v<T>>;
template<typename T>
constexpr bool is_char_range_v =
(is_convertible_and_n_bytes_v<
remove_cv_ref_t<detected_t<has_begin, T>>,
char,
1> &&
is_convertible_and_n_bytes_v<
remove_cv_ref_t<detected_t<has_end, T>>,
char,
1>);
template<
typename T,
typename R1,
typename Exclude,
bool R1IsCharRange =
is_char_range_v<R1> && !std::is_same<R1, Exclude>::value>
struct rng_alg_ret
{
};
template<typename T, typename R1, typename Exclude>
struct rng_alg_ret<T, R1, Exclude, true>
{
using type = T;
};
template<typename T, typename R1, typename Exclude = void>
using rng_alg_ret_t = typename rng_alg_ret<T, R1, Exclude>::type;
template<
typename T,
typename R1,
typename R2,
bool R1IsCharRange = is_char_range_v<R1>,
bool R2IsCharRange = is_char_range_v<R2>>
struct rngs_alg_ret
{
};
template<typename T, typename R1, typename R2>
struct rngs_alg_ret<T, R1, R2, true, true>
{
using type = T;
};
template<typename T, typename R1, typename R2>
using rngs_alg_ret_t = typename rngs_alg_ret<T, R1, R2>::type;
template<typename T>
using has_contig_begin = decltype(&*detail::begin(std::declval<T &>()));
template<typename T>
using has_contig_end = decltype(&*detail::end(std::declval<T &>()));
template<typename T>
constexpr bool is_contig_char_range_v =
((std::is_same<
fixup_ptr_t<detected_t<has_contig_begin, T>>,
char const *>::value &&
std::is_same<
fixup_ptr_t<detected_t<has_contig_end, T>>,
char const *>::value)
#if defined(__cpp_char8_t)
|| (std::is_same<
fixup_ptr_t<detected_t<has_contig_begin, T>>,
char8_t const *>::value &&
std::is_same<
fixup_ptr_t<detected_t<has_contig_end, T>>,
char8_t const *>::value)
#endif
) &&
std::is_convertible<
iterator_category_<T>,
std::random_access_iterator_tag>::value;
template<
typename T,
typename R1,
bool R1IsContigCharRange = is_contig_char_range_v<R1>>
struct contig_rng_alg_ret
{
};
template<typename T, typename R1>
struct contig_rng_alg_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using contig_rng_alg_ret_t = typename contig_rng_alg_ret<T, R1>::type;
template<
typename T,
typename R1,
typename R2,
bool R1IsContigCharRange = is_contig_char_range_v<R1>,
bool R2IsContigCharRange = is_contig_char_range_v<R2>>
struct contig_rngs_alg_ret
{
};
template<typename T, typename R1, typename R2>
struct contig_rngs_alg_ret<T, R1, R2, true, true>
{
using type = T;
};
template<typename T, typename R1, typename R2>
using contig_rngs_alg_ret_t = typename contig_rngs_alg_ret<T, R1, R2>::type;
template<typename T>
constexpr bool is_char16_range_v =
(is_convertible_and_n_bytes_v<
remove_cv_ref_t<detected_t<has_begin, T>>,
uint16_t,
2> &&
is_convertible_and_n_bytes_v<
remove_cv_ref_t<detected_t<has_end, T>>,
uint16_t,
2>);
template<
typename T,
typename R1,
bool R1IsChar16Range = is_char16_range_v<R1>>
struct rng16_alg_ret
{
};
template<typename T, typename R1>
struct rng16_alg_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using rng16_alg_ret_t = typename rng16_alg_ret<T, R1>::type;
template<typename T, typename R1, bool R1IsCharRange = is_char_iter_v<R1>>
struct char_iter_ret
{
};
template<typename T, typename R1>
struct char_iter_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using char_iter_ret_t = typename char_iter_ret<T, R1>::type;
template<typename T>
constexpr bool is_code_point_v = std::is_integral<T>::value &&
sizeof(T) == 4;
template<typename T>
using has_deref_and_incr =
std::pair<decltype(*std::declval<T>()), decltype(++std::declval<T>())>;
template<typename T>
constexpr bool is_cp_iter_v =
((std::is_pointer<T>::value &&
is_code_point_v<typename std::remove_cv<
typename std::remove_pointer<T>::type>::type>) ||
(is_detected_v<has_deref_and_incr, T> &&
is_code_point_v<
typename std::remove_cv<detected_t<value_type_, T>>::type>));
template<typename T, typename R1, bool R1IsCPRange = is_cp_iter_v<R1>>
struct cp_iter_ret
{
};
template<typename T, typename R1>
struct cp_iter_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using cp_iter_ret_t = typename cp_iter_ret<T, R1>::type;
template<
typename T,
typename R1,
typename R2,
bool R1R2AreCPRanges = is_cp_iter_v<R1> && is_cp_iter_v<R2>>
struct cp_iters_ret
{
};
template<typename T, typename R1, typename R2>
struct cp_iters_ret<T, R1, R2, true>
{
using type = T;
};
template<typename T, typename R1, typename R2>
using cp_iters_ret_t = typename cp_iters_ret<T, R1, R2>::type;
template<typename T>
constexpr bool is_16_code_unit_v = std::is_integral<T>::value &&
sizeof(T) == 2;
template<typename T>
constexpr bool is_16_iter_v =
((std::is_pointer<T>::value &&
is_16_code_unit_v<typename std::remove_cv<
typename std::remove_pointer<T>::type>::type>) ||
(is_detected_v<has_deref_and_incr, T> &&
is_16_code_unit_v<
typename std::remove_cv<detected_t<value_type_, T>>::type>));
template<typename T, typename R1, bool R1IsCPRange = is_16_iter_v<R1>>
struct _16_iter_ret
{
};
template<typename T, typename R1>
struct _16_iter_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using _16_iter_ret_t = typename _16_iter_ret<T, R1>::type;
template<typename T>
constexpr bool is_8_code_unit_v = std::is_integral<T>::value &&
sizeof(T) == 1;
template<typename T>
constexpr bool is_8_iter_v =
((std::is_pointer<T>::value &&
is_8_code_unit_v<typename std::remove_cv<
typename std::remove_pointer<T>::type>::type>) ||
(is_detected_v<has_deref_and_incr, T> &&
is_8_code_unit_v<
typename std::remove_cv<detected_t<value_type_, T>>::type>));
template<typename T, typename R1, bool R1IsCPRange = is_8_iter_v<R1>>
struct _8_iter_ret
{
};
template<typename T, typename R1>
struct _8_iter_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using _8_iter_ret_t = typename _8_iter_ret<T, R1>::type;
template<typename T, typename U>
using comparable_ = decltype(std::declval<T>() == std::declval<U>());
template<
typename T,
typename CPIter,
typename Sentinel,
bool FIsWordPropFunc = is_cp_iter_v<CPIter> &&
is_detected_v<comparable_, CPIter, Sentinel>>
struct cp_iter_sntl_ret
{
};
template<typename T, typename CPIter, typename Sentinel>
struct cp_iter_sntl_ret<T, CPIter, Sentinel, true>
{
using type = T;
};
template<typename T, typename CPIter, typename Sentinel>
using cp_iter_sntl_ret_t =
typename cp_iter_sntl_ret<T, CPIter, Sentinel>::type;
template<typename T, typename R>
using cp_rng_alg_ret_t =
cp_iter_sntl_ret_t<T, iterator_t<R>, sentinel_t<R>>;
template<
typename T,
typename CPIter1,
typename Sentinel1,
typename CPIter2,
typename Sentinel2,
bool AreCPRanges = is_cp_iter_v<CPIter1> && is_cp_iter_v<CPIter2> &&
is_detected_v<comparable_, CPIter1, Sentinel1> &&
is_detected_v<comparable_, CPIter2, Sentinel2>>
struct cp_iters_sntls_ret
{
};
template<
typename T,
typename CPIter1,
typename Sentinel1,
typename CPIter2,
typename Sentinel2>
struct cp_iters_sntls_ret<T, CPIter1, Sentinel1, CPIter2, Sentinel2, true>
{
using type = T;
};
template<
typename T,
typename CPIter1,
typename Sentinel1,
typename CPIter2,
typename Sentinel2>
using cp_iters_sntls_ret_t =
typename cp_iters_sntls_ret<T, CPIter1, Sentinel1, CPIter2, Sentinel2>::
type;
template<typename T, typename R1, typename R2>
using cp_rngs_alg_ret_t = cp_iters_sntls_ret_t<
T,
iterator_t<R1>,
sentinel_t<R1>,
iterator_t<R2>,
sentinel_t<R2>>;
template<int Size, typename T>
constexpr bool is_cu_iter_v =
Size == 1 ? is_char_iter_v<T> : is_16_iter_v<T>;
template<
int Size,
typename T,
typename U,
bool UIsCUIter = is_cu_iter_v<Size, U>>
struct cu_iter_ret
{
};
template<int Size, typename T, typename U>
struct cu_iter_ret<Size, T, U, true>
{
using type = T;
};
template<int Size, typename T, typename U>
using cu_iter_ret_t = typename cu_iter_ret<Size, T, U>::type;
template<int Size, typename T>
constexpr bool is_cu_range_v =
Size == 1 ? is_char_range_v<T> : is_char16_range_v<T>;
template<
int Size,
typename T,
typename U,
typename Exclude,
bool UIsCURange =
is_cu_range_v<Size, U> && !std::is_same<U, Exclude>::value>
struct cu_rng_alg_ret
{
};
template<int Size, typename T, typename U, typename Exclude>
struct cu_rng_alg_ret<Size, T, U, Exclude, true>
{
using type = T;
};
template<int Size, typename T, typename U, typename Exclude = void>
using cu_rng_alg_ret_t = typename cu_rng_alg_ret<Size, T, U, Exclude>::type;
template<typename T>
using is_grapheme_iter_expr = std::integral_constant<
bool,
is_cp_iter_v<
remove_cv_ref_t<decltype(std::declval<const T>().base())>>>;
template<typename T>
using is_grapheme_iter =
detected_or_t<std::false_type, is_grapheme_iter_expr, T>;
template<
typename T,
typename Iter,
bool R1IsGraphemeIter = is_grapheme_iter<Iter>::value>
struct graph_iter_alg_ret
{};
template<typename T, typename Iter>
struct graph_iter_alg_ret<T, Iter, true>
{
using type = T;
};
template<typename T, typename Iter>
using graph_iter_alg_ret_t = typename graph_iter_alg_ret<T, Iter>::type;
template<
typename T,
typename Iter1,
typename Iter2,
bool Iter1Iter2AreGraphemeIter =
is_grapheme_iter<Iter1>::value && is_grapheme_iter<Iter2>::value>
struct graph_iters_alg_ret
{};
template<typename T, typename Iter1, typename Iter2>
struct graph_iters_alg_ret<T, Iter1, Iter2, true>
{
using type = T;
};
template<typename T, typename Iter1, typename Iter2>
using graph_iters_alg_ret_t =
typename graph_iters_alg_ret<T, Iter1, Iter2>::type;
template<typename Size, typename T>
using is_grapheme_cu_iter_expr = std::integral_constant<
bool,
is_cp_iter_v<
remove_cv_ref_t<decltype(std::declval<const T>().base())>> &&
is_cu_iter_v<
Size::value,
remove_cv_ref_t<
decltype(std::declval<const T>().base().base())>>>;
template<int Size, typename T>
using is_grapheme_cu_iter = detected_or_t<
std::false_type,
is_grapheme_cu_iter_expr,
std::integral_constant<int, Size>,
T>;
template<
int Size,
typename T,
typename R1,
bool R1IsGraphemeIter = is_grapheme_cu_iter<Size, R1>::value>
struct graph_iter_cu_alg_ret
{};
template<int Size, typename T, typename R1>
struct graph_iter_cu_alg_ret<Size, T, R1, true>
{
using type = T;
};
template<int Size, typename T, typename R1>
using graph_iter_alg_cu_ret_t =
typename graph_iter_cu_alg_ret<Size, T, R1>::type;
template<typename T>
using is_grapheme_range_expr = std::integral_constant<
bool,
is_cp_iter_v<remove_cv_ref_t<
decltype(std::declval<const T>().begin().base())>> &&
is_cp_iter_v<remove_cv_ref_t<
decltype(std::declval<const T>().end().base())>> &&
void_<
decltype(std::declval<const T>().begin().base().base()),
decltype(std::declval<const T>().end().base().base())>::value>;
template<typename T>
using is_grapheme_range =
detected_or_t<std::false_type, is_grapheme_range_expr, T>;
template<
typename T,
typename R1,
bool R1IsGraphemeRange = is_grapheme_range<R1>::value>
struct graph_rng_alg_ret
{};
template<typename T, typename R1>
struct graph_rng_alg_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using graph_rng_alg_ret_t = typename graph_rng_alg_ret<T, R1>::type;
template<typename T>
using is_cp_grapheme_range_expr = std::integral_constant<
bool,
is_cp_iter_v<remove_cv_ref_t<
decltype(std::declval<const T>().begin().base())>> &&
is_cp_iter_v<remove_cv_ref_t<
decltype(std::declval<const T>().end().base())>>>;
template<typename T>
using is_cp_grapheme_range =
detected_or_t<std::false_type, is_cp_grapheme_range_expr, T>;
template<
typename T,
typename R1,
bool R1IsGraphemeRange = is_grapheme_range<R1>::value>
struct cp_graph_rng_alg_ret
{};
template<typename T, typename R1>
struct cp_graph_rng_alg_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using cp_graph_rng_alg_ret_t = typename cp_graph_rng_alg_ret<T, R1>::type;
template<
typename T,
typename R1,
typename R2,
bool R1R2AreGraphemeRanges =
is_cp_grapheme_range<R1>::value && is_cp_grapheme_range<R2>::value>
struct graph_rngs_alg_ret
{};
template<typename T, typename R1, typename R2>
struct graph_rngs_alg_ret<T, R1, R2, true>
{
using type = T;
};
template<typename T, typename R1, typename R2>
using graph_rngs_alg_ret_t = typename graph_rngs_alg_ret<T, R1, R2>::type;
template<
typename T,
typename R1,
typename R2,
bool R1IsGraphemeRangeButNotR2 =
is_cp_grapheme_range<R1>::value && !is_cp_grapheme_range<R2>::value>
struct lazy_graph_rng_and_non_alg_ret
{};
template<typename T, typename R1, typename R2>
struct lazy_graph_rng_and_non_alg_ret<T, R1, R2, true>
{
using type = typename T::type;
};
template<typename T, typename R1, typename R2>
using lazy_graph_rng_and_non_alg_ret_t =
typename lazy_graph_rng_and_non_alg_ret<T, R1, R2>::type;
template<
typename T,
typename R1,
typename R2,
bool R1IsGraphemeRangeButNotR2 =
is_cp_grapheme_range<R1>::value && !is_cp_grapheme_range<R2>::value>
struct graph_rng_and_non_alg_ret
{};
template<typename T, typename R1, typename R2>
struct graph_rng_and_non_alg_ret<T, R1, R2, true>
{
using type = T;
};
template<typename T, typename R1, typename R2>
using graph_rng_and_non_alg_ret_t =
typename graph_rng_and_non_alg_ret<T, R1, R2>::type;
template<
typename T,
typename R1,
typename R2,
bool R1R2AreNotGraphemeRanges = !is_cp_grapheme_range<R1>::value &&
!is_cp_grapheme_range<R2>::value>
struct non_graph_rngs_alg_ret
{};
template<typename T, typename R1, typename R2>
struct non_graph_rngs_alg_ret<T, R1, R2, true>
{
using type = T;
};
template<typename T, typename R1, typename R2>
using non_graph_rngs_alg_ret_t =
typename non_graph_rngs_alg_ret<T, R1, R2>::type;
template<
typename T,
typename R1,
typename R2,
bool R1R2AreNotGraphemeRanges = !is_cp_grapheme_range<R1>::value &&
!is_cp_grapheme_range<R2>::value>
struct lazy_non_graph_rngs_alg_ret
{};
template<typename T, typename R1, typename R2>
struct lazy_non_graph_rngs_alg_ret<T, R1, R2, true>
{
using type = typename T::type;
};
template<typename T, typename R1, typename R2>
using lazy_non_graph_rngs_alg_ret_t =
typename lazy_non_graph_rngs_alg_ret<T, R1, R2>::type;
template<typename T>
using is_contig_grapheme_range_expr = std::integral_constant<
bool,
(std::is_same<
decltype(std::declval<const T>().begin().base().base()),
char const *>::value ||
std::is_same<
decltype(std::declval<const T>().begin().base().base()),
char *>::value) &&
(std::is_same<
decltype(std::declval<const T>().end().base().base()),
char const *>::value ||
std::is_same<
decltype(std::declval<const T>().end().base().base()),
char *>::value)>;
template<typename T>
using is_contig_grapheme_range =
detected_or_t<std::false_type, is_contig_grapheme_range_expr, T>;
template<
typename T,
typename R1,
bool R1IsContigGraphemeRange = is_contig_grapheme_range<R1>::value>
struct contig_graph_rng_alg_ret
{
};
template<typename T, typename R1>
struct contig_graph_rng_alg_ret<T, R1, true>
{
using type = T;
};
template<typename T, typename R1>
using contig_graph_rng_alg_ret_t =
typename contig_graph_rng_alg_ret<T, R1>::type;
inline std::size_t hash_combine_(std::size_t seed, std::size_t value)
{
return seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
template<int N>
struct hash_4_more_chars
{
template<typename Iter>
static std::size_t call(std::size_t curr, Iter it)
{
return curr;
}
};
template<>
struct hash_4_more_chars<8>
{
template<typename Iter>
static std::size_t call(std::size_t curr, Iter it)
{
curr <<= 32;
curr += (*(it + 4) << 24) + (*(it + 5) << 16) + (*(it + 2) << 6) +
(*(it + 7) << 0);
return curr;
}
};
template<typename CharRange>
std::size_t hash_char_range(CharRange const & r)
{
auto first = r.begin();
auto last = r.end();
auto const size = last - first;
auto const remainder = size % sizeof(std::size_t);
last -= remainder;
std::size_t retval = size;
for (; first != last; first += sizeof(std::size_t)) {
std::size_t curr = (*(first + 0) << 24) + (*(first + 1) << 16) +
(*(first + 2) << 8) + (*(first + 3) << 0);
curr = hash_4_more_chars<sizeof(std::size_t)>::call(curr, first);
retval = detail::hash_combine_(retval, curr);
}
first = last;
last += remainder;
for (; first != last; ++first) {
retval = detail::hash_combine_(retval, *first);
}
return retval;
}
template<typename GraphemeRange>
std::size_t hash_grapheme_range(GraphemeRange const & r)
{
std::size_t cps = 0;
std::size_t retval = std::accumulate(
r.begin().base(),
r.end().base(),
std::size_t(0),
[&cps](std::size_t seed, std::size_t value) {
++cps;
return detail::hash_combine_(seed, value);
});
return detail::hash_combine_(retval, cps);
}
template<typename Iter>
using char_value_expr = std::integral_constant<
bool,
std::is_integral<
typename std::iterator_traits<Iter>::value_type>::value &&
sizeof(typename std::iterator_traits<Iter>::value_type) == 1>;
template<typename Iter>
constexpr bool is_char_ptr_v = std::is_pointer<Iter>::value &&
detected_or_t<std::false_type, char_value_expr, Iter>::value;
template<typename Iter>
using _16_value_expr = std::integral_constant<
bool,
std::is_integral<
typename std::iterator_traits<Iter>::value_type>::value &&
sizeof(typename std::iterator_traits<Iter>::value_type) == 2>;
template<typename Iter>
constexpr bool is_16_ptr_v = std::is_pointer<Iter>::value &&
detected_or_t<std::false_type, _16_value_expr, Iter>::value;
template<typename Iter>
using cp_value_expr = std::integral_constant<
bool,
std::is_integral<
typename std::iterator_traits<Iter>::value_type>::value &&
sizeof(typename std::iterator_traits<Iter>::value_type) == 4>;
template<typename Iter>
constexpr bool is_cp_ptr_v = std::is_pointer<Iter>::value &&
detected_or_t<std::false_type, cp_value_expr, Iter>::value;
}}}
#endif

View File

@@ -1,144 +0,0 @@
// 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
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

View File

@@ -1,154 +0,0 @@
// Copyright (C) 2022 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_BEGIN_END_HPP
#define BOOST_PARSER_DETAIL_TEXT_BEGIN_END_HPP
#include <boost/parser/detail/detection.hpp>
#include <initializer_list>
namespace boost::parser::detail { namespace text { namespace detail {
template<typename T>
T decay_copy(T) noexcept;
template<typename T>
struct static_const
{
static constexpr T value{};
};
template<typename T>
constexpr T static_const<T>::value;
namespace begin_impl {
template<typename T>
void begin(T &&) = delete;
template<typename T>
void begin(std::initializer_list<T>) = delete;
template<typename T>
using member_begin_expr = decltype(std::declval<T &>().begin());
template<typename T>
using adl_begin_expr = decltype(begin(std::declval<T &>()));
template<typename T>
constexpr bool has_member_begin_v = is_detected_v<member_begin_expr, T>;
template<typename T>
constexpr bool has_adl_begin_v = is_detected_v<adl_begin_expr, T>;
template<typename R>
using member_return_t =
decltype(detail::decay_copy(std::declval<R &>().begin()));
template<typename R>
using adl_return_t =
decltype(detail::decay_copy(begin(std::declval<R &>)));
struct impl
{
template<typename R, std::size_t N>
void operator()(R (&&)[N]) const = delete;
template<typename R, std::size_t N>
constexpr R * operator()(R (&array)[N]) const
{
return array;
}
template<typename R>
constexpr std::
enable_if_t<has_member_begin_v<R>, member_return_t<R>>
operator()(R && r) const
{
return r.begin();
}
template<typename R>
constexpr std::enable_if_t<
!has_member_begin_v<R> && has_adl_begin_v<R>,
adl_return_t<R>>
operator()(R && r) const
{
return begin(r);
}
};
}
#if 201703L <= __cplusplus
namespace _ {
inline constexpr begin_impl::impl begin;
}
using namespace _;
#else
namespace {
constexpr auto & begin = static_const<begin_impl::impl>::value;
}
#endif
namespace end_impl {
template<typename T>
void end(T &&) = delete;
template<typename T>
void end(std::initializer_list<T>) = delete;
template<typename T>
using member_end_expr = decltype(std::declval<T &>().end());
template<typename T>
using adl_end_expr = decltype(end(std::declval<T &>()));
template<typename T>
constexpr bool has_member_end_v = is_detected_v<member_end_expr, T>;
template<typename T>
constexpr bool has_adl_end_v = is_detected_v<adl_end_expr, T>;
template<typename R>
using member_return_t =
decltype(detail::decay_copy(std::declval<R &>().end()));
template<typename R>
using adl_return_t =
decltype(detail::decay_copy(end(std::declval<R &>)));
struct impl
{
template<typename R, std::size_t N>
void operator()(R (&&)[N]) const = delete;
template<typename R, std::size_t N>
constexpr R * operator()(R (&array)[N]) const
{
return array + N;
}
template<typename R>
constexpr std::enable_if_t<has_member_end_v<R>, member_return_t<R>>
operator()(R && r) const
{
return r.end();
}
template<typename R>
constexpr std::enable_if_t<
!has_member_end_v<R> && has_adl_end_v<R>,
adl_return_t<R>>
operator()(R && r) const
{
return end(r);
}
};
}
#if 201703L <= __cplusplus
namespace _ {
inline constexpr end_impl::impl end;
}
using namespace _;
#else
namespace {
constexpr auto & end = static_const<end_impl::impl>::value;
}
#endif
}}}
#endif

View File

@@ -1,24 +0,0 @@
// Copyright (C) 2020 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_ITERATOR_HPP
#define BOOST_PARSER_DETAIL_TEXT_DETAIL_ITERATOR_HPP
#include <boost/parser/detail/text/config.hpp>
#include <boost/parser/detail/stl_interfaces/reverse_iterator.hpp>
#include <iterator>
namespace boost::parser::detail { namespace text { namespace detail {
using reverse_char_iterator =
parser::detail::stl_interfaces::reverse_iterator<char *>;
using const_reverse_char_iterator =
parser::detail::stl_interfaces::reverse_iterator<char const *>;
}}}
#endif

View File

@@ -1,19 +0,0 @@
// Copyright (C) 2020 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_SENTINEL_TAG_HPP
#define BOOST_PARSER_DETAIL_TEXT_DETAIL_SENTINEL_TAG_HPP
#include <boost/parser/detail/text/config.hpp>
namespace boost::parser::detail { namespace text { namespace detail {
struct sentinel_tag
{};
struct non_sentinel_tag
{};
}}}
#endif

View File

@@ -1,47 +0,0 @@
// Copyright (C) 2020 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_IN_OUT_RESULT_HPP
#define BOOST_PARSER_DETAIL_TEXT_IN_OUT_RESULT_HPP
#include <boost/parser/detail/text/config.hpp>
namespace boost::parser::detail { namespace text {
/** A replacement for C++20's `std::ranges::in_out_result` for use in
pre-C++20 build modes. */
template<typename I, typename O>
struct in_out_result
{
[[no_unique_address]] I in;
[[no_unique_address]] O out;
};
}}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
#include <ranges>
namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 {
namespace dtl {
template<typename R>
std::ranges::borrowed_iterator_t<R> result_iterator(R &&);
template<typename Ptr>
requires std::is_pointer_v<std::remove_reference_t<Ptr>>
Ptr result_iterator(Ptr &&);
template<typename T>
using uc_result_iterator =
decltype(dtl::result_iterator(std::declval<T>()));
}
}}}
#endif
#endif

View File

@@ -1,800 +0,0 @@
// Copyright (C) 2018 Robert N. Steagall
// Copyright (C) 2019 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_TRANSCODE_ALGORITHM_HPP
#define BOOST_PARSER_DETAIL_TEXT_TRANSCODE_ALGORITHM_HPP
#include <boost/parser/detail/text/in_out_result.hpp>
#include <boost/parser/detail/text/transcode_iterator.hpp>
#include <boost/parser/detail/text/unpack.hpp>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
#include <algorithm>
#endif
#include <boost/parser/config.hpp>
namespace boost::parser::detail { namespace text {
template<typename Range>
struct utf_range_like_iterator
{
using type = decltype(std::declval<Range>().begin());
};
template<typename T>
struct utf_range_like_iterator<T *>
{
using type = T *;
};
template<std::size_t N, typename T>
struct utf_range_like_iterator<T[N]>
{
using type = T *;
};
template<std::size_t N, typename T>
struct utf_range_like_iterator<T (&)[N]>
{
using type = T *;
};
template<typename Range>
using utf_range_like_iterator_t =
typename utf_range_like_iterator<Range>::type;
/** An alias for `in_out_result` returned by algorithms that perform a
transcoding copy. */
template<typename Iter, typename OutIter>
using transcode_result = in_out_result<Iter, OutIter>;
namespace detail {
template<typename OutIter>
constexpr OutIter read_into_utf8_iter(uint32_t cp, OutIter out)
{
if (cp < 0x80) {
*out = static_cast<char>(cp);
++out;
} else if (cp < 0x800) {
*out = static_cast<char>(0xC0 + (cp >> 6));
++out;
*out = static_cast<char>(0x80 + (cp & 0x3f));
++out;
} else if (cp < 0x10000) {
*out = static_cast<char>(0xe0 + (cp >> 12));
++out;
*out = static_cast<char>(0x80 + ((cp >> 6) & 0x3f));
++out;
*out = static_cast<char>(0x80 + (cp & 0x3f));
++out;
} else {
*out = static_cast<char>(0xf0 + (cp >> 18));
++out;
*out = static_cast<char>(0x80 + ((cp >> 12) & 0x3f));
++out;
*out = static_cast<char>(0x80 + ((cp >> 6) & 0x3f));
++out;
*out = static_cast<char>(0x80 + (cp & 0x3f));
++out;
}
return out;
}
template<typename OutIter>
constexpr OutIter read_into_utf16_iter(uint32_t cp, OutIter out)
{
uint16_t const high_surrogate_base = 0xd7c0;
uint16_t const low_surrogate_base = 0xdc00;
if (cp < 0x10000) {
*out = static_cast<uint16_t>(cp);
++out;
} else {
*out = static_cast<uint16_t>(cp >> 10) + high_surrogate_base;
++out;
*out = static_cast<uint16_t>(cp & 0x3ff) + low_surrogate_base;
++out;
}
return out;
}
template<
bool UseN,
typename InputIter,
typename Sentinel,
typename OutIter>
transcode_result<InputIter, OutIter> transcode_utf_8_to_16(
InputIter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out,
std::input_iterator_tag)
{
for (; first != last && (!UseN || n); --n) {
unsigned char const c = *first;
if (c < 0x80) {
*out = *first;
++first;
++out;
} else {
auto const cp = detail::advance(first, last);
out = detail::read_into_utf16_iter(cp, out);
}
}
return {first, out};
}
template<bool UseN, typename Iter, typename OutIter>
transcode_result<Iter, OutIter> transcode_utf_8_to_16(
Iter first,
Iter last,
std::ptrdiff_t n,
OutIter out,
std::random_access_iterator_tag)
{
return transcode_utf_8_to_16<UseN>(
first, last, n, out, std::input_iterator_tag{});
}
template<
bool UseN,
typename InputIter,
typename Sentinel,
typename OutIter>
transcode_result<InputIter, OutIter> transcode_utf_8_to_32(
InputIter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out,
std::input_iterator_tag)
{
for (; first != last && (!UseN || n); --n) {
unsigned char const c = *first;
if (c < 0x80) {
*out = *first;
++first;
++out;
} else {
*out = detail::advance(first, last);
++out;
}
}
return {first, out};
}
template<bool UseN, typename Iter, typename OutIter>
transcode_result<Iter, OutIter> transcode_utf_8_to_32(
Iter first,
Iter last,
std::ptrdiff_t n,
OutIter out,
std::random_access_iterator_tag)
{
return transcode_utf_8_to_32<UseN>(
first, last, n, out, std::input_iterator_tag{});
}
template<format Tag>
struct tag_t
{};
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_8(
tag_t<format::utf8>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
for (; first != last && (!UseN || n); ++first, ++out) {
*out = *first;
--n;
}
return {first, out};
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_16(
tag_t<format::utf8>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
return detail::transcode_utf_8_to_16<UseN>(
first,
last,
n,
out,
typename std::iterator_traits<Iter>::iterator_category{});
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_32(
tag_t<format::utf8>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
return detail::transcode_utf_8_to_32<UseN>(
first,
last,
n,
out,
typename std::iterator_traits<Iter>::iterator_category{});
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_8(
tag_t<format::utf16>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
uint32_t const high_surrogate_max = 0xdbff;
uint16_t const high_surrogate_base = 0xd7c0;
uint16_t const low_surrogate_base = 0xdc00;
for (; first != last && (!UseN || n); ++first, --n) {
uint32_t const hi = *first;
if (surrogate(hi)) {
if (hi <= high_surrogate_max) {
++first;
if (first == last) {
uint32_t const cp = replacement_character;
out = detail::read_into_utf8_iter(cp, out);
++out;
return {first, out};
}
uint32_t const lo = *first;
if (low_surrogate(lo)) {
uint32_t const cp =
((hi - high_surrogate_base) << 10) +
(lo - low_surrogate_base);
out = detail::read_into_utf8_iter(cp, out);
continue;
}
}
out = detail::read_into_utf8_iter(
replacement_character, out);
} else {
out = detail::read_into_utf8_iter(hi, out);
}
}
return {first, out};
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_16(
tag_t<format::utf16>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
for (; first != last && (!UseN || n); ++first, ++out, --n) {
*out = *first;
}
return {first, out};
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_32(
tag_t<format::utf16>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
uint32_t const high_surrogate_max = 0xdbff;
uint16_t const high_surrogate_base = 0xd7c0;
uint16_t const low_surrogate_base = 0xdc00;
for (; first != last && (!UseN || n); ++first, --n) {
uint32_t const hi = *first;
if (surrogate(hi)) {
if (hi <= high_surrogate_max) {
++first;
if (first == last) {
*out = replacement_character;
++out;
return {first, out};
}
uint32_t const lo = *first;
if (low_surrogate(lo)) {
uint32_t const cp =
((hi - high_surrogate_base) << 10) +
(lo - low_surrogate_base);
*out = cp;
++out;
continue;
}
}
*out = replacement_character;
++out;
} else {
*out = hi;
++out;
}
}
return {first, out};
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_8(
tag_t<format::utf32>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
for (; first != last && (!UseN || n); ++first, --n) {
out = detail::read_into_utf8_iter(*first, out);
}
return {first, out};
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_16(
tag_t<format::utf32>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
for (; first != last && (!UseN || n); ++first, --n) {
out = detail::read_into_utf16_iter(*first, out);
}
return {first, out};
}
template<bool UseN, typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_32(
tag_t<format::utf32>,
Iter first,
Sentinel last,
std::ptrdiff_t n,
OutIter out)
{
for (; first != last && (!UseN || n); ++first, ++out, --n) {
*out = *first;
}
return {first, out};
}
}
#if 0
/** Copies the code points in the range [first, last) to out, changing the
encoding from UTF-8 to UTF-32. */
template<typename InputIter, typename Sentinel, typename OutIter>
transcode_result<InputIter, OutIter> transcode_utf_8_to_32_take_n(
InputIter first, Sentinel last, std::ptrdiff_t n, OutIter out)
{
auto const r = detail::unpack_iterator_and_sentinel(first, last);
return detail::transcode_to_32<true>(
detail::tag_t<r.format_tag>{}, r.first, r.last, n, out);
}
/** Copies the first `n` code points in the range [first, last) to out,
changing the encoding from UTF-8 to UTF-32. */
template<typename InputIter, typename Sentinel, typename OutIter>
transcode_result<InputIter, OutIter> transcode_utf_8_to_32_take_n(
InputIter first, Sentinel last, std::ptrdiff_t n, OutIter out)
{
auto const r = detail::unpack_iterator_and_sentinel(first, last);
return detail::transcode_to_32<true>(
detail::tag_t<r.format_tag>{}, r.first, r.last, n, out);
}
/** Copies the first `n` code points in the range [first, last) to out,
changing the encoding from UTF-8 to UTF-32. */
template<typename InputIter, typename Sentinel, typename OutIter>
transcode_result<InputIter, OutIter>
transcode_utf_8_to_32_take_n(Range && r, std::ptrdiff_t n, OutIter out)
{
return detail::transcode_utf_8_to_32_dispatch<true, Range, OutIter>::
call(r, n, out)
.out;
}
#endif
}}
namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V1 {
#if defined(BOOST_TEXT_DOXYGEN)
// -> utf8
/** Copies the code points in the range `[first, last)` to `out`, changing
the encoding to UTF-8. */
template<
std::input_iterator I,
std::sentinel_for<I> S,
std::output_iterator<uint8_t> O>
requires(
utf16_code_unit<std::iter_value_t<I>> ||
utf32_code_unit<std::iter_value_t<I>>)
transcode_result<I, O> transcode_to_utf8(I first, S last, O out);
/** Copies the code points in the range `[p, null_sentinel)` to `out`,
changing the encoding to UTF-8. */
template<typename Ptr, std::output_iterator<uint8_t> O>
requires(utf16_pointer<Ptr> || utf32_pointer<Ptr>)
transcode_result<Ptr, O> transcode_to_utf8(Ptr p, O out);
/** Copies the code points in the array `arr` to `out`, changing the
encoding to UTF-8. */
template<std::size_t N, typename Char, std::output_iterator<uint8_t> O>
requires (utf16_code_unit<Char> || utf32_code_unit<Char>)
transcode_result<Char *, O> transcode_to_utf8(Char (&arr)[N], O out);
/** Copies the code points in the range `r` to `out`, changing the
encoding to UTF-8. */
template<std::ranges::input_range R, std::output_iterator<uint8_t> O>
requires (utf16_code_unit<std::ranges::range_value_t<R>> ||
utf32_code_unit<std::ranges::range_value_t<R>>)
transcode_result<std::ranges::borrowed_iterator_t<R>, O>
transcode_to_utf8(R && r, O out);
// -> utf16
/** Copies the code points in the range `[first, last)` to `out`, changing
the encoding to UTF-16. */
template<
std::input_iterator I,
std::sentinel_for<I> S,
std::output_iterator<char16_t> O>
requires (utf8_code_unit<std::iter_value_t<I>> ||
utf32_code_unit<std::iter_value_t<I>>)
transcode_result<I, O> transcode_to_utf16(I first, S last, O out);
/** Copies the code points in the range `[p, null_sentinel)` to `out`,
changing the encoding to UTF-16. */
template<typename Ptr, std::output_iterator<char16_t> O>
requires (utf8_pointer<Ptr> || utf32_pointer<Ptr>)
transcode_result<Ptr, O> transcode_to_utf16(Ptr p, O out);
/** Copies the code points in the array `arr` to `out`, changing the
encoding to UTF-16. */
template<std::size_t N, typename Char, std::output_iterator<char16_t> O>
requires (utf8_code_unit<Char> || utf32_code_unit<Char>)
transcode_result<Char *, O> transcode_to_utf16(Char (&arr)[N], O out);
/** Copies the code points in the range `r` to `out`, changing the
encoding to UTF-16. */
template<std::ranges::input_range R, std::output_iterator<cjar16_t> O>
requires (utf8_code_unit<std::ranges::range_value_t<R>> ||
utf32_code_unit<std::ranges::range_value_t<R>>)
transcode_result<std::ranges::borrowed_iterator_t<R>, O>
transcode_to_utf16(R && r, O out);
// -> utf32
/** Copies the code points in the range `[first, last)` to `out`, changing
the encoding to UTF-32. */
template<
std::input_iterator I,
std::sentinel_for<I> S,
std::output_iterator<uint32_t> O>
requires (utf8_code_unit<std::iter_value_t<I>> ||
utf16_code_unit<std::iter_value_t<I>>)
transcode_result<I, O> transcode_to_utf32(I first, S last, O out);
/** Copies the code points in the range `[p, null_sentinel)` to `out`,
changing the encoding to UTF-32. */
template<typename Ptr, std::output_iterator<uint32_t> O>
requires (utf8_pointer<Ptr> || utf16_pointer<Ptr>)
transcode_result<Ptr, O> transcode_to_utf32(Ptr p, O out);
/** Copies the code points in the array `arr` to `out`, changing the
encoding to UTF-32. */
template<std::size_t N, typename Char, std::output_iterator<uint32_t> O>
requires (utf8_code_unit<Char> || utf16_code_unit<Char>)
transcode_result<Char *, O> transcode_to_utf32(Char (&arr)[N], O out);
/** Copies the code points in the range `r` to `out`, changing the
encoding to UTF-32. */
template<std::ranges::input_range R, std::output_iterator<uint32_t> O>
requires (utf8_code_unit<std::ranges::range_value_t<R>> ||
utf16_code_unit<std::ranges::range_value_t<R>>)
transcode_result<std::ranges::borrowed_iterator_t<R>, O>
transcode_to_utf32(R && r, O out);
#endif
namespace dtl {
template<
bool UseN,
typename Range,
typename OutIter,
bool _16Ptr = detail::is_16_ptr_v<Range>,
bool CPPtr = detail::is_cp_ptr_v<Range>>
struct transcode_to_8_dispatch
{
static constexpr auto
call(Range && r, std::ptrdiff_t n, OutIter out)
-> transcode_result<decltype(detail::begin(r)), OutIter>
{
auto const u = text::unpack_iterator_and_sentinel(
detail::begin(r), detail::end(r));
auto unpacked = detail::transcode_to_8<UseN>(
detail::tag_t<u.format_tag>{}, u.first, u.last, n, out);
return {u.repack(unpacked.in), unpacked.out};
}
};
template<bool UseN, typename Ptr, typename OutIter>
struct transcode_to_8_dispatch<UseN, Ptr, OutIter, true, false>
{
static constexpr auto
call(Ptr p, std::ptrdiff_t n, OutIter out)
{
return detail::transcode_to_8<UseN>(
detail::tag_t<format::utf16>{}, p, null_sentinel, n, out);
}
};
template<bool UseN, typename Ptr, typename OutIter>
struct transcode_to_8_dispatch<UseN, Ptr, OutIter, false, true>
{
static constexpr auto
call(Ptr p, std::ptrdiff_t n, OutIter out)
{
return detail::transcode_to_8<UseN>(
detail::tag_t<format::utf32>{}, p, null_sentinel, n, out);
}
};
template<
bool UseN,
typename Range,
typename OutIter,
bool CharPtr = detail::is_char_ptr_v<Range>,
bool CPPtr = detail::is_cp_ptr_v<Range>>
struct transcode_to_16_dispatch
{
static constexpr auto
call(Range && r, std::ptrdiff_t n, OutIter out)
-> transcode_result<decltype(detail::begin(r)), OutIter>
{
auto const u = text::unpack_iterator_and_sentinel(
detail::begin(r), detail::end(r));
auto unpacked = detail::transcode_to_16<UseN>(
detail::tag_t<u.format_tag>{}, u.first, u.last, n, out);
return {u.repack(unpacked.in), unpacked.out};
}
};
template<bool UseN, typename Ptr, typename OutIter>
struct transcode_to_16_dispatch<UseN, Ptr, OutIter, true, false>
{
static constexpr auto
call(Ptr p, std::ptrdiff_t n, OutIter out)
{
return detail::transcode_to_16<UseN>(
detail::tag_t<format::utf8>{}, p, null_sentinel, n, out);
}
};
template<bool UseN, typename Ptr, typename OutIter>
struct transcode_to_16_dispatch<UseN, Ptr, OutIter, false, true>
{
static constexpr auto
call(Ptr p, std::ptrdiff_t n, OutIter out)
{
return detail::transcode_to_16<UseN>(
detail::tag_t<format::utf32>{}, p, null_sentinel, n, out);
}
};
template<
bool UseN,
typename Range,
typename OutIter,
bool CharPtr = detail::is_char_ptr_v<Range>,
bool _16Ptr = detail::is_16_ptr_v<Range>>
struct transcode_to_32_dispatch
{
static constexpr auto
call(Range && r, std::ptrdiff_t n, OutIter out)
-> transcode_result<decltype(detail::begin(r)), OutIter>
{
auto const u = text::unpack_iterator_and_sentinel(
detail::begin(r), detail::end(r));
auto unpacked = detail::transcode_to_32<UseN>(
detail::tag_t<u.format_tag>{}, u.first, u.last, n, out);
return {u.repack(unpacked.in), unpacked.out};
}
};
template<bool UseN, typename Ptr, typename OutIter>
struct transcode_to_32_dispatch<UseN, Ptr, OutIter, true, false>
{
static constexpr auto
call(Ptr p, std::ptrdiff_t n, OutIter out)
{
return detail::transcode_to_32<UseN>(
detail::tag_t<format::utf8>{}, p, null_sentinel, n, out);
}
};
template<bool UseN, typename Ptr, typename OutIter>
struct transcode_to_32_dispatch<UseN, Ptr, OutIter, false, true>
{
static constexpr auto
call(Ptr p, std::ptrdiff_t n, OutIter out)
{
return detail::transcode_to_32<UseN>(
detail::tag_t<format::utf16>{}, p, null_sentinel, n, out);
}
};
}
template<typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_utf8(
Iter first, Sentinel last, OutIter out)
{
auto const r = text::unpack_iterator_and_sentinel(first, last);
auto unpacked = detail::transcode_to_8<false>(
detail::tag_t<r.format_tag>{}, r.first, r.last, -1, out);
return {r.repack(unpacked.in), unpacked.out};
}
template<typename Range, typename OutIter>
transcode_result<utf_range_like_iterator_t<Range>, OutIter>
transcode_to_utf8(Range && r, OutIter out)
{
return dtl::transcode_to_8_dispatch<false, Range, OutIter>::call(
r, -1, out);
}
template<typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_utf16(
Iter first, Sentinel last, OutIter out)
{
auto const r = text::unpack_iterator_and_sentinel(first, last);
auto unpacked = detail::transcode_to_16<false>(
detail::tag_t<r.format_tag>{}, r.first, r.last, -1, out);
return {r.repack(unpacked.in), unpacked.out};
}
template<typename Range, typename OutIter>
transcode_result<utf_range_like_iterator_t<Range>, OutIter>
transcode_to_utf16(Range && r, OutIter out)
{
return dtl::transcode_to_16_dispatch<false, Range, OutIter>::call(
r, -1, out);
}
template<typename Iter, typename Sentinel, typename OutIter>
transcode_result<Iter, OutIter> transcode_to_utf32(
Iter first, Sentinel last, OutIter out)
{
auto const r = text::unpack_iterator_and_sentinel(first, last);
auto unpacked = detail::transcode_to_32<false>(
detail::tag_t<r.format_tag>{}, r.first, r.last, -1, out);
return {r.repack(unpacked.in), unpacked.out};
}
template<typename Range, typename OutIter>
transcode_result<utf_range_like_iterator_t<Range>, OutIter>
transcode_to_utf32(Range && r, OutIter out)
{
return dtl::transcode_to_32_dispatch<false, Range, OutIter>::call(
r, -1, out);
}
}}}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
namespace boost::parser::detail { namespace text { BOOST_PARSER_DETAIL_TEXT_NAMESPACE_V2 {
// -> utf8
template<
std::input_iterator I,
std::sentinel_for<I> S,
std::output_iterator<uint8_t> O>
requires(
utf16_code_unit<std::iter_value_t<I>> ||
utf32_code_unit<std::iter_value_t<I>>)
transcode_result<I, O> transcode_to_utf8(I first, S last, O out)
{
auto const r = text::unpack_iterator_and_sentinel(first, last);
auto unpacked = detail::transcode_to_8<false>(
detail::tag_t<r.format_tag>{}, r.first, r.last, -1, out);
return {r.repack(unpacked.in), unpacked.out};
}
template<typename R, std::output_iterator<uint32_t> O>
requires(utf16_range_like<R> || utf32_range_like<R>)
transcode_result<dtl::uc_result_iterator<R>, O> transcode_to_utf8(
R && r, O out)
{
if constexpr (std::is_pointer_v<std::remove_reference_t<R>>) {
return text::transcode_to_utf8(r, null_sentinel, out);
} else {
return text::transcode_to_utf8(
std::ranges::begin(r), std::ranges::end(r), out);
}
}
// -> utf16
template<
std::input_iterator I,
std::sentinel_for<I> S,
std::output_iterator<char16_t> O>
requires(
utf8_code_unit<std::iter_value_t<I>> ||
utf32_code_unit<std::iter_value_t<I>>)
transcode_result<I, O> transcode_to_utf16(I first, S last, O out)
{
auto const r = text::unpack_iterator_and_sentinel(first, last);
auto unpacked = detail::transcode_to_16<false>(
detail::tag_t<r.format_tag>{}, r.first, r.last, -1, out);
return {r.repack(unpacked.in), unpacked.out};
}
template<typename R, std::output_iterator<uint32_t> O>
requires(utf8_range_like<R> || utf32_range_like<R>)
transcode_result<dtl::uc_result_iterator<R>, O> transcode_to_utf16(
R && r, O out)
{
if constexpr (std::is_pointer_v<std::remove_reference_t<R>>) {
return text::transcode_to_utf16(r, null_sentinel, out);
} else {
return text::transcode_to_utf16(
std::ranges::begin(r), std::ranges::end(r), out);
}
}
// -> utf32
template<
std::input_iterator I,
std::sentinel_for<I> S,
std::output_iterator<uint32_t> O>
requires(
utf8_code_unit<std::iter_value_t<I>> ||
utf16_code_unit<std::iter_value_t<I>>)
transcode_result<I, O> transcode_to_utf32(I first, S last, O out)
{
auto const r = text::unpack_iterator_and_sentinel(first, last);
auto unpacked = detail::transcode_to_32<false>(
detail::tag_t<r.format_tag>{}, r.first, r.last, -1, out);
return {r.repack(unpacked.in), unpacked.out};
}
template<typename R, std::output_iterator<uint32_t> O>
requires(utf8_range_like<R> || utf16_range_like<R>)
transcode_result<dtl::uc_result_iterator<R>, O> transcode_to_utf32(
R && r, O out)
{
if constexpr (std::is_pointer_v<std::remove_reference_t<R>>) {
return text::transcode_to_utf32(r, null_sentinel, out);
} else {
return text::transcode_to_utf32(
std::ranges::begin(r), std::ranges::end(r), out);
}
}
}}}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,101 +0,0 @@
// Copyright (C) 2023 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_TRANSCODE_ITERATOR_FWD_HPP
#define BOOST_PARSER_DETAIL_TEXT_TRANSCODE_ITERATOR_FWD_HPP
#include <boost/parser/detail/text/concepts.hpp>
namespace boost::parser::detail { namespace text {
struct use_replacement_character;
namespace detail {
template<
typename RepackedIterator,
typename I,
typename S,
typename Then>
struct bidi_repacker;
}
}}
namespace boost::parser::detail { namespace text {
namespace detail {
template<format Format>
constexpr auto format_to_type();
template<format Format>
using format_to_type_t = decltype(format_to_type<Format>());
}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<
format FromFormat,
format ToFormat,
std::input_iterator I,
std::sentinel_for<I> S = I,
transcoding_error_handler ErrorHandler = use_replacement_character>
requires std::convertible_to<std::iter_value_t<I>, detail::format_to_type_t<FromFormat>>
#else
template<
format FromFormat,
format ToFormat,
typename I,
typename S = I,
typename ErrorHandler = use_replacement_character>
#endif
class utf_iterator;
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<
utf8_iter I,
std::sentinel_for<I> S = I,
transcoding_error_handler ErrorHandler = use_replacement_character>
using utf_8_to_16_iterator =
utf_iterator<format::utf8, format::utf16, I, S, ErrorHandler>;
template<
utf16_iter I,
std::sentinel_for<I> S = I,
transcoding_error_handler ErrorHandler = use_replacement_character>
using utf_16_to_8_iterator =
utf_iterator<format::utf16, format::utf8, I, S, ErrorHandler>;
template<
utf8_iter I,
std::sentinel_for<I> S = I,
transcoding_error_handler ErrorHandler = use_replacement_character>
using utf_8_to_32_iterator =
utf_iterator<format::utf8, format::utf32, I, S, ErrorHandler>;
template<
utf32_iter I,
std::sentinel_for<I> S = I,
transcoding_error_handler ErrorHandler = use_replacement_character>
using utf_32_to_8_iterator =
utf_iterator<format::utf32, format::utf8, I, S, ErrorHandler>;
template<
utf16_iter I,
std::sentinel_for<I> S = I,
transcoding_error_handler ErrorHandler = use_replacement_character>
using utf_16_to_32_iterator =
utf_iterator<format::utf16, format::utf32, I, S, ErrorHandler>;
template<
utf32_iter I,
std::sentinel_for<I> S = I,
transcoding_error_handler ErrorHandler = use_replacement_character>
using utf_32_to_16_iterator =
utf_iterator<format::utf32, format::utf16, I, S, ErrorHandler>;
#endif
}}
#endif

View File

@@ -1,836 +0,0 @@
// Copyright (C) 2020 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_TRANSCODE_VIEW_HPP
#define BOOST_PARSER_DETAIL_TEXT_TRANSCODE_VIEW_HPP
#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>
#include <climits>
namespace boost::parser::detail { namespace text {
namespace detail {
template<class I>
constexpr auto iterator_to_tag()
{
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
if constexpr (std::random_access_iterator<I>) {
return std::random_access_iterator_tag{};
} else if constexpr (std::bidirectional_iterator<I>) {
return std::bidirectional_iterator_tag{};
} else if constexpr (std::forward_iterator<I>) {
#else
if constexpr (detail::random_access_iterator_v<I>) {
return std::random_access_iterator_tag{};
} else if constexpr (detail::bidirectional_iterator_v<I>) {
return std::bidirectional_iterator_tag{};
} else if constexpr (detail::forward_iterator_v<I>) {
#endif
return std::forward_iterator_tag{};
} else {
return std::input_iterator_tag{};
}
}
template<class I>
using iterator_to_tag_t = decltype(iterator_to_tag<I>());
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
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; }
};
#else
struct cast_to_char8;
struct cast_to_char16;
struct cast_to_char32;
template<typename Tag, typename Arg>
auto function_for_tag(Arg arg)
{
#if defined(__cpp_char8_t)
if constexpr (std::is_same_v<Tag, cast_to_char8>) {
return (char8_t)arg;
} else
#endif
if constexpr (std::is_same_v<Tag, cast_to_char16>) {
return (char16_t)arg;
} else if constexpr (std::is_same_v<Tag, cast_to_char32>) {
return (char32_t)arg;
}
}
#endif
}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<std::ranges::input_range V, auto F>
requires std::ranges::view<V> &&
std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
#else
template<typename V, typename F> // F is a tag type in c++17
#endif
class project_view : public stl_interfaces::view_interface<project_view<V, F>>
{
V base_ = V();
template<bool Const>
class iterator;
template<bool Const>
class sentinel;
public:
constexpr project_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr explicit project_view(V base) : base_(std::move(base)) {}
constexpr V& base() & { return base_; }
constexpr const V& base() const& { return base_; }
constexpr V base() && { return std::move(base_); }
constexpr iterator<false> begin() { return iterator<false>{detail::begin(base_)}; }
constexpr iterator<true> begin() const
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::ranges::range<const V>
#endif
{ return iterator<true>{detail::begin(base_)}; }
constexpr sentinel<false> end() { return sentinel<false>{detail::end(base_)}; }
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
constexpr iterator<false> end() requires std::ranges::common_range<V>
{ return iterator<false>{detail::end(base_)}; }
#endif
constexpr sentinel<true> end() const
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::ranges::range<const V>
{ return sentinel<true>{detail::end(base_)}; }
constexpr iterator<true> end() const
requires std::ranges::common_range<const V>
#endif
{ return iterator<true>{detail::end(base_)}; }
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
constexpr auto size() requires std::ranges::sized_range<V> { return std::ranges::size(base_); }
constexpr auto size() const requires std::ranges::sized_range<const V> { return std::ranges::size(base_); }
#endif
};
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<std::ranges::input_range V, auto F>
requires std::ranges::view<V> &&
std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
#else
template<typename V, typename F>
#endif
template<bool Const>
class project_view<V, F>::iterator
: public boost::parser::detail::stl_interfaces::proxy_iterator_interface<
iterator<Const>,
detail::iterator_to_tag_t<detail::iterator_t<detail::maybe_const<Const, V>>>,
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
std::invoke_result_t<decltype(F)&, detail::range_reference_t<V>>
#else
decltype(detail::function_for_tag<F>(0))
#endif
>
{
using iterator_type = detail::iterator_t<detail::maybe_const<Const, V>>;
using sentinel_type = detail::sentinel_t<detail::maybe_const<Const, V>>;
using reference_type =
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
std::invoke_result_t<decltype(F) &, detail::range_reference_t<V>>
#else
decltype(detail::function_for_tag<F>(0))
#endif
;
using sentinel = project_view<V, F>::sentinel<Const>;
friend boost::parser::detail::stl_interfaces::access;
iterator_type & base_reference() noexcept { return it_; }
iterator_type base_reference() const { return it_; }
iterator_type it_ = iterator_type();
friend project_view<V, F>::sentinel<Const>;
template<bool OtherConst>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
#endif
friend constexpr bool operator==(const iterator<OtherConst> & x,
const sentinel & y);
template<bool OtherConst>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
#endif
friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
operator-(const iterator<OtherConst> & x, const sentinel & y);
template<bool OtherConst>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
#endif
friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
operator-(const sentinel & y, const iterator<OtherConst> & x);
public:
constexpr iterator() = default;
constexpr iterator(iterator_type it) : it_(std::move(it)) {}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
constexpr reference_type operator*() const { return F(*it_); }
#else
constexpr reference_type operator*() const
{
return detail::function_for_tag<F>(*it_);
}
#endif
};
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<std::ranges::input_range V, auto F>
requires std::ranges::view<V> &&
std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
#else
template<typename V, typename F>
#endif
template<bool Const>
class project_view<V, F>::sentinel
{
using Base = detail::maybe_const<Const, V>;
using sentinel_type = detail::sentinel_t<Base>;
sentinel_type end_ = sentinel_type();
public:
constexpr sentinel() = default;
constexpr explicit sentinel(sentinel_type end) : end_(std::move(end)) {}
#if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<bool Enable = Const, class = std::enable_if_t<Enable>>
#endif
constexpr sentinel(sentinel<!Const> i)
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires Const &&
std::convertible_to<detail::sentinel_t<V>, detail::sentinel_t<Base>>
#endif
: end_(std::move(i.end_))
{}
constexpr sentinel_type base() const { return end_; }
template<bool OtherConst>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
#endif
friend constexpr bool operator==(const iterator<OtherConst> & x,
const sentinel & y)
{ return x.it_ == y.end_; }
template<bool OtherConst>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
#endif
friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
operator-(const iterator<OtherConst> & x, const sentinel & y)
{ return x.it_ - y.end_; }
template<bool OtherConst>
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
#endif
friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
operator-(const sentinel & y, const iterator<OtherConst> & x)
{ return y.end_ - x.it_; }
};
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<class R, auto F>
project_view(R &&) -> project_view<std::views::all_t<R>, F>;
#endif
namespace detail {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<auto F>
#else
template<typename F>
#endif
struct project_impl : stl_interfaces::range_adaptor_closure<project_impl<F>>
{
template<class R>
using project_view_type = project_view<R, F>;
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
requires std::ranges::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>>>
#else
template<class R>
#endif
[[nodiscard]] constexpr auto operator()(R && r) const
{
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
return project_view_type(std::forward<R>(r));
#else
return project_view_type<R>(std::forward<R>(r));
#endif
}
};
}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<auto F>
#else
template<typename F>
#endif
constexpr detail::project_impl<F> project{};
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<class V>
using char8_view = project_view<V, detail::cast_to_charn<char8_t>{}>;
template<class V>
using char16_view = project_view<V, detail::cast_to_charn<char16_t>{}>;
template<class V>
using char32_view = project_view<V, detail::cast_to_charn<char32_t>{}>;
#else
#if defined(__cpp_char8_t)
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<std::ranges::input_range V>
requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char8_t>
class char8_view : public project_view<V, detail::cast_to_charn<char8_type>{}>
#else
template<typename V>
class char8_view : public project_view<V, detail::cast_to_char8>
#endif
{
public:
constexpr char8_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr char8_view(V base) :
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
project_view<V, detail::cast_to_charn<char8_t>{}>{std::move(base)}
#else
project_view<V, detail::cast_to_char8>{std::move(base)}
#endif
{}
};
#endif
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<std::ranges::input_range V>
requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char16_t>
class char16_view : public project_view<V, detail::cast_to_charn<char16_t>{}>
#else
template<typename V>
class char16_view : public project_view<V, detail::cast_to_char16>
#endif
{
public:
constexpr char16_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr char16_view(V base) :
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
project_view<V, detail::cast_to_charn<char16_t>{}>{std::move(base)}
#else
project_view<V, detail::cast_to_char16>{std::move(base)}
#endif
{}
};
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<std::ranges::input_range V>
requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char32_t>
class char32_view : public project_view<V, detail::cast_to_charn<char32_t>{}>
#else
template<typename V>
class char32_view : public project_view<V, detail::cast_to_char32>
#endif
{
public:
constexpr char32_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr char32_view(V base) :
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
project_view<V, detail::cast_to_charn<char32_t>{}>{std::move(base)}
#else
project_view<V, detail::cast_to_char32>{std::move(base)}
#endif
{}
};
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
char8_view(R &&) -> char8_view<detail::all_t<R>>;
template<class R>
char16_view(R &&) -> char16_view<detail::all_t<R>>;
template<class R>
char32_view(R &&) -> char32_view<detail::all_t<R>>;
#endif
#endif
namespace detail {
template<template<class> class View, format Format>
struct as_charn_impl : stl_interfaces::range_adaptor_closure<as_charn_impl<View, Format>>
{
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
requires (std::ranges::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>>
#else
template<class R>
#endif
[[nodiscard]] constexpr auto operator()(R && r) const
{
using T = remove_cv_ref_t<R>;
if constexpr (detail::is_empty_view<T>) {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
return std::ranges::empty_view<format_to_type_t<Format>>{};
#else
return 42; // Never gonna happen.
#endif
} else if constexpr (std::is_pointer_v<T>) {
return View(
BOOST_PARSER_DETAIL_TEXT_SUBRANGE(r, null_sentinel));
} else {
return View(std::forward<R>(r));
}
}
};
template<class T>
constexpr bool is_charn_view = false;
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class V>
constexpr bool is_charn_view<char8_view<V>> = true;
#endif
template<class V>
constexpr bool is_charn_view<char16_view<V>> = true;
template<class V>
constexpr bool is_charn_view<char32_view<V>> = true;
}
#if defined(__cpp_char8_t)
inline constexpr detail::as_charn_impl<char8_view, format::utf8> as_char8_t;
#endif
inline constexpr detail::as_charn_impl<char16_view, format::utf16> as_char16_t;
inline constexpr detail::as_charn_impl<char32_view, format::utf32> as_char32_t;
// clang-format off
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<utf_range V>
requires std::ranges::view<V> && std::ranges::forward_range<V>
#else
template<typename V>
#endif
class unpacking_view : public stl_interfaces::view_interface<unpacking_view<V>> {
V base_ = V();
public:
constexpr unpacking_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr unpacking_view(V base) : base_(std::move(base)) {}
constexpr V base() const &
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::copy_constructible<V>
#endif
{ return base_; }
constexpr V base() && { return std::move(base_); }
constexpr auto code_units() const noexcept {
auto unpacked = boost::parser::detail::text::unpack_iterator_and_sentinel(detail::begin(base_), detail::end(base_));
return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(unpacked.first, unpacked.last);
}
constexpr auto begin() { return code_units().begin(); }
constexpr auto begin() const { return code_units().begin(); }
constexpr auto end() { return code_units().end(); }
constexpr auto end() const { return code_units().end(); }
};
template<class R>
unpacking_view(R &&) -> unpacking_view<detail::all_t<R>>;
// clang-format on
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<format Format, utf_range V>
requires std::ranges::view<V>
#else
template<format Format, typename V>
#endif
class utf_view : public stl_interfaces::view_interface<utf_view<Format, V>>
{
V base_ = V();
template<format FromFormat, class I, class S>
static constexpr auto make_begin(I first, S last)
{
if constexpr (detail::bidirectional_iterator_v<I>) {
return utf_iterator<FromFormat, Format, I, S>{first, first, last};
} else {
return utf_iterator<FromFormat, Format, I, S>{first, last};
}
}
template<format FromFormat, class I, class S>
static constexpr auto make_end(I first, S last)
{
if constexpr (!std::is_same_v<I, S>) {
return last;
} else if constexpr (detail::bidirectional_iterator_v<I>) {
return utf_iterator<FromFormat, Format, I, S>{first, last, last};
} else {
return utf_iterator<FromFormat, Format, I, S>{last, last};
}
}
public:
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
constexpr utf_view() requires std::default_initializable<V> = default;
#endif
constexpr utf_view(V base) : base_{std::move(base)} {}
constexpr V base() const &
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::copy_constructible<V>
#endif
{ return base_; }
constexpr V base() && { return std::move(base_); }
constexpr auto begin()
{
constexpr format from_format = detail::format_of<detail::range_value_t<V>>();
if constexpr(detail::is_charn_view<V>) {
return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
} else {
return make_begin<from_format>(detail::begin(base_), detail::end(base_));
}
}
constexpr auto begin() const
{
constexpr format from_format = detail::format_of<detail::range_value_t<const V>>();
if constexpr(detail::is_charn_view<V>) {
return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
} else {
return make_begin<from_format>(detail::begin(base_), detail::end(base_));
}
}
constexpr auto end()
{
constexpr format from_format = detail::format_of<detail::range_value_t<V>>();
if constexpr(detail::is_charn_view<V>) {
return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
} else {
return make_end<from_format>(detail::begin(base_), detail::end(base_));
}
}
constexpr auto end() const
{
constexpr format from_format = detail::format_of<detail::range_value_t<const V>>();
if constexpr(detail::is_charn_view<V>) {
return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
} else {
return make_end<from_format>(detail::begin(base_), detail::end(base_));
}
}
/** Stream inserter; performs unformatted output, in UTF-8
encoding. */
friend std::ostream & operator<<(std::ostream & os, utf_view v)
{
if constexpr (Format == format::utf8) {
auto out = std::ostreambuf_iterator<char>(os);
for (auto it = v.begin(); it != v.end(); ++it, ++out) {
*out = *it;
}
} else {
boost::parser::detail::text::transcode_to_utf8(
v.begin(), v.end(), std::ostreambuf_iterator<char>(os));
}
return os;
}
#if defined(BOOST_TEXT_DOXYGEN) || defined(_MSC_VER)
/** Stream inserter; performs unformatted output, in UTF-16 encoding.
Defined on Windows only. */
friend std::wostream & operator<<(std::wostream & os, utf_view v)
{
if constexpr (Format == format::utf16) {
auto out = std::ostreambuf_iterator<wchar_t>(os);
for (auto it = v.begin(); it != v.end(); ++it, ++out) {
*out = *it;
}
} else {
boost::parser::detail::text::transcode_to_utf16(
v.begin(), v.end(), std::ostreambuf_iterator<wchar_t>(os));
}
return os;
}
#endif
};
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<format Format, class R>
utf_view(R &&) -> utf_view<Format, std::views::all_t<R>>;
template<class V>
using utf8_view = utf_view<format::utf8, V>;
template<class V>
using utf16_view = utf_view<format::utf16, V>;
template<class V>
using utf32_view = utf_view<format::utf32, V>;
#else
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<utf_range V>
requires std::ranges::view<V>
#else
template<typename V>
#endif
class utf8_view : public utf_view<format::utf8, V>
{
public:
constexpr utf8_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr utf8_view(V base) :
utf_view<format::utf8, V>{std::move(base)}
{}
};
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<utf_range V>
requires std::ranges::view<V>
#else
template<typename V>
#endif
class utf16_view : public utf_view<format::utf16, V>
{
public:
constexpr utf16_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr utf16_view(V base) :
utf_view<format::utf16, V>{std::move(base)}
{}
};
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<utf_range V>
requires std::ranges::view<V>
#else
template<typename V>
#endif
class utf32_view : public utf_view<format::utf32, V>
{
public:
constexpr utf32_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires std::default_initializable<V>
#endif
= default;
constexpr utf32_view(V base) :
utf_view<format::utf32, V>{std::move(base)}
{}
};
#if !BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<class R>
utf8_view(R &&) -> utf8_view<detail::all_t<R>>;
template<class R>
utf16_view(R &&) -> utf16_view<detail::all_t<R>>;
template<class R>
utf32_view(R &&) -> utf32_view<detail::all_t<R>>;
#endif
#endif
#if defined(BOOST_TEXT_DOXYGEN)
/** A view adaptor that produces a UTF-8 view of the given view. */
constexpr detail::unspecified as_utf8;
/** A view adaptor that produces a UTF-16 view of the given view. */
constexpr detail::unspecified as_utf16;
/** A view adaptor that produces a UTF-32 view of the given view. */
constexpr detail::unspecified as_utf32;
#endif
namespace detail {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R, template<class> class View>
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>()));
template<class R, template<class> class View>
constexpr bool can_utf_view =
is_detected_v<can_utf_view_expr, R, View<R>>;
#endif
template<class T>
constexpr bool is_utf_view = false;
template<class T>
constexpr bool is_utf_view<utf8_view<T>> = true;
template<class T>
constexpr bool is_utf_view<utf16_view<T>> = true;
template<class T>
constexpr bool is_utf_view<utf32_view<T>> = true;
template<format F, class T>
constexpr bool is_utf_view<utf_view<F, T>> = true;
template<typename T>
constexpr bool is_bounded_array_v = false;
template<typename T, int N>
constexpr bool is_bounded_array_v<T[N]> = true;
template<class R>
constexpr decltype(auto) unpack_range(R && r)
{
using T = detail::remove_cv_ref_t<R>;
if constexpr (forward_range_v<T>) {
auto unpacked =
boost::parser::detail::text::unpack_iterator_and_sentinel(detail::begin(r), detail::end(r));
if constexpr (is_bounded_array_v<T>) {
constexpr auto n = std::extent_v<T>;
if (n && !r[n - 1])
--unpacked.last;
return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(unpacked.first, unpacked.last);
} else if constexpr (
!std::is_same_v<decltype(unpacked.first), iterator_t<R>> ||
!std::is_same_v<decltype(unpacked.last), sentinel_t<R>>) {
return unpacking_view(std::forward<R>(r));
} else {
return std::forward<R>(r);
}
} else {
return std::forward<R>(r);
}
}
template<class R>
using unpacked_range = decltype(detail::unpack_range(std::declval<R>()));
template<template<class> class View, format Format>
struct as_utf_impl : stl_interfaces::range_adaptor_closure<as_utf_impl<View, Format>>
{
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
requires is_utf_view<std::remove_cvref_t<R>> ||
(std::ranges::viewable_range<R> &&
can_utf_view<unpacked_range<R>, View>) ||
utf_pointer<std::remove_cvref_t<R>>
#else
template<typename R>
#endif
[[nodiscard]] constexpr auto operator()(R && r) const
{
using T = detail::remove_cv_ref_t<R>;
if constexpr (detail::is_empty_view<T>) {
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
return std::ranges::empty_view<format_to_type_t<Format>>{};
#else
return 42; // Never gonna happen.
#endif
} else if constexpr (is_utf_view<T>) {
return View(std::forward<R>(r).base());
} else if constexpr (detail::is_charn_view<T>) {
return View(std::forward<R>(r));
} else if constexpr (std::is_pointer_v<T>) {
return View(
BOOST_PARSER_DETAIL_TEXT_SUBRANGE(r, null_sentinel));
} else {
return View(detail::unpack_range(std::forward<R>(r)));
}
}
};
template<class T>
constexpr bool is_utf32_view = false;
template<class V>
constexpr bool is_utf32_view<utf_view<format::utf32, V>> = true;
}
inline constexpr detail::as_utf_impl<utf8_view, format::utf8> as_utf8;
inline constexpr detail::as_utf_impl<utf16_view, format::utf16> as_utf16;
inline constexpr detail::as_utf_impl<utf32_view, format::utf32> as_utf32;
}}
#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>> =
enable_borrowed_range<V>;
template<boost::parser::detail::text::format Format, class V>
inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf_view<Format, V>> =
enable_borrowed_range<V>;
#if !BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<class V>
inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf8_view<V>> =
enable_borrowed_range<V>;
template<class V>
inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf16_view<V>> =
enable_borrowed_range<V>;
template<class V>
inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf32_view<V>> =
enable_borrowed_range<V>;
#endif
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +0,0 @@
// Copyright (C) 2020 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_TRIE_FWD_HPP
#define BOOST_PARSER_DETAIL_TEXT_TRIE_FWD_HPP
namespace boost::parser::detail { namespace text {
/** A statically polymorphic less-than compariason object type. This is
only necessary for pre-C++14 portablility. */
struct less
{
template<typename T>
bool operator()(T const & lhs, T const & rhs) const
{
return std::less<T>{}(lhs, rhs);
}
};
template<
typename Key,
typename Value,
typename Compare = less,
std::size_t KeySize = 0>
struct trie;
template<typename Key, typename Value, typename Compare = less>
struct trie_map;
template<typename Key, typename Compare = less>
struct trie_set;
}}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,274 +0,0 @@
// Copyright (C) 2020 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_UNPACK_HPP
#define BOOST_PARSER_DETAIL_TEXT_UNPACK_HPP
#include <boost/parser/detail/text/transcode_iterator_fwd.hpp>
#include <type_traits>
#include <optional>
namespace boost::parser::detail { namespace text {
struct no_op_repacker
{
template<class T>
T operator()(T x) const
{
return x;
}
};
namespace detail {
// Using this custom template is quite a bit faster than using lambdas.
// Unexpected.
template<
typename RepackedIterator,
typename I,
typename S,
typename Then,
bool Bidi>
struct repacker
{
repacker() = default;
#if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<bool Enable = Bidi, typename = std::enable_if_t<Enable>>
#endif
repacker(I first, S last, Then then)
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires Bidi
#endif
: first{first},
last{last},
then{then}
{}
#if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<bool Enable = !Bidi, typename = std::enable_if_t<Enable>>
#endif
repacker(S last, Then then)
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
requires(!Bidi)
#endif
:
last{last}, then{then}
{}
auto operator()(I it) const
{
if constexpr (Bidi) {
return then(RepackedIterator(*first, it, last));
} else {
return then(RepackedIterator(it, last));
}
}
std::optional<I> first;
[[no_unique_address]] S last;
[[no_unique_address]] Then then;
};
template<typename I, typename S, typename Repack>
constexpr auto
unpack_iterator_and_sentinel_impl(I first, S last, Repack repack);
template<
format FromFormat,
format ToFormat,
typename I,
typename S,
typename ErrorHandler,
typename Repack>
constexpr auto unpack_iterator_and_sentinel_impl(
utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> last,
Repack repack);
template<
format FromFormat,
format ToFormat,
typename I,
typename S,
typename ErrorHandler,
typename Repack>
constexpr auto unpack_iterator_and_sentinel_impl(
utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
S last,
Repack repack);
template<typename I, typename S, typename Repack>
constexpr auto
unpack_iterator_and_sentinel(I first, S last, Repack repack)
{
return detail::unpack_iterator_and_sentinel_impl(
first, last, repack);
}
struct unpack_iterator_and_sentinel_cpo
{
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<
utf_iter I,
std::sentinel_for<I> S,
typename Repack = no_op_repacker>
requires std::forward_iterator<I>
#else
template<typename I, typename S, typename Repack = no_op_repacker>
#endif
constexpr auto
operator()(I first, S last, Repack repack = Repack()) const
{
return unpack_iterator_and_sentinel(first, last, repack);
}
};
}
inline namespace cpo {
inline constexpr detail::unpack_iterator_and_sentinel_cpo
unpack_iterator_and_sentinel{};
}
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<format FormatTag, utf_iter I, std::sentinel_for<I> S, class Repack>
#else
template<format FormatTag, typename I, typename S, class Repack>
#endif
struct unpack_result
{
static constexpr format format_tag = FormatTag;
I first;
[[no_unique_address]] S last;
[[no_unique_address]] Repack repack;
};
namespace detail {
struct no_such_type
{};
template<typename I, typename S, typename Repack>
constexpr auto
unpack_iterator_and_sentinel_impl(I first, S last, Repack repack)
{
using value_type = detail::iter_value_t<I>;
if constexpr (
std::is_same_v<value_type, char>
#if defined(__cpp_char8_t)
|| std::is_same_v<value_type, char8_t>
#endif
) {
return unpack_result<format::utf8, I, S, Repack>{
first, last, repack};
} else if constexpr (
#if defined(_MSC_VER)
std::is_same_v<value_type, wchar_t> ||
#endif
std::is_same_v<value_type, char16_t>) {
return unpack_result<format::utf16, I, S, Repack>{
first, last, repack};
} else if constexpr (
#if !defined(_MSC_VER)
std::is_same_v<value_type, wchar_t> ||
#endif
std::is_same_v<value_type, char32_t>) {
return unpack_result<format::utf32, I, S, Repack>{
first, last, repack};
} else {
static_assert(
std::is_same_v<Repack, no_such_type>,
"Unpacked iterator is not a utf_iter!");
return 0;
}
}
}
}}
#include <boost/parser/detail/text/transcode_iterator.hpp>
namespace boost::parser::detail { namespace text { namespace detail {
template<
format FromFormat,
format ToFormat,
typename I,
typename S,
typename ErrorHandler,
typename Repack>
constexpr auto unpack_iterator_and_sentinel_impl(
utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> last,
Repack repack)
{
using iterator = utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>;
if constexpr (
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
std::bidirectional_iterator<I>
#else
std::is_base_of_v<
std::bidirectional_iterator_tag,
typename std::iterator_traits<I>::iterator_category>
#endif
) {
return boost::parser::detail::text::unpack_iterator_and_sentinel(
first.base(),
last.base(),
repacker<
iterator,
decltype(first.begin()),
decltype(first.end()),
Repack,
true>(first.begin(), first.end(), repack));
} else {
return boost::parser::detail::text::unpack_iterator_and_sentinel(
first.base(),
last.base(),
repacker<iterator, int, decltype(first.end()), Repack, false>(
first.end(), repack));
}
}
template<
format FromFormat,
format ToFormat,
typename I,
typename S,
typename ErrorHandler,
typename Repack>
constexpr auto unpack_iterator_and_sentinel_impl(
utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler> first,
S last,
Repack repack)
{
using iterator = utf_iterator<FromFormat, ToFormat, I, S, ErrorHandler>;
if constexpr (
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
std::bidirectional_iterator<I>
#else
std::is_base_of_v<
std::bidirectional_iterator_tag,
typename std::iterator_traits<I>::iterator_category>
#endif
) {
return boost::parser::detail::text::unpack_iterator_and_sentinel(
first.base(),
last,
repacker<
iterator,
decltype(first.begin()),
decltype(first.end()),
Repack,
true>(first.begin(), first.end(), repack));
} else {
return boost::parser::detail::text::unpack_iterator_and_sentinel(
first.base(),
last,
repacker<iterator, int, S, Repack, false>(last, repack));
}
}
}}}
#endif

View File

@@ -1,47 +0,0 @@
// Copyright (C) 2020 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_UTF_HPP
#define BOOST_PARSER_DETAIL_TEXT_UTF_HPP
#include <boost/parser/detail/text/config.hpp>
#include <cstdint>
#include <type_traits>
#include <cstdint>
namespace boost::parser::detail { namespace text {
/** The Unicode Transformation Formats. */
enum class format { none = 0, utf8 = 1, utf16 = 2, utf32 = 4 };
namespace detail {
template<typename T>
constexpr format format_of()
{
if constexpr (
std::is_same_v<T, char>
#if defined(__cpp_char8_t)
|| std::is_same_v<T, char8_t>
#endif
) {
return format::utf8;
} else if (
std::is_same_v<T, char16_t>
#ifdef _MSC_VER
|| std::is_same_v<T, wchar_t>
#endif
) {
return format::utf16;
} else {
return format::utf32;
}
}
}
}}
#endif

View File

@@ -1,706 +0,0 @@
// 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

View File

@@ -1,360 +0,0 @@
#ifndef BOOST_PARSER_ERROR_HANDLING_HPP
#define BOOST_PARSER_ERROR_HANDLING_HPP
#include <boost/parser/error_handling_fwd.hpp>
#include <boost/parser/detail/printing.hpp>
#include <boost/parser/detail/text/algorithm.hpp>
#include <boost/parser/detail/text/transcode_iterator.hpp>
#include <algorithm>
#include <array>
#include <functional>
#include <iostream>
#include <sstream>
namespace boost { namespace parser {
namespace detail {
// All the hard line break code points from the Unicode Line Break
// Algorithm; see https://unicode.org/reports/tr14.
inline constexpr std::array<int, 7> eol_cps = {
{0x000a, 0x000b, 0x000c, 0x000d, 0x0085, 0x2028, 0x2029}};
inline constexpr int eol_cp_mask =
0x000a | 0x000b | 0x000c | 0x000d | 0x0085 | 0x2028 | 0x2029;
}
/** Returns the `line_position` for `it`, counting lines from the
beginning of the input `first`. */
template<typename Iter>
line_position<Iter> find_line_position(Iter first, Iter it)
{
bool prev_cr = false;
auto retval = line_position<Iter>{first, 0, 0};
for (Iter pos = first; pos != it; ++pos) {
auto const c = *pos;
bool const found =
(c & detail::eol_cp_mask) == c &&
std::find(detail::eol_cps.begin(), detail::eol_cps.end(), c) !=
detail::eol_cps.end();
if (found) {
retval.line_start = std::next(pos);
retval.column_number = 0;
} else {
++retval.column_number;
}
if (found && (!prev_cr || c != 0x000a))
++retval.line_number;
prev_cr = c == 0x000d;
}
return retval;
}
/** Returns the iterator to the end of the line in which `it` is
found. */
template<typename Iter, typename Sentinel>
Iter find_line_end(Iter it, Sentinel last)
{
return parser::detail::text::find_if(it, last, [](auto c) {
return (c & detail::eol_cp_mask) == c &&
std::find(
detail::eol_cps.begin(), detail::eol_cps.end(), c) !=
detail::eol_cps.end();
});
}
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_message(
std::ostream & os,
std::string_view filename,
Iter first,
Iter it,
Sentinel last,
std::string_view message,
int64_t preferred_max_line_length,
int64_t max_after_caret)
{
if (!filename.empty())
os << filename << ':';
auto const position = parser::find_line_position(first, it);
os << (position.line_number + 1) << ':' << position.column_number
<< ": " << message << " here";
if (it == last)
os << " (end of input)";
os << ":\n";
std::string underlining(std::distance(position.line_start, it), ' ');
detail::trace_input(os, position.line_start, it, false, 1u << 31);
if (it == last) {
os << '\n' << underlining << "^\n";
return os;
}
underlining += '^';
int64_t const limit = (std::max)(
preferred_max_line_length,
(int64_t)underlining.size() + max_after_caret);
int64_t i = (int64_t)underlining.size();
auto const line_end = parser::find_line_end(std::next(it), last);
detail::trace_input(os, it, line_end, false, limit - i);
os << '\n' << underlining << '\n';
return os;
}
#if defined(_MSC_VER)
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_message(
std::ostream & os,
std::wstring_view filename,
Iter first,
Iter it,
Sentinel last,
std::string_view message,
int64_t preferred_max_line_length,
int64_t max_after_caret)
{
auto const r = filename | parser::detail::text::as_utf8;
std::string s(r.begin(), r.end());
return parser::write_formatted_message(
os,
s,
first,
it,
last,
message,
preferred_max_line_length,
max_after_caret);
}
#endif
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_expectation_failure_error_message(
std::ostream & os,
std::string_view filename,
Iter first,
Sentinel last,
parse_error<Iter> const & e,
int64_t preferred_max_line_length,
int64_t max_after_caret)
{
std::string message = "error: Expected ";
message += e.what();
return parser::write_formatted_message(
os,
filename,
first,
e.iter,
last,
message,
preferred_max_line_length,
max_after_caret);
}
#if defined(_MSC_VER)
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_expectation_failure_error_message(
std::ostream & os,
std::wstring_view filename,
Iter first,
Sentinel last,
parse_error<Iter> const & e,
int64_t preferred_max_line_length,
int64_t max_after_caret)
{
auto const r = filename | parser::detail::text::as_utf8;
std::string s(r.begin(), r.end());
return parser::write_formatted_expectation_failure_error_message(
os, s, first, last, e, preferred_max_line_length, max_after_caret);
}
#endif
/** An error handler that allows users to supply callbacks to handle the
reporting of warnings and errors. The reporting of errors and/or
warnings can be suppressed by supplying one or both
default-constructed callbacks. */
struct callback_error_handler
{
using callback_type = std::function<void(std::string const &)>;
callback_error_handler() {}
callback_error_handler(
callback_type error,
callback_type warning = callback_type(),
std::string_view filename = "") :
error_(error), warning_(warning), filename_(filename)
{}
#if defined(_MSC_VER) || defined(BOOST_PARSER_DOXYGEN)
/** This overload is Windows-only. */
callback_error_handler(
callback_type error,
callback_type warning,
std::wstring_view filename) :
error_(error), warning_(warning)
{
auto const r = filename | parser::detail::text::as_utf8;
filename_.assign(r.begin(), r.end());
}
#endif
template<typename Iter, typename Sentinel>
error_handler_result
operator()(Iter first, Sentinel last, parse_error<Iter> const & e) const
{
if (error_) {
std::stringstream ss;
parser::write_formatted_expectation_failure_error_message(
ss, filename_, first, last, e);
error_(ss.str());
}
return error_handler_result::fail;
}
template<typename Context, typename Iter>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context,
Iter it) const
{
callback_type const & cb =
kind == diagnostic_kind::error ? error_ : warning_;
if (!cb)
return;
std::stringstream ss;
parser::write_formatted_message(
ss,
filename_,
parser::_begin(context),
it,
parser::_end(context),
message);
cb(ss.str());
}
template<typename Context>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context) const
{
diagnose(kind, message, context, parser::_where(context).begin());
}
callback_type error_;
callback_type warning_;
std::string filename_;
};
/** An error handler that just re-throws any exception generated by the
parse. */
struct rethrow_error_handler
{
template<typename Iter, typename Sentinel>
error_handler_result
operator()(Iter first, Sentinel last, parse_error<Iter> const & e) const
{
return error_handler_result::rethrow;
}
template<typename Context, typename Iter>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context,
Iter it) const
{}
template<typename Context>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context) const
{}
};
// implementations
template<typename Iter, typename Sentinel>
error_handler_result default_error_handler::operator()(
Iter first, Sentinel last, parse_error<Iter> const & e) const
{
parser::write_formatted_expectation_failure_error_message(
std::cerr, "", first, last, e);
return error_handler_result::fail;
}
template<typename Context, typename Iter>
void default_error_handler::diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context,
Iter it) const
{
parser::write_formatted_message(
std::cerr,
"",
parser::_begin(context),
it,
parser::_end(context),
message);
}
template<typename Context>
void default_error_handler::diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context) const
{
diagnose(kind, message, context, parser::_where(context).begin());
}
template<typename Iter, typename Sentinel>
error_handler_result stream_error_handler::operator()(
Iter first, Sentinel last, parse_error<Iter> const & e) const
{
std::ostream * os = err_os_;
if (!os)
os = &std::cerr;
parser::write_formatted_expectation_failure_error_message(
*os, filename_, first, last, e);
return error_handler_result::fail;
}
template<typename Context, typename Iter>
void stream_error_handler::diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context,
Iter it) const
{
std::ostream * os = kind == diagnostic_kind::error ? err_os_ : warn_os_;
if (!os)
os = &std::cerr;
parser::write_formatted_message(
*os,
filename_,
parser::_begin(context),
it,
parser::_end(context),
message);
}
template<typename Context>
void stream_error_handler::diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context) const
{
diagnose(kind, message, context, parser::_where(context).begin());
}
}}
#endif

View File

@@ -1,230 +0,0 @@
#ifndef BOOST_PARSER_ERROR_HANDLING_FWD_HPP
#define BOOST_PARSER_ERROR_HANDLING_FWD_HPP
#include <boost/parser/config.hpp>
#include <boost/parser/detail/text/transcode_view.hpp>
#include <iostream>
#include <string_view>
namespace boost { namespace parser {
/** The possible actions to take when a parse error is handled by an error
handler. */
enum class error_handler_result {
fail, /// Fail the top-level parse.
rethrow /// Re-throw the parse error exception.
};
/** The exception thrown when a parse error is encountered, consisting of
an iterator to the point of failure, and the name of the failed parser
or rule in `what()`. */
template<typename Iter>
struct parse_error : std::runtime_error
{
parse_error(Iter it, std::string const & msg) :
runtime_error(msg), iter(it)
{}
Iter iter;
};
/** A position within a line, consisting of an iterator to the start of
the line, the line number, and the column number. */
template<typename Iter>
struct line_position
{
Iter line_start;
int64_t line_number;
int64_t column_number;
};
/** Writes a formatted message (meaning prefixed with the file name, line,
and column number) to `os`. */
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_message(
std::ostream & os,
std::string_view filename,
Iter first,
Iter it,
Sentinel last,
std::string_view message,
int64_t preferred_max_line_length = 80,
int64_t max_after_caret = 40);
#if defined(_MSC_VER) || defined(BOOST_PARSER_DOXYGEN)
/** Writes a formatted message (meaning prefixed with the file name, line,
and column number) to `os`. This overload is Windows-only. */
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_message(
std::ostream & os,
std::wstring_view filename,
Iter first,
Iter it,
Sentinel last,
std::string_view message,
int64_t preferred_max_line_length = 80,
int64_t max_after_caret = 40);
#endif
/** Writes a formatted parse-expectation failure (meaning prefixed with
the file name, line, and column number) to `os`. */
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_expectation_failure_error_message(
std::ostream & os,
std::string_view filename,
Iter first,
Sentinel last,
parse_error<Iter> const & e,
int64_t preferred_max_line_length = 80,
int64_t max_after_caret = 40);
#if defined(_MSC_VER) || defined(BOOST_PARSER_DOXYGEN)
/** Writes a formatted parse-expectation failure (meaning prefixed with
the file name, line, and column number) to `os`. This overload is
Windows-only. */
template<typename Iter, typename Sentinel>
std::ostream & write_formatted_expectation_failure_error_message(
std::ostream & os,
std::wstring_view filename,
Iter first,
Sentinel last,
parse_error<Iter> const & e,
int64_t preferred_max_line_length = 80,
int64_t max_after_caret = 40);
#endif
/** The kinds of diagnostics that can be handled by an error handler. */
enum class diagnostic_kind {
error, /// An error diagnostic.
warning /// A warning diagnostic.
};
/** The error handler used when the user does not specify a custom one.
This error handler prints warnings and errors to `std::cerr`, and does
not have an associcated filename. */
struct default_error_handler
{
constexpr default_error_handler() = default;
/** Handles a `parse_error` exception thrown during parsing. A
formatted parse-expectation failure is printed to `std::cerr`.
Always returns `error_handler_result::fail`. */
template<typename Iter, typename Sentinel>
error_handler_result operator()(
Iter first, Sentinel last, parse_error<Iter> const & e) const;
/** Prints `message` to `std::cerr`. The diagnostic is printed with
the given `kind`, indicating the location as being at `it`. This
must be called within a parser semantic action, providing the
parse context. */
//[ error_handler_api_1
template<typename Context, typename Iter>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context,
Iter it) const;
//]
/** Prints `message` to `std::cerr`. The diagnostic is printed with
the given `kind`, at no particular location. This must be called
within a parser semantic action, providing the parse context. */
//[ error_handler_api_2
template<typename Context>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context) const;
//]
};
/** Prints warnings and errors to the `std::ostream`s provided by the
user, or `std::cerr` if neither stream is specified. If a filename is
provided, that is used to print all diagnostics. */
struct stream_error_handler
{
stream_error_handler() : err_os_(&std::cerr), warn_os_(err_os_) {}
stream_error_handler(std::string_view filename) :
filename_(filename), err_os_(&std::cerr), warn_os_(err_os_)
{}
stream_error_handler(std::string_view filename, std::ostream & errors) :
filename_(filename), err_os_(&errors), warn_os_(&errors)
{}
stream_error_handler(
std::string_view filename,
std::ostream & errors,
std::ostream & warnings) :
filename_(filename), err_os_(&errors), warn_os_(&warnings)
{}
#if defined(_MSC_VER) || defined(BOOST_PARSER_DOXYGEN)
/** This overload is Windows-only. */
stream_error_handler(std::wstring_view filename) :
err_os_(&std::cerr), warn_os_(err_os_)
{
auto const r = filename | detail::text::as_utf8;
filename_.assign(r.begin(), r.end());
}
/** This overload is Windows-only. */
stream_error_handler(
std::wstring_view filename, std::ostream & errors) :
err_os_(&errors), warn_os_(&errors)
{
auto const r = filename | detail::text::as_utf8;
filename_.assign(r.begin(), r.end());
}
/** This overload is Windows-only. */
stream_error_handler(
std::wstring_view filename,
std::ostream & errors,
std::ostream & warnings) :
err_os_(&errors), warn_os_(&warnings)
{
auto const r = filename | detail::text::as_utf8;
filename_.assign(r.begin(), r.end());
}
#endif
/** Handles a `parse_error` exception thrown during parsing. A
formatted parse-expectation failure is printed to `*err_os_` when
`err_os_` is non-null, or `std::cerr` otherwise. Always returns
`error_handler_result::fail`. */
template<typename Iter, typename Sentinel>
error_handler_result
operator()(Iter first, Sentinel last, parse_error<Iter> const & e) const;
/** Let `std::ostream * s = kind == diagnostic_kind::error : err_os_ :
warn_os_`; prints `message` to `*s` when `s` is non-null, or
`std::cerr` otherwise. The diagnostic is printed with the given
`kind`, indicating the location as being at `it`. This must be
called within a parser semantic action, providing the parse
context. */
template<typename Context, typename Iter>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context,
Iter it) const;
/** Let `std::ostream * s = kind == diagnostic_kind::error : err_os_ :
warn_os_`; prints `message` to `*s` when `s` is non-null, or
`std::cerr` otherwise. The diagnostic is printed with the given
`kind`, at no particular location. This must be called within a
parser semantic action, providing the parse context. */
template<typename Context>
void diagnose(
diagnostic_kind kind,
std::string_view message,
Context const & context) const;
private:
std::string filename_;
std::ostream * err_os_;
std::ostream * warn_os_;
};
}}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,553 +0,0 @@
// Copyright (C) 2020 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_PARSER_FWD_HPP
#define BOOST_PARSER_PARSER_FWD_HPP
#include <boost/parser/config.hpp>
#include <boost/parser/error_handling_fwd.hpp>
#include <any>
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <variant>
namespace boost::parser::detail { namespace text {
struct null_sentinel_t;
}}
namespace boost { namespace parser {
/** A sentinel type that compares equal to a pointer to a character value
type, iff the pointer is null. */
using null_sentinel_t = boost::parser::detail::text::null_sentinel_t;
/** A variable template that indicates that type `T` is an optional-like
type. */
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
/** A type trait that evaluates to the attribute type for parser `Parser`
used to parse range `R`, as if by calling `parse(r, parser)`, using
some `R r` and `Parser parser`. Note that this implies that pointers
to null-terminated strings are supported types for `R`. The result is
not wrapped in a `std::optional` like the result of a call to
`parse()` would be. If `Parser` produces no attribute, the result is
the no-attribute sentinel type `none`. */
template<typename R, typename Parser>
struct attribute;
/** An alias for `typename attribute<R, Parser>::type`. */
template<typename R, typename Parser>
using attribute_t = typename attribute<R, Parser>::type;
namespace detail {
template<typename T>
constexpr bool is_optional_v = enable_optional<T>;
struct nope;
enum class flags : unsigned int {
gen_attrs = 1 << 0,
use_skip = 1 << 1,
trace = 1 << 2,
in_apply_parser = 1 << 3
};
constexpr inline flags disable_attrs(flags f);
using symbol_table_tries_t =
std::map<void *, std::pair<std::any, bool>, std::less<void *>>;
template<
bool DoTrace,
bool UseCallbacks,
typename Iter,
typename Sentinel,
typename ErrorHandler>
inline auto make_context(
Iter first,
Sentinel last,
bool & success,
int & indent,
ErrorHandler const & error_handler,
nope &,
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
{};
template<
bool OmitAttr = false,
bool DontConsumeInput = false,
bool FailOnMatch = false,
typename Action = nope>
struct parser_config
{
static constexpr bool omit = OmitAttr;
static constexpr bool dont_consume_input = DontConsumeInput;
static constexpr bool fail_on_match = FailOnMatch;
static constexpr detail::flags flags(detail::flags f)
{
return omit ? detail::disable_attrs(f) : f;
}
[[maybe_unused]] Action action_;
};
}
/** Repeats the application of another parser `p` of type `Parser`,
optionally applying another parser `d` of type `DelimiterParser` in
between each pair of applications of `p`. The parse succeeds if `p`
succeeds at least the minumum number of times, and `d` succeeds each
time it is applied. The attribute produced is a sequence of the type
of attribute produced by `Parser`. */
template<
typename Parser,
typename DelimiterParser = detail::nope,
typename MinType = int64_t,
typename MaxType = int64_t,
typename ParserConfig = parser_config<>>
struct repeat_parser;
/** Repeats the application of another parser of type `Parser`, `[0, 1]`
times. The parse always succeeds. The attribute produced is a
`std::optional<T>`, where `T` is the type of attribute produced by
`Parser`. */
template<typename Parser, typename ParserConfig = parser_config<>>
struct opt_parser;
/** Applies each parser in `ParserTuple`, in order, stopping after the
application of the first one that succeeds. The parse succeeds iff
one of the sub-parsers succeeds. The attribute produced is a
`std::variant` over the types of attribute produced by the parsers in
`ParserTuple`. */
template<typename ParserTuple, typename ParserConfig = parser_config<>>
struct or_parser;
/** Applies each parsers in `ParserTuple`, an any order, stopping after
all of them have matched the input. The parse succeeds iff all the
parsers match, regardless of the order in which they do. The
attribute produced is a `parser::tuple` containing the attributes of
the subparsers, in their order of the parsers' appearance in
`ParserTuple`, not the order of the parsers' matches. It is an error
to specialize `perm_parser` with a `ParserTuple` template parameter
that includes an `eps_parser`. */
template<typename ParserTuple, typename ParserConfig = parser_config<>>
struct perm_parser;
/** Applies each parser in `ParserTuple`, in order. The parse succeeds
iff all of the sub-parsers succeed. The attribute produced is a
`std::tuple` over the types of attribute produced by the parsers in
`ParserTuple`. The BacktrackingTuple template parameter is a
`parser::tuple` of `std::bool_constant` values. The `i`th such value
indicates whether backtracking is allowed if the `i`th parser
fails. */
template<
typename ParserTuple,
typename BacktrackingTuple,
typename CombiningGroups,
typename ParserConfig = parser_config<>>
struct seq_parser;
/** Applies the given parser `p` of type `Parser` and an invocable `a` of
type `Action`. `Action` shall model `semantic_action`, and `a` will
only be invoked if `p` succeeds. The parse succeeds iff `p` succeeds.
Produces no attribute. */
template<
typename Parser,
typename Action,
typename ParserConfig = parser_config<>>
struct action_parser;
/** Applies the given parser `p` of type `Parser`. The attribute produced
by `p` is passed to the fiven invocable `f` of type `F`. `f` will
only be invoked if `p` succeeds and sttributes are currently being
generated. The parse succeeds iff `p` succeeds. The attribute
produced is the the result of the call to `f`. */
template<
typename Parser,
typename F,
typename ParserConfig = parser_config<>>
struct transform_parser;
/** Applies the given parser `p` of type `Parser`. This parser produces
no attribute, and suppresses the production of any attributes that
would otherwise be produced by `p`. The parse succeeds iff `p`
succeeds. */
template<typename Parser, typename ParserConfig = parser_config<>>
struct omit_parser;
/** Applies the given parser `p` of type `Parser`; regardless of the
attribute produced by `Parser`, this parser's attribute is equivalent
to `_where(ctx)` within a semantic action on `p`. The parse succeeds
iff `p` succeeds. */
template<typename Parser, typename ParserConfig = parser_config<>>
struct raw_parser;
#if defined(BOOST_PARSER_DOXYGEN) || defined(__cpp_lib_concepts)
/** Applies the given parser `p` of type `Parser`. Regardless of the
attribute produced by `Parser`, this parser's attribute is equivalent
to `std::basic_string_view<char_type>` within a semantic action on
`p`, where `char_type` is the type of character in the sequence being
parsed. If the parsed range is transcoded, `char_type` will be the
type being transcoded from. If the underlying range of `char_type` is
non-contiguous, code using `string_view_parser` is ill-formed. The
parse succeeds iff `p` succeeds. This parser is only available in
C++20 and later. */
template<typename Parser, typename ParserConfig = parser_config<>>
struct string_view_parser;
#endif
/** Applies the given parser `p` of type `Parser`, disabling the current
skipper in use, if any. The parse succeeds iff `p` succeeds. The
attribute produced is the type of attribute produced by `Parser`. */
template<typename Parser, typename ParserConfig = parser_config<>>
struct lexeme_parser;
/** Applies the given parser `p` of type `Parser`, enabling
case-insensitive matching, based on Unicode case folding. The parse
succeeds iff `p` succeeds. The attribute produced is the type of
attribute produced by `Parser`. */
template<typename Parser, typename ParserConfig = parser_config<>>
struct no_case_parser;
/** Applies the given parser `p` of type `Parser`, using a parser of type
`SkipParser` as the skipper. The parse succeeds iff `p` succeeds.
The attribute produced is the type of attribute produced by
`Parser`. */
template<
typename Parser,
typename SkipParser = detail::nope,
typename ParserConfig = parser_config<>>
struct skip_parser;
/** Applies the given parser `p` of type `Parser`, producing no attributes
and consuming no input. The parse succeeds iff `p`'s success is
unequal to `FailOnMatch`. */
template<
typename Parser,
typename ParserConfig,
typename ParserConfig = parser_config<>>
struct expect_parser;
/** Matches one of a set S of possible inputs, each of which is
associated with an attribute value of type `T`, forming a symbol
table. New elements and their associated attributes may be added to
or removed from S dynamically, during parsing; any such changes are
reverted at the end of parsing. The parse succeeds iff an element of
S is matched. \see `symbols` */
template<typename T, typename ParserConfig = parser_config<>>
struct symbol_parser;
/** Applies another parser `p`, associated with this parser via `TagType`.
The attribute produced is `Attribute`. Both a default-constructed
object of type `LocalState`, and a default-constructed object of type
`ParamsTuple`, are added to the parse context before the associated
parser is applied. The parse succeeds iff `p` succeeds. If
`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 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,
typename Attribute,
typename LocalState,
typename ParamsTuple,
typename ParserConfig = parser_config<>>
struct rule_parser;
/** Matches anything, and consumes no input. If `Predicate` is anything
other than `detail::nope` (which it is by default), and `pred_(ctx)`
evaluates to false, where `ctx` is the parser context, the parse
fails. */
template<typename Predicate, typename ParserConfig = parser_config<>>
struct eps_parser;
/** Matches only the end of input. Produces no attribute. */
template<typename ParserConfig = parser_config<>>
struct eoi_parser;
/** Matches anything, consumes no input, and produces an attribute of type
`RESOLVE(Attribute)`. */
template<typename Attribute, typename ParserConfig = parser_config<>>
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
parse fails only if the parser is constructed with a specific set of
expected code point values that does not include the matched code
point. */
template<typename Expected, typename AttributeType = void>
struct char_parser;
/** 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;
/** Maches 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`), 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, bool NoNewlines>
struct ws_parser;
/** Maches the strings "true" and "false", producing an attribute of
`true` or `false`, respectively, and fails on any other input. */
struct bool_parser;
/** Matches an unsigned number of radix `Radix`, of at least `MinDigits`
and at most `MaxDigits`, producing an attribute of type `T`. Fails on
any other input. The parse will also fail if `Expected` is anything
but `detail::nope` (which it is by default), and the produced
attribute is not equal to `expected_`. `Radix` must be in `[2,
36]`. */
template<
typename T,
int Radix = 10,
int MinDigits = 1,
int MaxDigits = -1,
typename Expected = detail::nope>
struct uint_parser;
/** Matches a signed number of radix `Radix`, of at least `MinDigits` and
at most `MaxDigits`, producing an attribute of type `T`. Fails on any
other input. The parse will also fail if `Expected` is anything but
`detail::nope` (which it is by default), and the produced
attribute is not equal to `expected_`. `Radix` must be one of `2`,
`8`, `10`, or `16`. */
template<
typename T,
int Radix = 10,
int MinDigits = 1,
int MaxDigits = -1,
typename Expected = detail::nope>
struct int_parser;
/** Matches a floating point number, producing an attribute of type
`T`. */
template<typename T>
struct float_parser;
/** Applies at most one of the parsers in `OrParser`. If `switch_value_`
matches one or more of the values in the parsers in `OrParser`, the
first such parser is applied, and the success or failure and attribute
of the parse are those of the applied parser. Otherwise, the parse
fails. */
template<typename SwitchValue, typename OrParser = detail::nope>
struct switch_parser;
/** A wrapper for parsers that provides the operations that must be
supported by all parsers (e.g. `operator>>()`). `GlobalState` is an
optional state object that can be accessed within semantic actions via
a call to `_globals()`. This global state object is ignored for all
but the topmost parser; the topmost global state object is available
in the semantic actions of all nested parsers. `ErrorHandler` is the
type of the error handler to be used on parse failure. This handler
is ignored on all but the topmost parser; the topmost parser's error
handler is used for all errors encountered during parsing. */
template<
typename Parser,
typename GlobalState = detail::nope,
typename ErrorHandler = default_error_handler>
struct parser_interface;
using no_attribute = detail::nope;
using no_local_state = detail::nope;
using no_params = detail::nope;
/** A type used to declare named parsing rules. The `TagType` template
parameter is used to associate a particular `rule` with the
`rule_parser` used during parsing. */
template<
typename TagType,
typename Attribute = no_attribute,
typename LocalState = no_local_state,
typename ParamsTuple = no_params>
struct rule;
/** A type used to declare named parsing rules that support reporting of
attributes via callback. The `TagType` template parameter is used to
associate a particular `rule` with the `rule_parser` used during
parsing. */
template<
typename TagType,
typename Attribute = no_attribute,
typename LocalState = no_local_state,
typename ParamsTuple = no_params>
struct callback_rule;
#ifdef BOOST_PARSER_DOXYGEN
/** Returns a reference to the attribute(s) (i.e. return value) of the
bottommost parser; multiple attributes will be stored within a
`parser::tuple`. You may write to this value in a semantic action to
control what attribute value(s) the associated parser produces.
Returns `none` if the bottommost parser does produce an attribute. */
decltype(auto) _val(Context const & context);
#endif
/** Returns a reference to the attribute or attributes already produced by
the bottommost parser; multiple attributes will be stored within a
`parser::tuple`. Returns `none` if the bottommost parser does produce
an attribute. */
template<typename Context>
decltype(auto) _attr(Context const & context);
/** Returns a `subrange` that describes the matched range of the
bottommost parser. */
template<typename Context>
decltype(auto) _where(Context const & context);
/** Returns an iterator to the beginning of the entire sequence being
parsed. The effect of calling this within a semantic action
associated with a skip-parser is undefined */
template<typename Context>
decltype(auto) _begin(Context const & context);
/** Returns an iterator to the end of the entire sequence being parsed. */
template<typename Context>
decltype(auto) _end(Context const & context);
/** Returns a reference to a `bool` that represents the success or failure
of the bottommost parser. You can assign `false` to this within a
semantic action to force a parser to fail its parse. */
template<typename Context>
decltype(auto) _pass(Context const & context);
/** Returns a reference to one or more local values that the bottommost
rule is declared to have; multiple values will be stored within a
`parser::tuple`. Returns `none` if there is no bottommost rule, or if
that rule has no locals. */
template<typename Context>
decltype(auto) _locals(Context const & context);
/** Returns a reference to one or more parameters passed to the bottommost
rule `r`, by using `r` as `r.with(param0, param1, ... paramN)`;
multiple values will be stored within a `parser::tuple`. Returns
`none` if there is no bottommost rule, or if that rule was not given
any parameters. */
template<typename Context>
decltype(auto) _params(Context const & context);
/** Returns a reference to the globals object associated with the
top-level parser. Returns `none` if there is no associated globals
object. */
template<typename Context>
decltype(auto) _globals(Context const & context);
/** Returns a reference to the error handler object associated with the
top-level parser. Returns `none` if there is no associated error
handler. */
template<typename Context>
decltype(auto) _error_handler(Context const & context);
/** Report that the error described in `message` occurred at `location`,
using the context's error handler. */
#if BOOST_PARSER_USE_CONCEPTS
template<std::forward_iterator I, typename Context>
#else
template<typename I, typename Context>
#endif
void _report_error(
Context const & context, std::string_view message, I location);
/** Report that the error described in `message` occurred at
`_where(context).begin()`, using the context's error handler. */
template<typename Context>
void _report_error(Context const & context, std::string_view message);
/** Report that the warning described in `message` occurred at `location`,
using the context's error handler. */
#if BOOST_PARSER_USE_CONCEPTS
template<std::forward_iterator I, typename Context>
#else
template<typename I, typename Context>
#endif
void _report_warning(
Context const & context, std::string_view message, I location);
/** Report that the warning described in `message` occurred at
`_where(context).begin()`, using the context's error handler. */
template<typename Context>
void _report_warning(Context const & context, std::string_view message);
}}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,725 +0,0 @@
#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`.
In addition to the template parameter constraints, `V` and
`ReplacementV` must be ranges of `char`, or must have the same UTF
format, and `V` and `ReplacementV` must meet the same compatibility
requirements as described in `std::ranges::join_view`. */
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

View File

@@ -1,673 +0,0 @@
#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

View File

@@ -1,399 +0,0 @@
#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

View File

@@ -1,109 +0,0 @@
// Copyright (C) 2022 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_SUBRANGE_HPP
#define BOOST_PARSER_SUBRANGE_HPP
#include <boost/parser/detail/text/config.hpp>
#include <boost/parser/detail/text/detail/algorithm.hpp>
#include <boost/parser/detail/stl_interfaces/view_interface.hpp>
namespace boost::parser {
/** A simple view type used throughout the rest of the library in C++17
builds; similar to `std::ranges::subrange`. */
#if BOOST_PARSER_USE_CONCEPTS
template<std::forward_iterator I, std::sentinel_for<I> S = I>
#else
template<typename I, typename S = I>
#endif
struct subrange : detail::stl_interfaces::view_interface<subrange<I, S>>
{
constexpr subrange() = default;
constexpr subrange(I first, S last) : first_(first), last_(last) {}
template<typename R>
constexpr explicit subrange(R const & r) :
first_(detail::text::detail::begin(r)),
last_(detail::text::detail::end(r))
{}
constexpr I begin() const { return first_; }
constexpr S end() const { return last_; }
[[nodiscard]] constexpr subrange next(std::ptrdiff_t n = 1) const
{
return subrange{detail::text::detail::next(first_), last_};
}
[[nodiscard]] constexpr subrange prev(std::ptrdiff_t n = 1) const
{
return subrange{detail::text::detail::prev(first_), last_};
}
constexpr subrange & advance(std::ptrdiff_t n)
{
std::advance(first_, n);
return *this;
}
template<
typename I2,
typename S2,
typename Enable = std::enable_if_t<
std::is_convertible<I, I2>::value &&
std::is_convertible<S, S2>::value>>
constexpr operator subrange<I2, S2>() const
{
return {first_, last_};
}
private:
I first_;
[[no_unique_address]] S last_;
};
#if defined(__cpp_deduction_guides)
#if BOOST_PARSER_USE_CONCEPTS
template<std::input_or_output_iterator I, std::sentinel_for<I> S>
#else
template<typename I, typename S>
#endif
subrange(I, S) -> subrange<I, S>;
#if BOOST_PARSER_USE_CONCEPTS
template<std::ranges::borrowed_range R>
#else
template<typename R>
#endif
subrange(R &&) -> subrange<
detail::text::detail::iterator_t<R>,
detail::text::detail::sentinel_t<R>>;
#endif
/** Makes a `subrange<I, S>` from an `I` and an `S`. */
#if BOOST_PARSER_USE_CONCEPTS
template<std::forward_iterator I, std::sentinel_for<I> S = I>
#else
template<typename I, typename S = I>
#endif
constexpr subrange<I, S> make_subrange(I first, S last) noexcept
{
return subrange<I, S>(first, last);
}
}
#if BOOST_PARSER_USE_CONCEPTS
namespace std::ranges {
template<std::forward_iterator I, std::sentinel_for<I> S>
inline constexpr bool enable_borrowed_range<boost::parser::subrange<I, S>> =
true;
}
#endif
#endif

View File

@@ -1,119 +0,0 @@
// Copyright (C) 2020 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_TRANSCODE_VIEW_HPP
#define BOOST_PARSER_TRANSCODE_VIEW_HPP
#include <boost/parser/detail/text/transcode_view.hpp>
namespace boost::parser {
using format = detail::text::format;
#if BOOST_PARSER_DETAIL_TEXT_USE_ALIAS_CTAD
template<class V>
using utf8_view = detail::text::utf_view<format::utf8, V>;
template<class V>
using utf16_view = detail::text::utf_view<format::utf16, V>;
template<class V>
using utf32_view = detail::text::utf_view<format::utf32, V>;
#else
/** A view that produces UTF-8 from an given sequence of UTF.
\tparam V Constrained by `std::ranges::view<V>`. Additionally, the
value type of `V` must be `char`, `wchar_t`, `char8_t`, `char16_t`, or
`char32_t`. */
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
template<detail::text::utf_range V>
requires std::ranges::view<V>
#else
template<typename V>
#endif
class utf8_view : public detail::text::utf_view<format::utf8, V>
{
public:
constexpr utf8_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
requires std::default_initializable<V>
#endif
= default;
constexpr utf8_view(V base) :
detail::text::utf_view<format::utf8, V>{std::move(base)}
{}
};
/** A view that produces UTF-16 from an given sequence of UTF.
\tparam V Constrained by `std::ranges::view<V>`. Additionally, the
value type of `V` must be `char`, `wchar_t`, `char8_t`, `char16_t`, or
`char32_t`. */
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
template<detail::text::utf_range V>
requires std::ranges::view<V>
#else
template<typename V>
#endif
class utf16_view : public detail::text::utf_view<format::utf16, V>
{
public:
constexpr utf16_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
requires std::default_initializable<V>
#endif
= default;
constexpr utf16_view(V base) :
detail::text::utf_view<format::utf16, V>{std::move(base)}
{}
};
/** A view that produces UTF-32 from an given sequence of UTF.
\tparam V Constrained by `std::ranges::view<V>`. Additionally, the
value type of `V` must be `char`, `wchar_t`, `char8_t`, `char16_t`, or
`char32_t`. */
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
template<detail::text::utf_range V>
requires std::ranges::view<V>
#else
template<typename V>
#endif
class utf32_view : public detail::text::utf_view<format::utf32, V>
{
public:
constexpr utf32_view()
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS || defined(BOOST_PARSER_DOXYGEN)
requires std::default_initializable<V>
#endif
= default;
constexpr utf32_view(V base) :
detail::text::utf_view<format::utf32, V>{std::move(base)}
{}
};
#if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
template<class R>
utf8_view(R &&) -> utf8_view<std::views::all_t<R>>;
template<class R>
utf16_view(R &&) -> utf16_view<std::views::all_t<R>>;
template<class R>
utf32_view(R &&) -> utf32_view<std::views::all_t<R>>;
#endif
#endif
/** A view adaptor that produces a `utf8_view` of the given view. */
inline constexpr auto as_utf8 = detail::text::as_utf8;
/** A view adaptor that produces a `utf16_view` of the given view. */
inline constexpr auto as_utf16 = detail::text::as_utf16;
/** A view adaptor that produces a `utf32_view` of the given view. */
inline constexpr auto as_utf32 = detail::text::as_utf32;
}
#endif

View File

@@ -1,848 +0,0 @@
#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) && \
(!defined(__GNUC__) || 12 <= __GNUC__ || !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::declval<I &>(),
std::declval<S>(),
std::declval<
parse_context<false, false, 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.
In addition to the template parameter constraints, `F` must be
invocable with the attribute type of `Parser`; `V` and the range type
produced by `F`, "`Rf`" must be ranges of `char`, or must have the
same UTF format; and `V` and `Rf` must meet the same compatibility
requirements as described in `std::ranges::join_view`. */
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

View File

@@ -1,346 +0,0 @@
// Copyright (C) 2020 T. Zachary Laine
// Copyright Louis Dionne 2013-2017
//
// 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_TUPLE_HPP
#define BOOST_PARSER_TUPLE_HPP
#include <boost/parser/config.hpp>
#include <boost/parser/detail/detection.hpp>
#if BOOST_PARSER_USE_STD_TUPLE
#include <tuple>
#else
// Silence very verbose warnings about std::is_pod/std::is_literal being
// deprecated.
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# pragma GCC diagnostic ignored "-Wunused-value"
#endif
#include <boost/hana.hpp>
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
#endif
#endif
namespace boost { namespace parser {
namespace detail {
// to_int() and parse_llong() taken from boost/hana/bool.hpp.
constexpr int to_int(char c)
{
int result = 0;
if (c >= 'A' && c <= 'F') {
result = static_cast<int>(c) - static_cast<int>('A') + 10;
} else if (c >= 'a' && c <= 'f') {
result = static_cast<int>(c) - static_cast<int>('a') + 10;
} else {
result = static_cast<int>(c) - static_cast<int>('0');
}
return result;
}
template<std::size_t N>
constexpr long long parse_llong(const char (&arr)[N])
{
long long base = 10;
std::size_t offset = 0;
if constexpr (N > 2) {
bool starts_with_zero = arr[0] == '0';
bool is_hex = starts_with_zero && arr[1] == 'x';
bool is_binary = starts_with_zero && arr[1] == 'b';
if (is_hex) {
// 0xDEADBEEF (hexadecimal)
base = 16;
offset = 2;
} else if (is_binary) {
// 0b101011101 (binary)
base = 2;
offset = 2;
} else if (starts_with_zero) {
// 012345 (octal)
base = 8;
offset = 1;
}
}
long long number = 0;
long long multiplier = 1;
for (std::size_t i = 0; i < N - offset; ++i) {
char c = arr[N - 1 - i];
if (c != '\'') { // skip digit separators
number += to_int(c) * multiplier;
multiplier *= base;
}
}
return number;
}
}
/** The tuple template alias used within Boost.Parser. This will be
`boost::hana::tuple` unless `BOOST_PARSER_DISABLE_HANA_TUPLE` is
defined, in which case it is `std::tuple`. */
#if BOOST_PARSER_USE_STD_TUPLE
template<typename... Args>
using tuple = std::tuple<Args...>;
#else
template<typename... Args>
using tuple = hana::tuple<Args...>;
#endif
/** A template alias that is `boost::hana::integral_constant<T, I>` unless
`BOOST_PARSER_DISABLE_HANA_TUPLE` is defined, in which case it is
`std::integral_constant<T, I>`. */
#if BOOST_PARSER_USE_STD_TUPLE
template<typename T, T I>
using integral_constant = std::integral_constant<T, I>;
#else
template<typename T, T I>
using integral_constant = hana::integral_constant<T, I>;
#endif
/** An accessor that returns a reference to the `I`-th data member of an
aggregate struct or `boost::parser::tuple`. */
template<typename T, typename U, U I>
constexpr decltype(auto) get(T && x, integral_constant<U, I> i);
/** A template alias that is `boost::hana::llong<I>` unless
`BOOST_PARSER_DISABLE_HANA_TUPLE` is defined, in which case it is
`std::integral_constant<long long, I>`. */
template<long long I>
using llong = integral_constant<long long, I>;
namespace literals {
/** A literal that can be used to concisely name `parser::llong`
integral constants. */
template<char... chars>
constexpr auto operator"" _c()
{
constexpr long long n =
detail::parse_llong<sizeof...(chars)>({chars...});
return llong<n>{};
}
}
namespace detail {
/** A tuple accessor that returns a reference to the `I`-th element. */
template<typename T, T I, typename... Args>
constexpr decltype(auto)
tuple_get(tuple<Args...> const & t, integral_constant<T, I>)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::get<I>(t);
#else
return hana::at_c<I>(t);
#endif
}
/** A tuple accessor that returns a reference to the `I`-th element. */
template<typename T, T I, typename... Args>
constexpr decltype(auto)
tuple_get(tuple<Args...> & t, integral_constant<T, I>)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::get<I>(t);
#else
return hana::at_c<I>(t);
#endif
}
/** A tuple accessor that returns a reference to the `I`-th element. */
template<typename T, T I, typename... Args>
constexpr decltype(auto)
tuple_get(tuple<Args...> && t, integral_constant<T, I>)
{
#if BOOST_PARSER_USE_STD_TUPLE
return std::move(std::get<I>(t));
#else
return std::move(hana::at_c<I>(t));
#endif
}
template<int N>
struct ce_int
{
constexpr static int value = N;
};
struct whatever
{
int _;
template<typename T>
operator T() const && noexcept
{
#if defined(__GNUC__) && __GNUC__ < 13
// Yuck.
std::remove_reference_t<T> * ptr = nullptr;
ptr += 1; // warning mitigation
return *ptr;
#else
return std::declval<T>();
#endif
}
};
template<typename T, int... Is>
constexpr auto
constructible_expr_impl(std::integer_sequence<int, Is...>)
-> decltype(T{whatever{Is}...}, ce_int<1>{});
template<typename T, typename N>
using constructible_expr = decltype(detail::constructible_expr_impl<T>(
std::make_integer_sequence<int, N::value>()));
template<typename T, int... Is>
constexpr int struct_arity_impl(std::integer_sequence<int, Is...>)
{
return (
detected_or_t<ce_int<0>, constructible_expr, T, ce_int<Is>>::
value +
... + 0);
}
// This often mistakenly returns 1 when you give it a struct with
// private/protected members, because of copy/move construction.
// Fortunately, we don't care -- we never assign from tuples of size
// 1.
template<typename T>
constexpr int struct_arity_v =
detail::struct_arity_impl<T>(std::make_integer_sequence<
int,
BOOST_PARSER_MAX_AGGREGATE_SIZE>()) -
1;
template<typename T>
constexpr int tuple_size_ = -1;
template<typename... Elems>
constexpr int tuple_size_<tuple<Elems...>> = sizeof...(Elems);
template<typename T, typename Tuple, int... Is>
auto assign_tuple_to_aggregate(
T & x, Tuple tup, std::integer_sequence<int, Is...>)
-> decltype(x = T{parser::get(std::move(tup), llong<Is>{})...});
template<typename T, typename Tuple, int... Is>
auto tuple_to_aggregate(Tuple && tup, std::integer_sequence<int, Is...>)
-> decltype(T{std::move(parser::get(tup, llong<Is>{}))...})
{
return T{std::move(parser::get(tup, llong<Is>{}))...};
}
template<typename T, typename Tuple>
using tuple_to_aggregate_expr =
decltype(detail::assign_tuple_to_aggregate(
std::declval<T &>(),
std::declval<Tuple>(),
std::make_integer_sequence<int, tuple_size_<Tuple>>()));
template<typename Struct, typename Tuple>
constexpr bool is_struct_assignable_v =
struct_arity_v<Struct> == tuple_size_<Tuple>
? is_detected_v<tuple_to_aggregate_expr, Struct, Tuple>
: false;
template<int N>
struct tie_aggregate_impl
{
template<typename T>
static constexpr auto call(T & x)
{
static_assert(
sizeof(T) && false,
"It looks like you're trying to use a struct larger than "
"the limit.");
}
};
template<typename T>
constexpr auto tie_aggregate(T & x)
{
static_assert(!std::is_union_v<T>);
return tie_aggregate_impl<struct_arity_v<T>>::call(x);
}
template<typename Tuple, typename Tie, int... Is>
auto aggregate_to_tuple(
Tuple & tup, Tie tie, std::integer_sequence<int, Is...>)
-> decltype((
(parser::get(tup, llong<Is>{}) =
std::move(parser::get(tie, llong<Is>{}))),
...,
(void)0))
{
return (
(parser::get(tup, llong<Is>{}) =
std::move(parser::get(tie, llong<Is>{}))),
...,
(void)0);
}
template<typename Tuple, typename T>
using aggregate_to_tuple_expr = decltype(detail::aggregate_to_tuple(
std::declval<Tuple &>(),
detail::tie_aggregate(std::declval<T &>()),
std::make_integer_sequence<int, tuple_size_<Tuple>>()));
template<typename Tuple, typename Struct>
constexpr bool is_tuple_assignable_impl()
{
if constexpr (
std::is_aggregate_v<Struct> &&
struct_arity_v<Struct> == tuple_size_<Tuple>) {
return is_detected_v<aggregate_to_tuple_expr, Tuple, Struct>;
} else {
return false;
}
}
template<typename Tuple, typename Struct>
constexpr bool
is_tuple_assignable_v = is_tuple_assignable_impl<Tuple, Struct>();
template<typename T>
struct is_tuple : std::false_type
{};
template<typename... T>
struct is_tuple<tuple<T...>> : std::true_type
{};
}
template<typename T, typename U, U I>
constexpr decltype(auto) get(T && x, integral_constant<U, I> i)
{
using just_t = std::decay_t<T>;
if constexpr (detail::is_tuple<just_t>::value) {
return detail::tuple_get((T &&) x, i);
} else if constexpr (std::is_aggregate_v<just_t>) {
auto tup = detail::tie_aggregate(x);
return detail::tuple_get(tup, i);
} else {
static_assert(
sizeof(T) != sizeof(T),
"boost::parser::get() is only defined for boost::parser::tuple "
"and aggregate structs.");
}
}
}}
#include <boost/parser/detail/aggr_to_tuple_generated.hpp>
#endif

View File

@@ -4,7 +4,7 @@ include(CTest)
enable_testing()
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -j4 -C ${CMAKE_CFG_INTDIR})
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -j4 -C ${CMAKE_CFG_INTDIR})
##################################################
# Parser tests
@@ -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 /bigobj)
target_compile_options(parser_ PRIVATE /source-charset:utf-8)
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 /bigobj)
target_compile_options(parser_api PRIVATE /source-charset:utf-8)
endif ()
add_test(NAME parser_api COMMAND parser_api ---gtest_catch_exceptions=1)
@@ -41,20 +41,13 @@ 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 /bigobj)
target_compile_options(${name} PRIVATE /source-charset:utf-8)
endif ()
add_test(NAME ${name} COMMAND ${name} --gtest_catch_exceptions=1)
endmacro()
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_perm)
add_test_executable(parser_attributes)
add_test_executable(parser_lazy_params)
add_test_executable(parser_if_switch)
add_test_executable(parser_rule)
@@ -65,12 +58,6 @@ 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)
add_test_executable(parser_seq_permutations_1)
add_test_executable(parser_seq_permutations_2)
add_test_executable(parser_or_permutations_1)
add_test_executable(parser_or_permutations_2)

View File

@@ -1,104 +0,0 @@
/**
* 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]>>);
}

View File

@@ -1,908 +0,0 @@
/**
* 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}));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -20,11 +20,6 @@ void compile_or_attribute()
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<int>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<int>>);
}
// scalar | scalar
@@ -32,33 +27,18 @@ void compile_or_attribute()
constexpr auto parser = char_ | char_;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(std::is_same_v<attr_t, std::optional<char>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
char>);
}
{
constexpr auto parser = char_ | char_ | eps;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<char>>);
}
{
constexpr auto parser = int_ | char_;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::variant<int, char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::variant<int, char>>);
}
{
constexpr auto parser = int_ | char_ | eps;
@@ -66,11 +46,6 @@ void compile_or_attribute()
static_assert(std::is_same_v<
attr_t,
std::optional<std::optional<std::variant<int, char>>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<std::variant<int, char>>>);
}
// -scalar | -scalar
@@ -79,22 +54,12 @@ void compile_or_attribute()
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<char>>);
}
{
constexpr auto parser = -char_ | -char_ | eps;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<char>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<char>>);
}
{
constexpr auto parser = -int_ | -char_;
@@ -104,11 +69,6 @@ void compile_or_attribute()
attr_t,
std::optional<
std::variant<std::optional<int>, std::optional<char>>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::variant<std::optional<int>, std::optional<char>>>);
}
{
constexpr auto parser = -int_ | -char_ | eps;
@@ -118,13 +78,6 @@ void compile_or_attribute()
attr_t,
std::optional<std::optional<
std::variant<std::optional<int>, std::optional<char>>>>>);
static_assert(
std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<
std::variant<std::optional<int>, std::optional<char>>>>);
}
// seq<T> | seq<T>
@@ -132,33 +85,18 @@ void compile_or_attribute()
constexpr auto parser = *char_ | *char_;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(std::is_same_v<attr_t, std::optional<std::string>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::string>);
}
{
constexpr auto parser = *char_ | *char_ | eps;
using attr_t = decltype(prefix_parse(first, last, parser));
static_assert(
std::is_same_v<attr_t, std::optional<std::optional<std::string>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<std::string>>);
}
{
constexpr auto parser = *string("str") | *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>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::vector<std::string>>);
}
{
constexpr auto parser = *string("str") | *string("str") | eps;
@@ -166,11 +104,6 @@ void compile_or_attribute()
static_assert(std::is_same_v<
attr_t,
std::optional<std::optional<std::vector<std::string>>>>);
static_assert(std::is_same_v<
attribute_t<
decltype(BOOST_PARSER_SUBRANGE(first, last)),
decltype(parser)>,
std::optional<std::vector<std::string>>>);
}
// seq<T> | seq<U>

View File

@@ -213,18 +213,6 @@ 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));

View File

@@ -208,7 +208,8 @@ TEST(merge_separate, merge_)
*result, detail::hl::make_tuple('z', std::string("abcdefghi")));
}
}
#if 0 // Intentionally ill-formed.
#if 0 // TODO: Document that this does not work, and why (flattening), and how
// making a rule for the parethesized part is a fix.
{
constexpr auto parser =
char_ >> merge[(string("abc") >> char_ >> char_) >> string("ghi")];

View File

@@ -23,9 +23,6 @@ TEST(no_case, doc_example)
auto const alpha_parser = bp::no_case[bp::char_('a', 'z')];
assert(bp::parse("a" | bp::as_utf32, bp::no_case[alpha_parser])); // Match!
assert(bp::parse("B" | bp::as_utf32, bp::no_case[alpha_parser])); // Match!
(void)street_parser;
(void)alpha_parser;
}
@@ -128,10 +125,9 @@ 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_FALSE(result);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 's');
}
{
auto const result = parse(U"S", _trasse_p);
@@ -140,7 +136,8 @@ TEST(no_case, match_any_within_string)
}
{
auto const result = parse("S", _trasse_p);
EXPECT_FALSE(result);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'S');
}
{
auto const result = parse(U"t", _trasse_p);
@@ -162,101 +159,6 @@ TEST(no_case, match_any_within_string)
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'T');
}
{
auto const result = parse("X", _trasse_p);
EXPECT_FALSE(result);
}
}
TEST(no_case, symbol_table)
{
// without mutation
{
symbols<int> const roman_numerals = {
{"I", 1}, {"V", 5}, {"X", 10}, {"L", 50}, {"C", 100}};
symbols<std::string> const named_strings = {
{"I", "1"}, {"V", "5"}, {"X", "10"}, {"L", "50"}, {"C", "100"}};
{
auto const result = parse("I", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 1);
}
{
auto const result = parse("i", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 1);
}
{
auto const result = parse("I", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "1");
}
{
auto const result = parse("i", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "1");
}
{
auto const result = parse("L", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
}
{
auto const result = parse("l", no_case[roman_numerals]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
}
{
auto const result = parse("L", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "50");
}
{
auto const result = parse("l", no_case[named_strings]);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "50");
}
}
// with mutation
{
symbols<int> roman_numerals;
roman_numerals.insert_for_next_parse("I", 1)("V", 5)("X", 10);
auto const add_numeral = [&roman_numerals](auto & context) {
using namespace boost::parser::literals;
char chars[2] = {get(_attr(context), 0_c), 0};
roman_numerals.insert(context, chars, get(_attr(context), 1_c));
};
auto const numerals_parser = omit[roman_numerals] >>
(char_ >> int_)[add_numeral] >>
no_case[roman_numerals];
{
auto const result = parse("VL50L", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
EXPECT_FALSE(parse("L", roman_numerals));
}
{
auto const result = parse("VL50l", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 50);
EXPECT_FALSE(parse("L", roman_numerals));
}
{
auto const result = parse("VC100C", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 100);
EXPECT_FALSE(parse("C", roman_numerals));
}
{
auto const result = parse("Vc100C", numerals_parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 100);
EXPECT_FALSE(parse("C", roman_numerals));
}
}
}
constexpr auto capital_sharp_s = u8""; // U+1E9E
@@ -384,7 +286,7 @@ TEST(no_case, detail_no_case_iter)
auto first =
detail::no_case_iter(mixed_sharp_s1, detail::text::null_sentinel);
while (first != detail::text::null_sentinel) {
folded.push_back((char)*first);
folded.push_back(*first);
++first;
}
EXPECT_EQ(folded, "sss");
@@ -396,57 +298,12 @@ TEST(no_case, detail_no_case_iter)
auto first =
detail::no_case_iter(mixed_sharp_s2, detail::text::null_sentinel);
while (first != detail::text::null_sentinel) {
folded.push_back((char)*first);
folded.push_back(*first);
++first;
}
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((char)*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)

View File

@@ -1,199 +0,0 @@
/**
* 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/config.hpp>
#if !BOOST_PARSER_USE_STD_TUPLE
#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);
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -14,29 +14,31 @@ constexpr rule<struct abc_def_tag, std::string> abc_def = "abc or def";
constexpr auto abc_def_def = string("abc") | string("def");
BOOST_PARSER_DEFINE_RULES(abc_def);
auto const fail = [](auto & ctx) { _pass(ctx) = false; };
auto const fail = [](auto & context) { _pass(context) = false; };
constexpr rule<struct fail_abc_pass_def_tag, std::string> fail_abc_pass_def =
"abc";
constexpr auto fail_abc_pass_def_def = string("abc")[fail] | string("def");
BOOST_PARSER_DEFINE_RULES(fail_abc_pass_def);
auto const attr_to_val = [](auto & ctx) { _val(ctx) = _attr(ctx); };
auto const attr_to_val = [](auto & context) { _val(context) = _attr(context); };
constexpr rule<struct action_copy_abc_def_tag, std::string>
action_copy_abc_def = "abc or def";
constexpr auto action_copy_abc_def_def =
string("abc")[attr_to_val] | string("def")[attr_to_val];
BOOST_PARSER_DEFINE_RULES(action_copy_abc_def);
auto const abc_value = [](auto & ctx) { _val(ctx) = "abc"; };
auto const def_value = [](auto & ctx) { _val(ctx) = "def"; };
auto const abc_value = [](auto & context) { _val(context) = "abc"; };
auto const def_value = [](auto & context) { _val(context) = "def"; };
constexpr rule<struct rev_abc_def_tag, std::string> rev_abc_def = "abc or def";
constexpr auto rev_abc_def_def =
string("abc")[def_value] | string("def")[abc_value];
BOOST_PARSER_DEFINE_RULES(rev_abc_def);
auto const append_attr = [](auto & ctx) { _locals(ctx) += _attr(ctx); };
auto const locals_to_val = [](auto & ctx) {
_val(ctx) = std::move(_locals(ctx));
auto const append_attr = [](auto & context) {
_locals(context) += _attr(context);
};
auto const locals_to_val = [](auto & context) {
_val(context) = std::move(_locals(context));
};
rule<struct locals_abc_def_tag, std::string, std::string> const locals_abc_def =
"abc or def";
@@ -44,10 +46,10 @@ auto locals_abc_def_def = -string("abc")[append_attr] >>
-string("def")[append_attr] >> eps[locals_to_val];
BOOST_PARSER_DEFINE_RULES(locals_abc_def);
TEST(action, side_effects)
TEST(parser, side_effects)
{
int i = 0;
auto increment_i = [&i](auto & ctx) { ++i; };
auto increment_i = [&i](auto & context) { ++i; };
using no_attribute_return = decltype(parse("xyz", char_('a')[increment_i]));
static_assert(std::is_same_v<no_attribute_return, bool>);
@@ -73,7 +75,7 @@ TEST(action, side_effects)
}
}
TEST(action, pass)
TEST(parser, pass)
{
{
std::string const str = "xyz";
@@ -105,7 +107,7 @@ TEST(action, pass)
}
}
TEST(action, val_attr)
TEST(parser, val_attr)
{
{
std::string const str = "abc";
@@ -133,7 +135,7 @@ TEST(action, val_attr)
}
}
TEST(action, locals)
TEST(parser, locals)
{
{
std::string const str = "";
@@ -160,60 +162,3 @@ TEST(action, locals)
EXPECT_EQ(*result, "def");
}
}
auto drop_result = [](auto & ctx) {};
auto auto_assign = [](auto & ctx) { return _attr(ctx); };
auto auto_assign_multi_string_1 = [](std::string const & str1,
std::string const & str2) {
return str1 + str2;
};
auto auto_assign_multi_string_2 = [](std::string && str1, std::string && str2) {
return str1 + str2;
};
constexpr rule<struct str_rule_1_tag, std::string> str_rule_1 = "str_rule_1";
constexpr auto str_rule_1_def = +char_;
BOOST_PARSER_DEFINE_RULES(str_rule_1);
constexpr rule<struct str_rule_2_tag, std::string> str_rule_2 = "str_rule_2";
constexpr auto str_rule_2_def = (+char_)[drop_result];
BOOST_PARSER_DEFINE_RULES(str_rule_2);
constexpr rule<struct str_rule_3_tag, std::string> str_rule_3 = "str_rule_3";
constexpr auto str_rule_3_def = (+char_)[auto_assign];
BOOST_PARSER_DEFINE_RULES(str_rule_3);
constexpr rule<struct str_rule_6_tag, std::string> str_rule_6 = "str_rule_6";
constexpr auto str_rule_6_def =
(+(char_ - ' ') >> ' ' >> +char_)[auto_assign_multi_string_1];
BOOST_PARSER_DEFINE_RULES(str_rule_6);
constexpr rule<struct str_rule_7_tag, std::string> str_rule_7 = "str_rule_7";
constexpr auto str_rule_7_def =
(+(char_ - ' ') >> ' ' >> +char_)[auto_assign_multi_string_2];
BOOST_PARSER_DEFINE_RULES(str_rule_7);
TEST(action, alternate_invocables)
{
{
auto result_1 = parse("some text", str_rule_1);
EXPECT_TRUE(result_1);
EXPECT_EQ(*result_1, "some text");
auto result_2 = parse("some text", str_rule_2);
EXPECT_TRUE(result_2);
EXPECT_EQ(*result_2, "");
auto result_3 = parse("some text", str_rule_3);
EXPECT_TRUE(result_3);
EXPECT_EQ(*result_3, "some text");
auto result_6 = parse("some text", str_rule_6);
EXPECT_TRUE(result_6);
EXPECT_EQ(*result_6, "sometext");
auto result_7 = parse("some text", str_rule_7);
EXPECT_TRUE(result_7);
EXPECT_EQ(*result_7, "sometext");
}
}

View File

@@ -15,7 +15,7 @@ auto make_13 = [](auto & context) { return 13; };
auto const first_param_to_val = [](auto & context) {
using namespace boost::parser::literals;
_val(context) = (int)get(_params(context), 0_c);
_val(context) = get(_params(context), 0_c);
};
auto const second_param_to_val = [](auto & context) {
using namespace boost::parser::literals;

View File

@@ -22,13 +22,15 @@ 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_RULES(callback_char_rule);
BOOST_PARSER_DEFINE_RULE(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
@@ -109,38 +111,36 @@ TEST(parser, full_parse_api)
first,
boost::parser::detail::text::null_sentinel,
char_,
ws,
skip_ws,
out));
first = str.c_str();
EXPECT_EQ(out, 'a');
out = 0;
first = str.c_str();
auto ws_copy = ws;
EXPECT_FALSE(prefix_parse(
first,
boost::parser::detail::text::null_sentinel,
char_('b'),
ws_copy,
skip_ws,
out));
EXPECT_EQ(out, 0);
}
// attr out param, using skipper, range
{
char out = 0;
EXPECT_TRUE(parse(str, char_, ws, out));
EXPECT_TRUE(parse(str, char_, skip_ws, out));
EXPECT_EQ(out, 'a');
out = 0;
EXPECT_FALSE(parse(str, char_('b'), ws, out));
EXPECT_FALSE(parse(str, char_('b'), skip_ws, out));
EXPECT_EQ(out, 0);
}
// attr out param, using skipper, pointer-as-range
{
char out = 0;
EXPECT_TRUE(parse(str.c_str(), char_, ws, out));
EXPECT_TRUE(parse(str.c_str(), char_, skip_ws, out));
EXPECT_EQ(out, 'a');
out = 0;
auto ws_copy = ws;
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws_copy, out));
EXPECT_FALSE(parse(str.c_str(), char_('b'), skip_ws, out));
EXPECT_EQ(out, 0);
}
@@ -148,35 +148,33 @@ TEST(parser, full_parse_api)
{
auto first = str.c_str();
EXPECT_TRUE(prefix_parse(
first, boost::parser::detail::text::null_sentinel, char_, ws));
first, boost::parser::detail::text::null_sentinel, char_, skip_ws));
first = str.c_str();
EXPECT_EQ(
*prefix_parse(
first,
boost::parser::detail::text::null_sentinel,
char_,
ws),
skip_ws),
'a');
first = str.c_str();
auto ws_copy = ws;
EXPECT_TRUE(!prefix_parse(
first,
boost::parser::detail::text::null_sentinel,
char_('b'),
ws_copy));
skip_ws));
}
// returned attr, using skipper, range
{
EXPECT_TRUE(parse(str, char_, ws));
EXPECT_EQ(*parse(str, char_, ws), 'a');
EXPECT_FALSE(parse(str, char_('b'), ws));
EXPECT_TRUE(parse(str, char_, skip_ws));
EXPECT_EQ(*parse(str, char_, skip_ws), 'a');
EXPECT_FALSE(parse(str, char_('b'), skip_ws));
}
// returned attr, using skipper, pointer-as-range
{
EXPECT_TRUE(parse(str.c_str(), char_, ws));
EXPECT_EQ(*parse(str.c_str(), char_, ws), 'a');
auto ws_copy = ws;
EXPECT_FALSE(parse(str.c_str(), char_('b'), ws_copy));
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));
}
// callback, iter/sent
@@ -216,21 +214,7 @@ TEST(parser, full_parse_api)
first,
boost::parser::detail::text::null_sentinel,
callback_char_rule,
ws,
callbacks));
first = str.c_str();
EXPECT_EQ(out, 'a');
}
{
char out = 0;
auto callbacks = [&out](auto tag, auto x) { out = x; };
auto first = str.c_str();
auto ws_copy = ws;
EXPECT_TRUE(callback_prefix_parse(
first,
boost::parser::detail::text::null_sentinel,
callback_char_rule,
ws_copy,
skip_ws,
callbacks));
first = str.c_str();
EXPECT_EQ(out, 'a');
@@ -240,16 +224,15 @@ 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, ws, callbacks));
callback_parse(str, callback_char_rule, skip_ws, callbacks));
EXPECT_EQ(out, 'a');
}
// callback, using skipper, pointer-as-range
{
char out = 0;
auto callbacks = [&out](auto tag, auto x) { out = x; };
auto ws_copy = ws;
EXPECT_TRUE(callback_parse(
str.c_str(), callback_char_rule, ws_copy, callbacks));
str.c_str(), callback_char_rule, skip_ws, callbacks));
EXPECT_EQ(out, 'a');
}
}
@@ -299,8 +282,10 @@ TEST(parser, basic)
}
{
char const * str = " ";
EXPECT_TRUE(parse(str, blank));
EXPECT_FALSE(parse(str, lower));
char c = '\0';
EXPECT_TRUE(parse(str, ascii::blank, c));
EXPECT_EQ(c, ' ');
EXPECT_FALSE(parse(str, ascii::lower));
}
{
char const * str = "ab";
@@ -490,7 +475,7 @@ TEST(parser, uint_)
char const * str = "-42";
unsigned int i = 3;
EXPECT_FALSE(parse(str, uint_, i));
EXPECT_EQ(i, 0);
EXPECT_EQ(i, 3);
}
{
char const * str = "42";
@@ -1816,7 +1801,11 @@ TEST(parser, combined_seq_and_or)
{
char const * str = "abc";
tuple<std::any, std::any, std::any> chars;
tuple<
boost::parser::detail::any_copyable,
boost::parser::detail::any_copyable,
boost::parser::detail::any_copyable>
chars;
EXPECT_TRUE(parse(str, parser, chars));
}
@@ -1994,7 +1983,6 @@ TEST(parser, attr_out_param_compat)
using namespace bp::literals;
assert(success);
(void)success;
assert(bp::get(result, 0_c) == std::vector<int>({'r', U'ô', 'l', 'e'}));
assert(bp::get(result, 1_c) == "foo");
}
@@ -2012,18 +2000,8 @@ TEST(parser, attr_out_param_compat)
using namespace bp::literals;
assert(success);
(void)success;
// The 4 code points "rôle" get transcoded to 5 UTF-8 code points to fit in the std::string.
assert(bp::get(result, 0_c) == std::vector<char>({'r', (char)0xc3, (char)0xb4, 'l', 'e'}));
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());
}

View File

@@ -1,67 +0,0 @@
/**
* 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>
namespace bp = boost::parser;
bp::rule<struct seq1_tag, bp::tuple<int, char>> seq1 = "";
bp::rule<struct seq2_tag, bp::tuple<int, char>> seq2 = "";
auto const seq1_def = bp::int_ >> bp::char_('a');
auto const seq2_def = bp::int_ >> bp::char_('b');
BOOST_PARSER_DEFINE_RULES(seq1, seq2);
TEST(attributes, internal_errors_munging_attributes)
{
// These are just some assorted cases that have, or seemed likely to,
// cause problems when an internal failure in an alternative wipes out an
// existing result. This covers all the cases where "if (!success)"
// causes the attribute to be overwritten with a default-constructed
// value.
{
auto const parser =
bp::string("FOO") >> -(bp::string("bar") | bp::string("foo"));
auto result = bp::parse("FOOfoo", parser);
EXPECT_TRUE(result);
EXPECT_EQ(bp::get(*result, bp::llong<0>{}), std::string("FOO"));
EXPECT_EQ(bp::get(*result, bp::llong<1>{}), std::string("foo"));
}
{
auto const parser = bp::merge
[bp::string("FOO") >> (bp::string("bar") | bp::string("foo"))];
auto result = bp::parse("FOOfoo", parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::string("FOOfoo"));
}
{
auto const parser = bp::merge
[(bp::attr(std::vector<std::string>({"FOO"})) | bp::eps) >>
(bp::repeat(1)[bp::string("foo")] | bp::eps)];
auto result = bp::parse("", parser);
EXPECT_TRUE(result);
EXPECT_TRUE(*result);
EXPECT_EQ(*result, std::vector<std::string>({"FOO"}));
}
{
auto const parser = bp::merge[seq1 >> (seq2 | seq1)];
auto result = bp::parse("7a9a", parser);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, char>(9, 'a')));
}
}

View File

@@ -1,338 +0,0 @@
/**
* 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>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 |/>> P2), -(P0 |/>> P1), (-P0 |/>> P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, or_parser_permutations_1)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P0
{
auto result = bp::parse("foo", bp::string("foo") | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("bar", bp::string("foo") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result = bp::parse("42", bp::string("foo") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("c", bp::string("foo") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse("foo", bp::string("foo") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional("foo"s));
}
{
auto result = bp::parse("foo", bp::string("foo") | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "foo"s);
}
{
auto result = bp::parse("", bp::string("foo") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo", bp::string("foo") | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "foo"s);
}
{
auto result = bp::parse(
"bar",
bp::string("foo") | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "bar"s);
}
{
auto result = bp::parse(
"", bp::string("foo") | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo", bp::string("foo") | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "foo"s);
}
{
auto result = bp::parse(
"", bp::string("foo") | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
(std::get<std::optional<bp::tuple<std::string, std::string>>>(
*result)),
std::nullopt);
}
{
auto result = bp::parse(
"bar",
bp::string("foo") | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
(std::get<bp::tuple<std::optional<std::string>, std::string>>(
*result)),
(make::tuple(std::optional<std::string>{}, "bar"s)));
}
// -P0
{
auto result = bp::parse("foo", -bp::string("foo") | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("foo"s));
}
{
auto result = bp::parse("", -bp::string("foo") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse("", -bp::string("foo") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse("", -bp::string("foo") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse("foo", -bp::string("foo") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("foo", -bp::string("foo") | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse("foo", -bp::string("foo") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result =
bp::parse("", -bp::string("foo") | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo",
-bp::string("foo") | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse(
"", -bp::string("foo") | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result = bp::parse(
"foo", -bp::string("foo") | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse(
"foo",
-bp::string("foo") | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse(
"foo",
-bp::string("foo") | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
// *P0
{
auto result = bp::parse(
"foo", bp::lexeme[*bp::string("foo")] | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result), std::vector({"foo"s}));
}
{
auto result =
bp::parse("foofoo", *bp::string("foo") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("", *bp::string("foo") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector<std::string>{});
}
{
auto result = bp::parse("", *bp::string("foo") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector<std::string>{});
}
{
auto result = bp::parse("foofoo", *bp::string("foo") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional(std::vector({"foo"s, "foo"s})));
}
{
auto result = bp::parse(
"foofoo", bp::lexeme[*bp::string("foo")] | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result =
bp::parse("foofoo", *bp::string("foo") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
-(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
(-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
-(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse(
"foofoo",
bp::lexeme[*bp::string("foo")] |
(-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
}

View File

@@ -1,312 +0,0 @@
/**
* 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>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, or_parser_permutations_2)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P1
{
auto result = bp::parse("foo", bp::string("bar") | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("bar", bp::string("bar") | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result = bp::parse("42", bp::string("bar") | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("bar", bp::string("bar") | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse("", bp::string("bar") | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::nullopt);
}
{
auto result =
bp::parse("foofoo", bp::string("bar") | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("bar", bp::string("bar") | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result =
bp::parse("42", bp::string("bar") | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"bar",
bp::string("foo") | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "bar"s);
}
{
auto result = bp::parse(
"foo",
bp::string("bar") | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), "foo"s);
}
{
auto result = bp::parse(
"bar", bp::string("bar") | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse(
"bar",
bp::string("bar") | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse(
"bar",
bp::string("bar") | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
// P2
{
auto result = bp::parse("42", bp::int_ | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("bar", bp::int_ | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse("42", bp::int_ | bp::int_, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 42);
}
{
auto result = bp::parse("c", bp::int_ | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse("", bp::int_ | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::nullopt);
}
{
auto result = bp::parse("foofoo", bp::int_ | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("42", bp::int_ | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result =
bp::parse("42", bp::int_ | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"bar", bp::int_ | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("bar"s));
}
{
auto result =
bp::parse("", bp::int_ | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::optional<std::string>>(*result), std::nullopt);
}
{
auto result =
bp::parse("42", bp::int_ | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"42", bp::int_ | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"42", bp::int_ | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<int>(*result), 42);
}
// P3
{
auto result = bp::parse("c", bp::char_('c') | bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse("bar", bp::char_('c') | bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<std::string>(*result), "bar"s);
}
{
auto result = bp::parse("42", bp::char_('c') | bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse("c", bp::char_('c') | bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result = bp::parse("c", bp::char_('c') | bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result = bp::parse("foofoo", bp::char_('c') | *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::vector<std::string>>(*result),
std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("c", bp::char_('c') | -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result =
bp::parse("42", bp::char_('c') | (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 2u);
EXPECT_EQ(std::get<int>(*result), 42);
}
{
auto result = bp::parse(
"bar", bp::char_('c') | -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("bar"s));
}
{
auto result = bp::parse(
"foo", bp::char_('c') | (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
std::get<std::optional<std::string>>(*result),
std::optional("foo"s));
}
{
auto result = bp::parse(
"foo42", bp::char_('c') | (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 1u);
EXPECT_EQ(
(std::get<bp::tuple<std::string, int>>(*result)),
(make::tuple("foo"s, 42)));
}
{
auto result = bp::parse(
"c", bp::char_('c') | -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
{
auto result = bp::parse(
"c", bp::char_('c') | (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(result->index(), 0);
EXPECT_EQ(std::get<char>(*result), 'c');
}
// eps | ... prohibited.
}

View File

@@ -1,90 +0,0 @@
/**
* 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>
namespace bp = boost::parser;
using namespace std::literals;
TEST(permutation_parser, basic)
{
{
constexpr auto parser = bp::int_ || bp::string("foo");
{
auto result = bp::parse("42 foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
{
auto result = bp::parse("42foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
{
auto result = bp::parse("foo 42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
{
auto result = bp::parse("foo42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (bp::tuple<int, std::string>(42, "foo"s)));
}
}
{
constexpr auto parser = bp::int_ || bp::string("foo") || bp::char_('g');
{
auto result = bp::parse("42 foo g", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("42 g foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("foo 42 g", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("foo g 42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("g foo 42", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
{
auto result = bp::parse("g 42 foo", parser, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(bp::tuple<int, std::string, double>(42, "foo"s, 'g')));
}
}
}

View File

@@ -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_RULES(flat_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(recursive_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(flat_string_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(recursive_string_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(flat_vector_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(callback_vector_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(callback_void_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(recursive_strings_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(value);
BOOST_PARSER_DEFINE_RULE(value);
}
namespace more_about_rules_2 {
@@ -557,85 +557,3 @@ namespace more_about_rules_4 {
return bp::parse(str, bp::omit[parens], bp::ws);
}
}
// clang-format off
namespace param_example {
//[ extended_param_yaml_example_rules
namespace bp = boost::parser;
// A type to represent the YAML parse context.
enum class context {
block_in,
block_out,
block_key,
flow_in,
flow_out,
flow_key
};
// A YAML value; no need to fill it in for this example.
struct value
{
// ...
};
// YAML [66], just stubbed in here.
auto const s_separate_in_line = bp::eps;
// YAML [137].
bp::rule<struct c_flow_seq_tag, value> c_flow_sequence = "c-flow-sequence";
// YAML [80].
bp::rule<struct s_separate_tag> s_separate = "s-separate";
// YAML [136].
bp::rule<struct in_flow_tag, value> in_flow = "in-flow";
// YAML [138]; just eps below.
bp::rule<struct ns_s_flow_seq_entries_tag, value> ns_s_flow_seq_entries =
"ns-s-flow-seq-entries";
// YAML [81]; just eps below.
bp::rule<struct s_separate_lines_tag> s_separate_lines = "s-separate-lines";
// Parser for YAML [137].
auto const c_flow_sequence_def =
'[' >>
-s_separate.with(bp::_p<0>, bp::_p<1>) >>
-in_flow.with(bp::_p<0>, bp::_p<1>) >>
']';
// Parser for YAML [80].
auto const s_separate_def = bp::switch_(bp::_p<1>)
(context::block_out, s_separate_lines.with(bp::_p<0>))
(context::block_in, s_separate_lines.with(bp::_p<0>))
(context::flow_out, s_separate_lines.with(bp::_p<0>))
(context::flow_in, s_separate_lines.with(bp::_p<0>))
(context::block_key, s_separate_in_line)
(context::flow_key, s_separate_in_line);
// Parser for YAML [136].
auto const in_flow_def = bp::switch_(bp::_p<1>)
(context::flow_out, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_in))
(context::flow_in, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_in))
(context::block_out, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_key))
(context::flow_key, ns_s_flow_seq_entries.with(bp::_p<0>, context::flow_key));
auto const ns_s_flow_seq_entries_def = bp::eps;
auto const s_separate_lines_def = bp::eps;
BOOST_PARSER_DEFINE_RULES(
c_flow_sequence,
s_separate,
in_flow,
ns_s_flow_seq_entries,
s_separate_lines);
//]
}
// clang-format on
TEST(parser, extended_param_example)
{
using namespace param_example;
//[ extended_param_yaml_example_use
auto const test_parser = c_flow_sequence.with(4, context::block_out);
auto result = bp::parse("[]", test_parser);
assert(result);
//]
(void)result;
}

View File

@@ -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_RULES(flat_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(recursive_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(flat_string_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(recursive_string_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(flat_vector_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(callback_vector_rule);
BOOST_PARSER_DEFINE_RULE(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_RULES(callback_void_rule);
BOOST_PARSER_DEFINE_RULE(callback_void_rule);
struct callback_vector_rule_tag
{};

View File

@@ -1,339 +0,0 @@
/**
* 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>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, seq_parser_permutations_1)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P0
{
auto result =
bp::parse("foofoo", bp::string("foo") >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, "foo"s)));
}
{
auto result =
bp::parse("foobar", bp::string("foo") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, "bar"s)));
}
{
auto result = bp::parse("foo42", bp::string("foo") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, 42)));
}
{
auto result = bp::parse("fooc", bp::string("foo") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "fooc"s);
}
{
auto result = bp::parse("foo", bp::string("foo") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result =
bp::parse("foofoofoo", bp::string("foo") >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s, "foo"s}));
}
{
auto result = bp::parse("foo", bp::string("foo") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"foofoo42", bp::string("foo") >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, "foo"s, 42)));
}
{
auto result = bp::parse(
"foofoobar",
bp::string("foo") >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple("foo"s, std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"foofoobar",
bp::string("foo") >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("foo"s, std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"foo42", bp::string("foo") >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("foo"s, std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"foo",
bp::string("foo") >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"foo",
bp::string("foo") >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
"foo"s,
std::variant<std::optional<std::string>, std::string>(
std::nullopt))));
}
// -P0
{
auto result =
bp::parse("foofoo", -bp::string("foo") >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "foo"s)));
}
{
auto result = bp::parse("bar", -bp::string("foo") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional<std::string>{}, "bar"s)));
}
{
auto result = bp::parse("42", -bp::string("foo") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional<std::string>{}, 42)));
}
{
auto result = bp::parse("c", -bp::string("foo") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional<std::string>{}, 'c')));
}
{
auto result = bp::parse("foo", -bp::string("foo") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional("foo"s));
}
{
auto result =
bp::parse("foofoo", -bp::string("foo") >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result =
bp::parse("foofoo", -bp::string("foo") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(std::optional("foo"s), std::optional("foo"s))));
}
{
auto result = bp::parse(
"foofoo42", -bp::string("foo") >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "foo"s, 42)));
}
{
auto result = bp::parse(
"foofoobar",
-bp::string("foo") >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::optional("foo"s),
std::optional((make::tuple("foo"s, "bar"s))))));
}
{
auto result = bp::parse(
"foofoobar",
-bp::string("foo") >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::optional("foo"s), std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"foo42", -bp::string("foo") >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::optional("foo"s), std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"foobar",
-bp::string("foo") >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(std::optional("foo"s), std::optional("bar"s))));
}
{
auto result = bp::parse(
"foofoo",
-bp::string("foo") >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
"foo"s,
std::variant<std::optional<std::string>, std::string>(
std::optional("foo"s)))));
}
// *P0
{
auto result = bp::parse(
"foo foo",
bp::lexeme[*bp::string("foo")] >> bp::string("foo"),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result =
bp::parse("foobar", *bp::string("foo") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "bar"s}));
}
{
auto result = bp::parse("foo42", *bp::string("foo") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s}), 42)));
}
{
auto result = bp::parse("fooc", *bp::string("foo") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s}), 'c')));
}
{
auto result = bp::parse("foo", *bp::string("foo") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s}));
}
{
auto result = bp::parse(
"foo foo",
bp::lexeme[*bp::string("foo")] >> *bp::string("foo"),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(std::vector({"foo"s}), std::vector({"foo"s}))));
}
{
auto result =
bp::parse("foo", *bp::string("foo") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s}));
}
{
auto result = bp::parse(
"foo foo42",
bp::lexeme[*bp::string("foo")] >> (bp::string("foo") >> bp::int_),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s, "foo"s}), 42)));
}
{
auto result = bp::parse(
"foo foobar",
bp::lexeme[*bp::string("foo")] >>
-(bp::string("foo") >> bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::vector({"foo"s}),
std::optional((make::tuple("foo"s, "bar"s))))));
}
{
auto result = bp::parse(
"foo foobar",
bp::lexeme[*bp::string("foo")] >>
(-bp::string("foo") >> bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s, "bar"s}));
}
{
auto result = bp::parse(
"foo 42",
bp::lexeme[*bp::string("foo")] >> (bp::string("foo") | bp::int_),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::vector({"foo"s}), std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"foo bar",
bp::lexeme[*bp::string("foo")] >>
-(bp::string("foo") | bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "bar"s}));
}
{
auto result = bp::parse(
"foo",
bp::lexeme[*bp::string("foo")] >>
(-bp::string("foo") | bp::string("bar")),
bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
std::vector({"foo"s}),
std::variant<std::optional<std::string>, std::string>(
std::nullopt))));
}
}

View File

@@ -1,370 +0,0 @@
/**
* 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>
namespace bp = boost::parser;
namespace make {
template<typename... Ts>
auto tuple(Ts &&... xs)
{
return bp::tuple<Ts...>((Ts &&) xs...);
}
}
/*
{P0, -P0, *P0, P1, P2, P3, eps}
<cartesian product>
{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)}
P0 = bp::string("foo");
P1 = bp::string("bar");
P2 = bp::int_;
P3 = bp::char_('c');
*/
using namespace std::literals;
TEST(attributes, seq_parser_permutations_2)
{
[[maybe_unused]] int dummy = 0; // for clang-format(!)
// P1
{
auto result =
bp::parse("barfoo", bp::string("bar") >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, "foo"s)));
}
{
auto result =
bp::parse("barbar", bp::string("bar") >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, "bar"s)));
}
{
auto result = bp::parse("bar42", bp::string("bar") >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, 42)));
}
{
auto result = bp::parse("barc", bp::string("bar") >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "barc"s);
}
{
auto result = bp::parse("bar", bp::string("bar") >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result =
bp::parse("barfoofoo", bp::string("bar") >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"bar"s, "foo"s, "foo"s}));
}
{
auto result =
bp::parse("barfoo", bp::string("bar") >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, std::optional("foo"s))));
}
{
auto result = bp::parse(
"barfoo42", bp::string("bar") >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, "foo"s, 42)));
}
{
auto result = bp::parse(
"barfoobar",
bp::string("bar") >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple("bar"s, std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"barfoobar",
bp::string("bar") >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("bar"s, std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"bar42", bp::string("bar") >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple("bar"s, std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"bar",
bp::string("bar") >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("bar"s, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"bar",
bp::string("bar") >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
make::tuple(
"bar"s,
std::variant<std::optional<std::string>, std::string>(
std::nullopt)));
}
// P2
{
auto result = bp::parse("42foo", bp::int_ >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, "foo"s)));
}
{
auto result = bp::parse("42bar", bp::int_ >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, "bar"s)));
}
{
auto result = bp::parse("42 42", bp::int_ >> bp::int_, bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, 42)));
}
{
auto result = bp::parse("42c", bp::int_ >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, 'c')));
}
{
auto result = bp::parse("42", bp::int_ >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 42);
}
{
auto result = bp::parse("42foofoo", bp::int_ >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::vector({"foo"s, "foo"s}))));
}
{
auto result = bp::parse("42foo", bp::int_ >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::optional("foo"s))));
}
{
auto result =
bp::parse("42foo42", bp::int_ >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, "foo"s, 42)));
}
{
auto result = bp::parse(
"42foobar", bp::int_ >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(42, std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"42foobar", bp::int_ >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::optional("foo"s), "bar"s)));
}
{
auto result = bp::parse(
"42 42", bp::int_ >> (bp::string("foo") | bp::int_), bp::ws);
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple(42, std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"42", bp::int_ >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(42, std::optional<std::string>{})));
}
{
auto result = bp::parse(
"42", bp::int_ >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
make::tuple(
42,
std::variant<std::optional<std::string>, std::string>(
std::nullopt)));
}
// P3
{
auto result = bp::parse("cfoo", bp::char_('c') >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "cfoo"s);
}
{
auto result = bp::parse("cbar", bp::char_('c') >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "cbar"s);
}
{
auto result = bp::parse("c42", bp::char_('c') >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', 42)));
}
{
auto result = bp::parse("cc", bp::char_('c') >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "cc"s);
}
{
auto result = bp::parse("c", bp::char_('c') >> bp::eps);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result =
bp::parse("cfoofoo", bp::char_('c') >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::vector({"foo"s, "foo"s}))));
}
{
auto result = bp::parse("cfoo", bp::char_('c') >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::optional("foo"s))));
}
{
auto result = bp::parse(
"cfoo42", bp::char_('c') >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("cfoo"s, 42)));
}
{
auto result = bp::parse(
"cfoobar",
bp::char_('c') >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple('c', std::optional(make::tuple("foo"s, "bar"s)))));
}
{
auto result = bp::parse(
"cfoobar",
bp::char_('c') >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::optional("foo"s), "bar"s)));
}
{
auto result =
bp::parse("c42", bp::char_('c') >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(
*result, (make::tuple('c', std::variant<std::string, int>(42))));
}
{
auto result = bp::parse(
"c", bp::char_('c') >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple('c', std::optional<std::string>{})));
}
{
auto result = bp::parse(
"c", bp::char_('c') >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(make::tuple(
'c',
std::variant<std::optional<std::string>, std::string>(
std::nullopt))));
}
// eps
{
auto result = bp::parse("foo", bp::eps >> bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "foo"s);
}
{
auto result = bp::parse("bar", bp::eps >> bp::string("bar"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, "bar"s);
}
{
auto result = bp::parse("42", bp::eps >> bp::int_);
EXPECT_TRUE(result);
EXPECT_EQ(*result, 42);
}
{
auto result = bp::parse("c", bp::eps >> bp::char_('c'));
EXPECT_TRUE(result);
EXPECT_EQ(*result, 'c');
}
{
auto result = bp::parse("", bp::eps >> bp::eps);
EXPECT_TRUE(result);
}
{
auto result = bp::parse("foofoo", bp::eps >> *bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::vector({"foo"s, "foo"s}));
}
{
auto result = bp::parse("foo", bp::eps >> -bp::string("foo"));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional("foo"s));
}
{
auto result =
bp::parse("foo42", bp::eps >> (bp::string("foo") >> bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple("foo"s, 42)));
}
{
auto result = bp::parse(
"foobar", bp::eps >> -(bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional((make::tuple("foo"s, "bar"s))));
}
{
auto result = bp::parse(
"foobar", bp::eps >> (-bp::string("foo") >> bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "bar"s)));
}
{
auto result =
bp::parse("42", bp::eps >> (bp::string("foo") | bp::int_));
EXPECT_TRUE(result);
EXPECT_EQ(*result, (std::variant<std::string, int>(42)));
}
{
auto result =
bp::parse("", bp::eps >> -(bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(*result, std::optional<std::string>{});
}
{
auto result =
bp::parse("", bp::eps >> (-bp::string("foo") | bp::string("bar")));
EXPECT_TRUE(result);
EXPECT_EQ(
*result,
(std::variant<std::optional<std::string>, std::string>(
std::nullopt)));
}
}

View File

@@ -1,478 +0,0 @@
/**
* 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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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((char)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

View File

@@ -1,755 +0,0 @@
/**
* 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");
(void)result;
}
{
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);
}
}

View File

@@ -1,269 +0,0 @@
/**
* 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);
}
}

View File

@@ -103,13 +103,6 @@ int main()
PARSE(char_ | int_ | float_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| operator|| |\n"
<< "----------------------------------------\n";
PARSE(char_ || int_ || float_);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| operator- (binary) |\n"
@@ -138,14 +131,6 @@ int main()
PARSE(char_[a]);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| transform)f_[] |\n"
<< "----------------------------------------\n";
auto f = [](auto x) { return x; };
PARSE(transform(f)[char_]);
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| omit[] |\n"
@@ -328,52 +313,21 @@ int main()
std::cout << "\n\n"
<< "----------------------------------------\n"
<< "| blank |\n"
<< "| ascii character classes |\n"
<< "----------------------------------------\n";
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);
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);
std::cout << "\n\n"
<< "----------------------------------------\n"

View File

@@ -1,864 +0,0 @@
/**
* 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) && \
(!defined(__GNUC__) || 12 <= __GNUC__ || !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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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) {
auto u8sub = subrange | bp::as_utf8;
std::string str(u8sub.begin(), u8sub.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((char)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((char)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