mirror of
https://github.com/boostorg/parser.git
synced 2026-01-21 05:02:14 +00:00
Compare commits
3 Commits
parser_con
...
single_hea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20b017c965 | ||
|
|
c4d9e4fbcd | ||
|
|
c68897b9e6 |
34
.github/workflows/deploy_unified_header.yml
vendored
34
.github/workflows/deploy_unified_header.yml
vendored
@@ -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
|
||||
4
.github/workflows/macos-12.yml
vendored
4
.github/workflows/macos-12.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/ubuntu-20.04.yml
vendored
4
.github/workflows/ubuntu-20.04.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/ubuntu-22.04.yml
vendored
4
.github/workflows/ubuntu-22.04.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/windows-2019.yml
vendored
4
.github/workflows/windows-2019.yml
vendored
@@ -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.)
|
||||
|
||||
4
.github/workflows/windows-2022.yml
vendored
4
.github/workflows/windows-2022.yml
vendored
@@ -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.)
|
||||
|
||||
@@ -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 ()
|
||||
|
||||
##################################################
|
||||
|
||||
@@ -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
|
||||
:
|
||||
|
||||
136
doc/intro.qbk
136
doc/intro.qbk
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
572
doc/tables.qbk
572
doc/tables.qbk
@@ -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)>>`]]
|
||||
]
|
||||
]
|
||||
1840
doc/tutorial.qbk
1840
doc/tutorial.qbk
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
//]
|
||||
}
|
||||
//]
|
||||
@@ -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);
|
||||
//]
|
||||
//]
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
26333
include/boost/parser/parser_unified.hpp
Normal file
26333
include/boost/parser/parser_unified.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
104
test/all_t.cpp
104
test/all_t.cpp
@@ -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]>>);
|
||||
}
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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")];
|
||||
|
||||
155
test/no_case.cpp
155
test/no_case.cpp
@@ -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)
|
||||
|
||||
@@ -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
|
||||
935
test/parser.cpp
935
test/parser.cpp
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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')));
|
||||
}
|
||||
}
|
||||
@@ -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}));
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
@@ -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')));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{};
|
||||
|
||||
@@ -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))));
|
||||
}
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
478
test/replace.cpp
478
test/replace.cpp
@@ -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
|
||||
755
test/search.cpp
755
test/search.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
269
test/split.cpp
269
test/split.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user