2
0
mirror of https://github.com/boostorg/spirit.git synced 2026-01-19 04:42:11 +00:00

Merge pull request #831 from saki7/revert-modernization

Revert modernization
This commit is contained in:
Nana Sakisaka
2025-09-13 09:36:40 +09:00
committed by GitHub
144 changed files with 5837 additions and 18463 deletions

77
.appveyor.yml Normal file
View File

@@ -0,0 +1,77 @@
#==============================================================================
# Copyright (c) 2016-2020 Nikita Kniazev
#
# Use, modification and distribution is subject to 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)
#==============================================================================
clone_depth: 50
environment:
global:
PROJECT: libs\spirit
matrix:
- { APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2019', ADDRMDL: 64, TOOLSET: 'msvc-14.2' }
- { APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2017', ADDRMDL: 64, TOOLSET: 'msvc-14.1' }
- { APPVEYOR_BUILD_WORKER_IMAGE: 'Visual Studio 2015', ADDRMDL: 64, TOOLSET: 'msvc-14.0' }
init:
- set BOOST_ROOT=%APPVEYOR_BUILD_FOLDER%\..\boost
- set BOOST_BUILD_PATH=%BOOST_ROOT%\..\boost-build
- set B2_ARGS=link=shared threading=multi variant=release
address-model=%ADDRMDL% toolset=%TOOLSET%
define=BOOST_ALL_NO_LIB
define=BOOST_SPIRIT_X3_HIDE_CXX17_WARNING
before_build:
- set PATH=%BOOST_ROOT%;C:\Python36-x64\Scripts;%PATH%
- ps: |
# Creating %USERPROFILE%/user-config.jam file
@'
import feature os regex toolset pch ;
# A subfeature that tells Spirit tests to use PCH
feature.subfeature pch on : version : spirit : optional propagated incidental ;
'@ | sc "$env:USERPROFILE/user-config.jam"
- set BRANCH=%APPVEYOR_REPO_BRANCH%
# TODO: Determine the root branch when PR targeted/build from not our main branches.
- if not "%BRANCH%" == "master"
if not "%BRANCH%" == "develop"
set BRANCH=develop
- echo Root branch is %BRANCH%
# Sadly git's --shallow-submodules has hardcoded depth of 1 commit
# Patch the git binary with a little more depth to deal with boost-commitbot's lag
- ps: |
$git = Get-Command git | Select-Object -ExpandProperty Definition
$git = Split-Path -Parent $git | Split-Path -Parent
Get-ChildItem -Path "$git\mingw64\*" -Include *.exe -Recurse |
ForEach-Object -Process {(Get-Content -Raw $_).Replace("--depth=1","--depth=9") | Set-Content $_}
# Checkout Boost
- git clone -j10 --branch=%BRANCH% --depth=1 --quiet
--recurse-submodules=":(exclude)%PROJECT%" --shallow-submodules
https://github.com/boostorg/boost.git %BOOST_ROOT%
- pushd %BOOST_ROOT%
# Remove empty folder
- rmdir /S /Q %PROJECT%
# Move the repository to boost/libs and make a link to previous place
- move %APPVEYOR_BUILD_FOLDER% %PROJECT%
- mklink /J %APPVEYOR_BUILD_FOLDER% %PROJECT%
build_script:
- bootstrap.bat --with-toolset=msvc
# Let's have less noise (Appveyor cannot collapse command output)
- b2 headers 2>&1 >> deps_build.log
|| ( echo === deps_build.log === && cat deps_build.log )
test_script:
- b2 %B2_ARGS% %PROJECT%\classic\test %PROJECT%\repository\test %PROJECT%\test
warnings=extra warnings-as-errors=on pch=on-spirit

50
.drone.star Normal file
View File

@@ -0,0 +1,50 @@
# Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE.txt)
#
# Copyright Rene Rivera 2020.
# For Drone CI we use the Starlark scripting language to reduce duplication.
# As the yaml syntax for Drone CI is rather limited.
#
#
globalenv={'PROJECT': 'libs/spirit'}
linuxglobalimage="cppalliance/droneubuntu1804:1"
windowsglobalimage="cppalliance/dronevs2019"
def main(ctx):
return [
linux_cxx("STD=14 JOB=test/x3 Job 0", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '14', 'JOB': 'test/x3', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': 'b6589fc6ab'}, globalenv=globalenv),
linux_cxx("STD=14 JOB=test/x3 Job 1", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '14', 'JOB': 'test/x3', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/qi Job 2", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/qi', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': 'da4b9237ba'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/karma Job 3", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/karma', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/lex Job 4", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/lex', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': '1b64538924'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/support Job 5", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/support', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': 'ac3478d69a'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=repository/test Job 6", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'repository/test', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': 'c1dfd96eea'}, globalenv=globalenv),
# Not building #
# linux_cxx("STD=03 JOB=test/qi Job 7", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/qi', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
# Not building #
# linux_cxx("STD=03 JOB=test/karma Job 8", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/karma', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': 'fe5dbbcea5'}, globalenv=globalenv),
linux_cxx("STD=03 JOB=test/lex Job 9", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/lex', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': '0ade7c2cf9'}, globalenv=globalenv),
linux_cxx("STD=03 JOB=test/support Job 10", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/support', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': 'b1d5781111'}, globalenv=globalenv),
linux_cxx("STD=03 JOB=repository/test Job 11", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'repository/test', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': '17ba079149'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/qi Job 12", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/qi', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/karma Job 13", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/karma', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': 'bd307a3ec3'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/lex Job 14", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/lex', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': 'fa35e19212'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=test/support Job 15", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'test/support', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': 'f1abd67035'}, globalenv=globalenv),
linux_cxx("STD=11 JOB=repository/test Job 16", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '11', 'JOB': 'repository/test', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': '1574bddb75'}, globalenv=globalenv),
# Not building #
# linux_cxx("STD=03 JOB=test/qi Job 17", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/qi', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': '0716d9708d'}, globalenv=globalenv),
# Not building #
# linux_cxx("STD=03 JOB=test/karma Job 18", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/karma', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': '9e6a55b6b4'}, globalenv=globalenv),
linux_cxx("STD=03 JOB=test/lex Job 19", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/lex', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': 'b3f0c7f6bb'}, globalenv=globalenv),
linux_cxx("STD=03 JOB=test/support Job 20", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'test/support', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),
linux_cxx("STD=03 JOB=repository/test Job 21", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'repository/test', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': '472b07b9fc'}, globalenv=globalenv),
# Not building #
# linux_cxx("STD=03 JOB=classic/test Job 22", "clang-10", packages="clang-10 libc++-10-dev libc++abi-10-dev jq", llvm_os="bionic", llvm_ver="10", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'classic/test', 'TRAVIS_COMPILER': 'clang-10', 'DRONE_JOB_UUID': '12c6fc06c9'}, globalenv=globalenv),
# Not building #
# linux_cxx("STD=03 JOB=classic/test Job 23", "gcc-10", packages="g++-10 jq", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'STD': '03', 'JOB': 'classic/test', 'TRAVIS_COMPILER': 'gcc-10', 'DRONE_JOB_UUID': 'd435a6cdd7'}, globalenv=globalenv),
]
# from https://github.com/boostorg/boost-ci
load("@boost_ci//ci/drone/:functions.star", "linux_cxx","windows_cxx","osx_cxx","freebsd_cxx")

88
.drone/drone.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/bash
# Copyright 2020 Rene Rivera, Sam Darwin
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)
set -e
export TRAVIS_BUILD_DIR=$(pwd)
export DRONE_BUILD_DIR=$(pwd)
export TRAVIS_BRANCH=$DRONE_BRANCH
export VCS_COMMIT_ID=$DRONE_COMMIT
export GIT_COMMIT=$DRONE_COMMIT
export REPO_NAME=$DRONE_REPO
export USER=$(whoami)
export CC=${CC:-gcc}
export PATH=~/.local/bin:/usr/local/bin:$PATH
export BOOST_ROOT="$HOME/boost"
export BOOST_BUILD_PATH="$HOME/build-boost"
export TRAVIS_PULL_REQUEST=${DRONE_PULL_REQUEST:-false}
export TRAVIS_REPO_SLUG=$REPO_NAME
if [ "$DRONE_JOB_BUILDTYPE" == "boost" ]; then
echo '==================================> INSTALL'
export CACHE_NAME=$TRAVIS_OS_NAME-$TOOLSET-$STD-$JOB
export PATH=$BOOST_ROOT:$PATH
if [[ "$TRAVIS_COMPILER" =~ ^clang- ]]; then export STDLIB=stdlib=libc++ ; fi
# Creating ~/user-config.jam file
sed 's/^ //' > ~/user-config.jam << 'EOF'
import feature ;
import os ;
import regex ;
import toolset ;
local TOOLSET = [ os.environ TRAVIS_COMPILER ] ;
local toolset-parts = [ regex.split $(TOOLSET) "-" ] ;
local toolset-name = $(toolset-parts[1]) ;
local toolset-feature = $(toolset-parts[2-]:J="-") ;
local cxx ;
switch $(toolset-name) {
case gcc : cxx ?= [ regex.replace $(TOOLSET) "gcc" "g++" ] ;
case clang : cxx ?= [ regex.replace $(TOOLSET) "clang" "clang++" ] ;
case * : EXIT "user-config: Unsupported toolset $(toolset-name)" ;
}
using $(toolset-name) : $(toolset-feature) : ccache $(cxx) ;
# Release variant with enabled asserts
variant sanitize : <optimization>speed <debug-symbols>off <inlining>full
<runtime-debugging>off ;
# Determining the root branch
if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then
export BRANCH=$TRAVIS_BRANCH
else
# It is a pull request. Retrieve the base branch from GitHub
GH_PR_API=https://api.github.com/repos/$TRAVIS_REPO_SLUG/pulls/$TRAVIS_PULL_REQUEST
export BRANCH=`curl -s $GH_PR_API | jq -r .head.ref`;
fi
if [[ ! "$BRANCH" =~ ^(master|develop)$ ]]; then
# Travis has been triggered not from our main branches.
# Find out the base branch from the git history
# TODO: Not implemented yet, but in most cases it will be develop branch
export BRANCH=develop
fi
echo Root branch is $BRANCH
env
sed 's/--depth=1/--depth=9/g' `which git` > ~/git && chmod +x ~/git
~/git clone -j10 --branch=$BRANCH --depth=1 --quiet --recurse-submodules=":(exclude)$PROJECT" --shallow-submodules https://github.com/boostorg/boost.git $BOOST_ROOT
pushd $BOOST_ROOT
rm -rf $PROJECT
./bootstrap.sh --with-toolset=clang
./b2 headers
cp -rp $TRAVIS_BUILD_DIR $PROJECT
ln -s $PROJECT $TRAVIS_BUILD_DIR
cd $PROJECT
cd $JOB
echo '==================================> SCRIPT'
b2 link=shared threading=multi variant=release,sanitize toolset=$TRAVIS_COMPILER cxxstd=$STD $STDLIB warnings=extra warnings-as-errors=on
fi

View File

@@ -9,295 +9,300 @@ concurrency:
cancel-in-progress: true
env:
BOOST_SPIRIT_BUILD_JOBS: 4
BOOST_SPIRIT_CACHED_UPSTREAM_LIBS: --with-regex --with-thread --with-atomic --with-chrono --with-container --with-date_time --with-exception --with-math
PROJECT: libs/spirit
jobs:
changes:
runs-on: ubuntu-latest
outputs:
spirit_component: ${{ steps.filter.outputs.changes }}
karma: ${{ steps.filter.outputs.karma }}
lex: ${{ steps.filter.outputs.lex }}
qi: ${{ steps.filter.outputs.qi }}
support: ${{ steps.filter.outputs.support }}
repository: ${{ steps.filter.outputs.repository }}
x3: ${{ steps.filter.outputs.x3 }}
steps:
- uses: actions/checkout@v5
- uses: dorny/paths-filter@v3
id: filter
with:
# Note: references to "support" directory in X3 can be completely
# eliminated as soon as those components are moved to X3's
# self-contained location
filters: |
karma:
- '.github/workflows/*.yml'
- 'include/boost/spirit/home/support/**/*'
- 'include/boost/spirit/home/support.hpp'
- 'include/boost/spirit/home/karma/**/*'
- 'include/boost/spirit/home/karma.hpp'
- 'test/karma/**/*'
lex:
- '.github/workflows/*.yml'
- 'include/boost/spirit/home/support/**/*'
- 'include/boost/spirit/home/support.hpp'
- 'include/boost/spirit/home/lex/**/*'
- 'include/boost/spirit/home/lex.hpp'
- 'test/lex/**/*'
qi:
- '.github/workflows/*.yml'
- 'include/boost/spirit/home/support/**/*'
- 'include/boost/spirit/home/support.hpp'
- 'include/boost/spirit/home/qi/**/*'
- 'include/boost/spirit/home/qi.hpp'
- 'test/qi/**/*'
support:
- '.github/workflows/*.yml'
- 'include/boost/spirit/home/support/**/*'
- 'include/boost/spirit/home/support.hpp'
- 'test/support/**/*'
repository:
- '.github/workflows/*.yml'
- 'include/boost/spirit/repository/**/*'
- 'repository/**/*'
x3:
- '.github/workflows/*.yml'
- 'include/boost/spirit/home/x3/**/*'
- 'include/boost/spirit/home/x3.hpp'
- 'test/x3/**/*'
- 'include/boost/spirit/home/support/char_set/**/*'
- 'include/boost/spirit/home/support/char_encoding/**/*'
build:
name: "[${{ matrix.cpp_version.name }}] ${{ matrix.spirit_component }} | ${{ matrix.compiler.toolset }}-${{ matrix.compiler.version }} (${{ matrix.build_type.name }}) @ ${{ matrix.os.name }}-${{ matrix.os.version }}"
needs: changes
if: ${{ needs.changes.outputs.spirit_component != '[]' && needs.changes.outputs.spirit_component != '' }}
runs-on: ${{ matrix.os.name }}-${{ matrix.os.version }}
posix:
strategy:
fail-fast: false
matrix:
os:
- name: ubuntu
version: 24.04
- name: windows
version: 2022
build_type:
- name: Debug
lowercase: debug
- name: Release
lowercase: release
cpp_version:
- name: C++11
number: 11
- name: C++23
number: 23
msvc_std: /std:c++23preview
- name: C++26
number: 26
msvc_std: /std:c++latest
compiler:
- name: GCC
toolset: gcc
version: 14
cxxflags: -fdiagnostics-color=always
- name: Clang
toolset: clang
version: 22
cxxflags: -fcolor-diagnostics
- name: MSVC
toolset: msvc
version: 2022
cxxflags: /EHsc /utf-8
include:
- name: "C++17 test/x3"
buildtype: "boost"
packages: "clang-18 libc++-18-dev libc++abi-18-dev libunwind-18-dev jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "clang-18"
sources: ""
llvm_os: "jammy"
llvm_ver: "18"
std: "17"
job: "test/x3"
travis_compiler: "clang-18"
- name: "C++17 test/x3"
buildtype: "boost"
packages: "g++-13 jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "gcc-13"
sources: ""
llvm_os: ""
llvm_ver: ""
std: "17"
job: "test/x3"
travis_compiler: "gcc-13"
- name: "C++11 test/qi"
buildtype: "boost"
packages: "clang-14 libc++-14-dev libc++abi-14-dev libunwind-14-dev jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "clang-14"
sources: ""
llvm_os: "jammy"
llvm_ver: "14"
std: "11"
job: "test/qi"
travis_compiler: "clang-14"
- name: "C++11 test/karma"
buildtype: "boost"
packages: "clang-14 libc++-14-dev libc++abi-14-dev libunwind-14-dev jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "clang-14"
sources: ""
llvm_os: "jammy"
llvm_ver: "14"
std: "11"
job: "test/karma"
travis_compiler: "clang-14"
- name: "C++11 test/lex"
buildtype: "boost"
packages: "clang-14 libc++-14-dev libc++abi-14-dev libunwind-14-dev jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "clang-14"
sources: ""
llvm_os: "jammy"
llvm_ver: "14"
std: "11"
job: "test/lex"
travis_compiler: "clang-14"
- name: "C++11 test/support"
buildtype: "boost"
packages: "clang-14 libc++-14-dev libc++abi-14-dev libunwind-14-dev jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "clang-14"
sources: ""
llvm_os: "jammy"
llvm_ver: "14"
std: "11"
job: "test/support"
travis_compiler: "clang-14"
- name: "C++11 repository/test"
buildtype: "boost"
packages: "clang-14 libc++-14-dev libc++abi-14-dev libunwind-14-dev jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "clang-14"
sources: ""
llvm_os: "jammy"
llvm_ver: "14"
std: "11"
job: "repository/test"
travis_compiler: "clang-14"
- name: "C++11 test/qi"
buildtype: "boost"
packages: "g++-11 jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "gcc-11"
sources: ""
llvm_os: ""
llvm_ver: ""
std: "11"
job: "test/qi"
travis_compiler: "gcc-11"
- name: "C++11 test/karma"
buildtype: "boost"
packages: "g++-11 jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "gcc-11"
sources: ""
llvm_os: ""
llvm_ver: ""
std: "11"
job: "test/karma"
travis_compiler: "gcc-11"
- name: "C++11 test/lex"
buildtype: "boost"
packages: "g++-11 jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "gcc-11"
sources: ""
llvm_os: ""
llvm_ver: ""
std: "11"
job: "test/lex"
travis_compiler: "gcc-11"
- name: "C++11 test/support"
buildtype: "boost"
packages: "g++-11 jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "gcc-11"
sources: ""
llvm_os: ""
llvm_ver: ""
std: "11"
job: "test/support"
travis_compiler: "gcc-11"
- name: "C++11 repository/test"
buildtype: "boost"
packages: "g++-11 jq ccache"
packages_to_remove: ""
os: "ubuntu-22.04"
cxx: "gcc-11"
sources: ""
llvm_os: ""
llvm_ver: ""
std: "11"
job: "repository/test"
travis_compiler: "gcc-11"
spirit_component: ${{ fromJSON(needs.changes.outputs.spirit_component) }}
exclude:
# Blacklist all invalid combinations of environments
- os:
name: windows
cpp_version:
number: 11 # /std:c++11 is no longer supported
- os:
name: windows
compiler:
name: GCC
- os:
name: windows
compiler:
name: Clang
- os:
name: ubuntu
compiler:
name: MSVC
# Blacklist incompatible toolchains
- spirit_component: karma
cpp_version:
number: 23
- spirit_component: karma
cpp_version:
number: 26
- spirit_component: lex
cpp_version:
number: 23
- spirit_component: lex
cpp_version:
number: 26
- spirit_component: qi
cpp_version:
number: 23
- spirit_component: qi
cpp_version:
number: 26
- spirit_component: support
cpp_version:
number: 23
- spirit_component: support
cpp_version:
number: 26
- spirit_component: repository
cpp_version:
number: 23
- spirit_component: repository
cpp_version:
number: 26
- spirit_component: x3
cpp_version:
number: 11
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
steps:
- uses: actions/checkout@v5
with:
# required for upstream Boost version detection
# sadly not working due to upstream bug: https://github.com/actions/checkout/issues/1471
fetch-tags: true
- name: Check if running in container
if: matrix.container != ''
run: echo "GHA_CONTAINER=${{ matrix.container }}" >> $GITHUB_ENV
- name: Fetch git tags
run: |
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- uses: actions/checkout@v2
- name: Initialize Ubuntu
if: matrix.os.name == 'ubuntu'
if: matrix.os == 'ubuntu-22.04'
run: |
sudo echo "set man-db/auto-update false" | sudo debconf-communicate
sudo dpkg-reconfigure man-db
sudo apt-get install -y jq
- name: Setup GCC
if: matrix.compiler.toolset == 'gcc'
run: |
sudo apt-get update
sudo apt-get install -y g++-${{ matrix.compiler.version }}
- name: Setup Clang
if: matrix.compiler.toolset == 'clang'
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x ./llvm.sh
sudo ./llvm.sh ${{ matrix.compiler.version }}
sudo apt-get install -y libc++-${{ matrix.compiler.version }}-dev libc++abi-${{ matrix.compiler.version }}-dev
echo "BOOST_SPIRIT_STDLIB=stdlib=libc++" >> "$GITHUB_ENV"
- name: Fetch Environment Info
id: env-info
- name: Linux
shell: bash
env:
CXX: ${{ matrix.cxx }}
SOURCES: ${{ matrix.sources }}
LLVM_OS: ${{ matrix.llvm_os }}
LLVM_VER: ${{ matrix.llvm_ver }}
PACKAGES: ${{ matrix.packages }}
PACKAGES_TO_REMOVE: ${{ matrix.packages_to_remove }}
JOB_BUILDTYPE: ${{ matrix.buildtype }}
STD: ${{ matrix.std }}
JOB: ${{ matrix.job }}
TRAVIS_COMPILER: ${{ matrix.travis_compiler }}
TRAVIS_BRANCH: ${{ github.base_ref }}
TRAVIS_OS_NAME: "linux"
run: |
echo '==================================> SETUP'
echo '==================================> PACKAGES'
set -e
export BOOST_RELEASE_VERSION_NAME=$(git for-each-ref refs/tags --sort=-refname --format='%(refname:lstrip=-1)' --count=1)
echo "BOOST_RELEASE_VERSION_NAME: $BOOST_RELEASE_VERSION_NAME"
echo "BOOST_RELEASE_VERSION_NAME=$BOOST_RELEASE_VERSION_NAME" >> "$GITHUB_OUTPUT"
if [ -n "$PACKAGES_TO_REMOVE" ]; then sudo apt-get purge -y $PACKAGES_TO_REMOVE; fi
echo ">>>>> APT: REPO.."
for i in {1..3}; do sudo -E apt-add-repository -y "ppa:ubuntu-toolchain-r/test" && break || sleep 2; done
if [ "${{ matrix.os.name }}" = "windows" ]; then
export BOOST_ROOT=$(cygpath -w $HOME/boost)
else
export BOOST_ROOT=$HOME/boost
if test -n "${LLVM_OS}" ; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
if test -n "${LLVM_VER}" ; then
sudo -E apt-add-repository "deb http://apt.llvm.org/${LLVM_OS}/ llvm-toolchain-${LLVM_OS}-${LLVM_VER} main"
else
# Snapshot (i.e. trunk) build of clang
sudo -E apt-add-repository "deb http://apt.llvm.org/${LLVM_OS}/ llvm-toolchain-${LLVM_OS} main"
fi
fi
echo "BOOST_ROOT: $BOOST_ROOT"
echo "BOOST_ROOT=$BOOST_ROOT" >> "$GITHUB_OUTPUT"
echo ">>>>> APT: UPDATE.."
sudo -E apt-get -o Acquire::Retries=3 update
if test -n "${SOURCES}" ; then
echo ">>>>> APT: INSTALL SOURCES.."
for SOURCE in $SOURCES; do
sudo -E apt-add-repository ppa:$SOURCE
done
fi
echo ">>>>> APT: INSTALL ${PACKAGES}.."
sudo -E DEBIAN_FRONTEND=noninteractive apt-get -o Acquire::Retries=3 -y --no-install-suggests --no-install-recommends install ${PACKAGES}
- name: Cache upstream Boost libraries (restore)
id: cache-boost
uses: actions/cache/restore@v4
with:
key: ${{ steps.env-info.outputs.BOOST_RELEASE_VERSION_NAME }}-${{ matrix.os.name }}-${{ matrix.os.version }}-${{ matrix.compiler.toolset }}-${{ matrix.compiler.version }}-${{ matrix.cpp_version.name }}-${{ matrix.build_type.name }}
path: |
${{ steps.env-info.outputs.BOOST_ROOT }}
!${{ steps.env-info.outputs.BOOST_ROOT }}/.git
echo '==================================> INSTALL AND COMPILE'
set -e
export TRAVIS_BUILD_DIR=$(pwd)
export TRAVIS_BRANCH=${TRAVIS_BRANCH:-$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')}
export VCS_COMMIT_ID=$GITHUB_SHA
export GIT_COMMIT=$GITHUB_SHA
export REPO_NAME=$(basename $GITHUB_REPOSITORY)
export USER=$(whoami)
export CC=${CC:-gcc}
export PATH=~/.local/bin:/usr/local/bin:$PATH
export BOOST_ROOT="$HOME/boost"
export BOOST_BUILD_PATH="$HOME/build-boost"
export GITHUB_EVENT_NUMBER=${{ github.event.number }}
export TRAVIS_PULL_REQUEST=${GITHUB_EVENT_NUMBER:-false}
export TRAVIS_REPO_SLUG=$REPO_NAME
- name: Clone upstream Boost libraries
if: steps.cache-boost.outputs.cache-hit != 'true'
run: |
git -c advice.detachedHead=false clone --no-tags --single-branch --branch=${{ steps.env-info.outputs.BOOST_RELEASE_VERSION_NAME }} --depth=1 --quiet --recurse-submodules=":(exclude)libs/spirit" --shallow-submodules https://github.com/boostorg/boost.git ${{ steps.env-info.outputs.BOOST_ROOT }}
- name: Build upstream Boost libraries (Ubuntu)
if: matrix.os.name == 'ubuntu' && steps.cache-boost.outputs.cache-hit != 'true'
env:
BOOST_ROOT: ${{ steps.env-info.outputs.BOOST_ROOT }}
working-directory: ${{ steps.env-info.outputs.BOOST_ROOT }}
shell: bash
run: |
set -xe
rm -rf libs/spirit
./bootstrap.sh --with-toolset=${{ matrix.compiler.toolset }}
./b2 -d0 headers
./b2 -d1 -j$BOOST_SPIRIT_BUILD_JOBS $BOOST_SPIRIT_CACHED_UPSTREAM_LIBS link=shared threading=multi variant=${{ matrix.build_type.lowercase }} toolset=${{ matrix.compiler.toolset }}-${{ matrix.compiler.version }} cxxstd=${{ matrix.cpp_version.number }} cxxflags="${{ matrix.compiler.cxxflags }}" $BOOST_SPIRIT_STDLIB warnings=extra warnings-as-errors=off
if [ "$JOB_BUILDTYPE" == "boost" ]; then
- uses: TheMrMilchmann/setup-msvc-dev@v3
if: matrix.os.name == 'windows'
with:
arch: x64
echo '==================================> INSTALL'
- name: Build upstream Boost libraries (Windows)
if: matrix.os.name == 'windows' && steps.cache-boost.outputs.cache-hit != 'true'
env:
BOOST_ROOT: ${{ steps.env-info.outputs.BOOST_ROOT }}
working-directory: ${{ steps.env-info.outputs.BOOST_ROOT }}
shell: cmd
run: |
rd /s /q libs\spirit
.\bootstrap.bat --with-toolset=${{ matrix.compiler.toolset }}
.\b2 -d0 headers
.\b2 -d1 -j%BOOST_SPIRIT_BUILD_JOBS% %BOOST_SPIRIT_CACHED_UPSTREAM_LIBS% link=shared threading=multi variant=${{ matrix.build_type.lowercase }} toolset=${{ matrix.compiler.toolset }} cxxflags="${{ matrix.cpp_version.msvc_std }} ${{matrix.compiler.cxxflags}}" warnings=extra warnings-as-errors=off
export CACHE_NAME=$TRAVIS_OS_NAME-$TOOLSET-$STD-$JOB
export PATH=$BOOST_ROOT:$PATH
if [[ "$TRAVIS_COMPILER" =~ ^clang- ]]; then export STDLIB=stdlib=libc++ ; fi
# Creating ~/user-config.jam file
sed 's/^ //' > ~/user-config.jam << 'EOF'
- name: Cache upstream Boost libraries
if: steps.cache-boost.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
key: ${{ steps.cache-boost.outputs.cache-primary-key }}
path: |
${{ steps.env-info.outputs.BOOST_ROOT }}
!${{ steps.env-info.outputs.BOOST_ROOT }}/.git
import feature ;
import os ;
import regex ;
import toolset ;
- name: Build and test (Ubuntu)
if: matrix.os.name == 'ubuntu'
env:
BOOST_ROOT: ${{ steps.env-info.outputs.BOOST_ROOT }}
working-directory: ${{ steps.env-info.outputs.BOOST_ROOT }}
shell: bash
run: |
set -xe
cp -rp $GITHUB_WORKSPACE libs/spirit
cd libs/spirit/test
ln -s ../repository/test repository # workaround legacy directory structure
cd ${{ matrix.spirit_component }}
$BOOST_ROOT/b2 -d1 -j$BOOST_SPIRIT_BUILD_JOBS link=shared threading=multi variant=${{ matrix.build_type.lowercase }} toolset=${{ matrix.compiler.toolset }}-${{ matrix.compiler.version }} cxxstd=${{ matrix.cpp_version.number }} cxxflags="${{ matrix.compiler.cxxflags }}" $BOOST_SPIRIT_STDLIB warnings=extra warnings-as-errors=off
local TOOLSET = [ os.environ TRAVIS_COMPILER ] ;
local toolset-parts = [ regex.split $(TOOLSET) "-" ] ;
local toolset-name = $(toolset-parts[1]) ;
local toolset-feature = $(toolset-parts[2-]:J="-") ;
- name: Build and test (Windows)
if: matrix.os.name == 'windows'
env:
BOOST_ROOT: ${{ steps.env-info.outputs.BOOST_ROOT }}
working-directory: ${{ steps.env-info.outputs.BOOST_ROOT }}
shell: cmd
run: |
xcopy /S /E /Q %GITHUB_WORKSPACE% libs\spirit\
cd libs\spirit\test
cd ${{ matrix.spirit_component }}
local cxx ;
switch $(toolset-name) {
case gcc : cxx ?= [ regex.replace $(TOOLSET) "gcc" "g++" ] ;
case clang : cxx ?= [ regex.replace $(TOOLSET) "clang" "clang++" ] ;
case * : EXIT "user-config: Unsupported toolset $(toolset-name)" ;
}
%BOOST_ROOT%\b2 -d1 -j%BOOST_SPIRIT_BUILD_JOBS% link=shared threading=multi variant=${{ matrix.build_type.lowercase }} toolset=${{ matrix.compiler.toolset }} cxxflags="${{ matrix.cpp_version.msvc_std }} ${{matrix.compiler.cxxflags}}" warnings=extra warnings-as-errors=off
using $(toolset-name) : $(toolset-feature) : ccache $(cxx) ;
# Release variant with enabled asserts
variant sanitize : <optimization>speed <debug-symbols>off <inlining>full
<runtime-debugging>off ;
EOF
# Determining the root branch
if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then
export BRANCH=$TRAVIS_BRANCH
else
# It is a pull request. Retrieve the base branch from GitHub
GH_PR_API=https://api.github.com/repos/$TRAVIS_REPO_SLUG/pulls/$TRAVIS_PULL_REQUEST
export BRANCH=`curl -s $GH_PR_API | jq -r .head.ref`;
fi
if [[ ! "$BRANCH" =~ ^(master|develop)$ ]]; then
# Travis has been triggered not from our main branches.
# Find out the base branch from the git history
# TODO: Not implemented yet, but in most cases it will be develop branch
export BRANCH=develop
fi
echo Root branch is $BRANCH
env
sed 's/--depth=1/--depth=9/g' `which git` > ~/git && chmod +x ~/git
~/git clone -j10 --branch=$BRANCH --depth=1 --quiet --recurse-submodules=":(exclude)$PROJECT" --shallow-submodules https://github.com/boostorg/boost.git $BOOST_ROOT
pushd $BOOST_ROOT
rm -rf $PROJECT
./bootstrap.sh --with-toolset=clang
./b2 headers
cp -rp $TRAVIS_BUILD_DIR $PROJECT
ln -s $PROJECT $TRAVIS_BUILD_DIR
cd $PROJECT
cd $JOB
echo '==================================> SCRIPT'
b2 link=shared threading=multi variant=release,sanitize toolset=$TRAVIS_COMPILER cxxstd=$STD $STDLIB warnings=extra warnings-as-errors=off define=BOOST_SPIRIT_X3_HIDE_CXX17_WARNING
fi

1
.gitignore vendored
View File

@@ -1,6 +1,5 @@
.DS_Store
/build*/
test/lex/matlib_static_switch.h

155
.travis.yml Normal file
View File

@@ -0,0 +1,155 @@
#==============================================================================
# Copyright (c) 2016-2021 Nikita Kniazev
#
# Use, modification and distribution is subject to 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)
#==============================================================================
language: cpp
sudo: false
addon_shortcuts:
clang-12: &clang-12
apt:
sources:
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- clang-12
- libc++-12-dev
- libc++abi-12-dev
gcc-11: &gcc-11
apt:
sources:
- sourceline: 'ppa:ubuntu-toolchain-r/test'
packages:
- g++-11
os: linux
dist: bionic
env:
global:
- PROJECT=libs/spirit
- BOOST_ROOT=$HOME/boost
- BOOST_BUILD_PATH=$HOME/build-boost
matrix:
include:
### Spirit 3
- { env: 'STD=14 JOB=test/x3', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=14 JOB=test/x3', compiler: gcc-11, addons: *gcc-11 }
### Spirit 2
## Clang
# 11
- { env: 'STD=11 JOB=test/qi', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=11 JOB=test/karma', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=11 JOB=test/lex', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=11 JOB=test/support', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=11 JOB=repository/test', compiler: clang-12, addons: *clang-12 }
# 03
- { env: 'STD=03 JOB=test/qi', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=03 JOB=test/karma', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=03 JOB=test/lex', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=03 JOB=test/support', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=03 JOB=repository/test', compiler: clang-12, addons: *clang-12 }
## GCC
# 11
- { env: 'STD=11 JOB=test/qi', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=11 JOB=test/karma', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=11 JOB=test/lex', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=11 JOB=test/support', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=11 JOB=repository/test', compiler: gcc-11, addons: *gcc-11 }
# 03
- { env: 'STD=03 JOB=test/qi', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=03 JOB=test/karma', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=03 JOB=test/lex', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=03 JOB=test/support', compiler: gcc-11, addons: *gcc-11 }
- { env: 'STD=03 JOB=repository/test', compiler: gcc-11, addons: *gcc-11 }
### Spirit 1
- { env: 'STD=03 JOB=classic/test', compiler: clang-12, addons: *clang-12 }
- { env: 'STD=03 JOB=classic/test', compiler: gcc-11, addons: *gcc-11 }
cache: ccache
before_install:
- export CACHE_NAME=$TRAVIS_OS_NAME-$TOOLSET-$STD-$JOB
- export PATH=$BOOST_ROOT:$PATH
- if [[ "$TRAVIS_COMPILER" =~ ^clang- ]]; then export STDLIB=stdlib=libc++ ; fi
- |
# Creating ~/user-config.jam file
sed 's/^ //' > ~/user-config.jam << 'EOF'
import feature ;
import os ;
import regex ;
import toolset ;
local TOOLSET = [ os.environ TRAVIS_COMPILER ] ;
local toolset-parts = [ regex.split $(TOOLSET) "-" ] ;
local toolset-name = $(toolset-parts[1]) ;
local toolset-feature = $(toolset-parts[2-]:J="-") ;
local cxx ;
switch $(toolset-name) {
case gcc : cxx ?= [ regex.replace $(TOOLSET) "gcc" "g++" ] ;
case clang : cxx ?= [ regex.replace $(TOOLSET) "clang" "clang++" ] ;
case * : EXIT "user-config: Unsupported toolset $(toolset-name)" ;
}
using $(toolset-name) : $(toolset-feature) : ccache $(cxx) ;
# Release variant with enabled asserts
variant sanitize : <optimization>speed <debug-symbols>off <inlining>full
<runtime-debugging>off ;
- |
# Determining the root branch
if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then
export BRANCH=$TRAVIS_BRANCH
else
# It is a pull request. Retrieve the base branch from GitHub
GH_PR_API=https://api.github.com/repos/$TRAVIS_REPO_SLUG/pulls/$TRAVIS_PULL_REQUEST
export BRANCH=`curl -s $GH_PR_API | jq -r .head.ref`;
fi
if [[ ! "$BRANCH" =~ ^(master|develop)$ ]]; then
# Travis has been triggered not from our main branches.
# Find out the base branch from the git history
# TODO: Not implemented yet, but in most cases it will be develop branch
export BRANCH=develop
fi
echo Root branch is $BRANCH
# Dump environment variables
- env
# Sadly git's --shallow-submodules has hardcoded depth of 1 commit
# Patch the git binary with a little more depth to deal with boost-commitbot's lag
- sed 's/--depth=1/--depth=9/g' `which git` > ~/git && chmod +x ~/git
# Checkout Boost
- ~/git clone -j10 --branch=$BRANCH --depth=1 --quiet
--recurse-submodules=":(exclude)$PROJECT" --shallow-submodules
https://github.com/boostorg/boost.git $BOOST_ROOT
- pushd $BOOST_ROOT
# Remove the empty folder
- rm -rf $PROJECT
- ./bootstrap.sh --with-toolset=clang
- ./b2 headers
# Move the repository to boost/libs and make a link to previous place
- mv $TRAVIS_BUILD_DIR $PROJECT
- ln -s $PROJECT $TRAVIS_BUILD_DIR
- cd $PROJECT
- cd $JOB
script:
- b2 link=shared threading=multi variant=release,sanitize
toolset=$TRAVIS_COMPILER cxxstd=$STD $STDLIB
warnings=extra warnings-as-errors=on
define=BOOST_SPIRIT_X3_HIDE_CXX17_WARNING

View File

@@ -1,63 +1,73 @@
# Spirit [![Build Status](https://github.com/boostorg/spirit/actions/workflows/ci.yml/badge.svg)](https://github.com/boostorg/spirit/actions/workflows/ci.yml)
# This repository is no longer actively maintained. [Spirit.X4](https://github.com/boostorg/spirit_x4) is the successor and is currently under development.
Spirit is a set of C++ libraries for parsing and output generation implemented as
Domain Specific Embedded Languages (DSEL) using Expression templates and Template
Meta-Programming. The Spirit libraries enable a target grammar to be written
exclusively in C++. Inline grammar specifications can mix freely with other
C++ code and, thanks to the generative power of C++ templates, are immediately
All components predating X4 currently lack an active maintainer. They are feature-frozen and will accept security patches only.
If you wish to maintain a legacy version, please contact the [Boost developers' mailing list](https://lists.boost.org/).
For background information, see:
- <https://lists.boost.org/archives/list/boost@lists.boost.org/thread/K3EQLEQJHEUBROB6ODUKTZHFP2FDUS2E/?sort=date>
- <https://github.com/boostorg/spirit/issues/795>
- <https://github.com/boostorg/spirit/pull/807>
Spirit
======
Spirit is a set of C++ libraries for parsing and output generation implemented as
Domain Specific Embedded Languages (DSEL) using Expression templates and Template
Meta-Programming. The Spirit libraries enable a target grammar to be written
exclusively in C++. Inline grammar specifications can mix freely with other
C++ code and, thanks to the generative power of C++ templates, are immediately
executable.
## Spirit.X3 (3rd generation)
### Spirit.X3 (3rd generation)
[Documentation](http://www.boost.org/doc/libs/develop/libs/spirit/doc/x3/html/index.html)
The newest Spirit shines faster compile times. Currently only a parser framework (no serialization support).
The newest Spirit shines faster compile times. Currently only a parser framework.
### Supported environments
*WARNING*: C++14 compilers support will be dropped soon.
- C++23 and C++26
- GCC 14
- Clang 22
- MSVC (2022)
Spirit X3 in Boost 1.81 (scheduled to November 2022) will use C++17 features.
Supported compilers will be:
* Clang 4 (currently 3.6)
* GCC 7 (currently 5)
* VS 2017 v15.8 (currently 2015 U3)
## Spirit V2 (2nd generation)
### Spirit V2 (2nd generation)
[Documentation](http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/index.html)
The latest Long Term Support version of Spirit. A Swiss Army knife for data
manipulation on any kind of input.
Note: Spirit V2 is no longer actively maintained. For new projects, use X3.
Consists of:
- [Qi]: Parser framework.
- [Karma]: Generator framework.
- [Lex]: Lexical analyzer framework.
- [Qi]: Parser framework.
- [Karma]: Generator framework.
- [Lex]: Lexical analyzer framework.
Runs on most C++03 compilers (GCC 4.1, Clang 3.0, VS 2005).
[Spirit V2]: http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/index.html
[Qi]: http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/spirit/qi.html
[Karma]: http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/spirit/karma.html
[Lex]: http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/spirit/lex.html
### Supported environments
- C++11 only
- GCC 14
- Clang 22
- **Windows is no longer supported** because [C++11 support was removed in Visual Studio 2017 and later](https://learn.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version?view=msvc-170#remarks).
## Spirit.Classic (1st generation)
### Spirit.Classic (1st generation)
[Documentation](http://www.boost.org/doc/libs/develop/libs/spirit/classic/index.html)
An elderling member of Spirit. It receives only limited maintenance, but
An elderling member of Spirit. It receives only limited maintanance, but
it is still used even inside Boost by [Boost.Serialization] and [Boost.Wave]
libraries. It also contains Phoenix V1.
Spirit.Classic should support even ancient compilers.
Spririt.Classic should support even ancient compilers.
[Boost.Serialization]: http://boost.org/libs/serialization
[Boost.Wave]: http://boost.org/libs/wave

View File

@@ -1,6 +1,5 @@
[/==============================================================================
Copyright (C) 2001-2018 Joel de Guzman
Copyright (C) 2025 Nana Sakisaka
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)
@@ -129,10 +128,9 @@ our `on_success` handler:
struct annotate_position
{
template <std::forward_iterator It, std::sentinel_for<It> Se, typename T, typename Context>
void on_success(
It const& first, Se const& last, T& ast, Context const& context
) const
template <typename T, typename Iterator, typename Context>
inline void on_success(Iterator const& first, Iterator const& last
, T& ast, Context const& context)
{
auto& position_cache = x3::get<position_cache_tag>(context).get();
position_cache.annotate(ast, first, last);

View File

@@ -1,6 +1,6 @@
[/==============================================================================
Copyright (C) 2001-2018 Joel de Guzman
Copyright (C) 2024-2025 Nana Sakisaka
Copyright (C) 2024 Nana Sakisaka
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)
@@ -129,12 +129,10 @@ Here's our `on_error` handler:
struct error_handler
{
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Exception, typename Context>
[[nodiscard]] x3::error_handler_result
on_error(
It const& first, Se const& last,
Exception const& x, Context const& context
)
template <typename Iterator, typename Exception, typename Context>
x3::error_handler_result on_error(
Iterator& first, Iterator const& last
, Exception const& x, Context const& context)
{
auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
std::string message = "Error! Expecting: " + x3::which(x) + " here:";

View File

@@ -1,7 +1,6 @@
// Copyright (c) 2001-2011 Hartmut Kaiser
// Copyright (c) 2025 Nana Sakisaka
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
//
// 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)
#if !defined(BOOST_SPIRIT_LEX_TOKEN_FEB_10_2008_0751PM)
@@ -38,33 +37,31 @@
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/static_assert.hpp>
#include <type_traits>
#if defined(BOOST_SPIRIT_DEBUG)
#include <iosfwd>
#endif
namespace boost { namespace spirit { namespace lex { namespace lexertl
{
{
///////////////////////////////////////////////////////////////////////////
//
// The token is the type of the objects returned by default by the
// The token is the type of the objects returned by default by the
// iterator.
//
// template parameters:
// Iterator The type of the iterator used to access the
// underlying character stream.
// AttributeTypes A mpl sequence containing the types of all
// required different token values to be supported
// AttributeTypes A mpl sequence containing the types of all
// required different token values to be supported
// by this token type.
// HasState A mpl::bool_ indicating, whether this token type
// should support lexer states.
// Idtype The type to use for the token id (defaults to
// Idtype The type to use for the token id (defaults to
// std::size_t).
//
// It is possible to use other token types with the spirit::lex
// framework as well. If you plan to use a different type as your token
// type, you'll need to expose the following things from your token type
// It is possible to use other token types with the spirit::lex
// framework as well. If you plan to use a different type as your token
// type, you'll need to expose the following things from your token type
// to make it compatible with spirit::lex:
//
// typedefs
@@ -75,28 +72,28 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
//
// methods
// default constructor
// This should initialize the token as an end of
// This should initialize the token as an end of
// input token.
// constructors The prototype of the other required
// constructors The prototype of the other required
// constructors should be:
//
// token(int)
// This constructor should initialize the token as
// an invalid token (not carrying any specific
// This constructor should initialize the token as
// an invalid token (not carrying any specific
// values)
//
// where: the int is used as a tag only and its value is
// where: the int is used as a tag only and its value is
// ignored
//
// and:
//
// token(Idtype id, std::size_t state,
// token(Idtype id, std::size_t state,
// iterator_type first, iterator_type last);
//
// where: id: token id
// state: lexer state this token was matched in
// first, last: pair of iterators marking the matched
// range in the underlying input stream
// first, last: pair of iterators marking the matched
// range in the underlying input stream
//
// accessors
// id() return the token id of the matched input sequence
@@ -107,16 +104,16 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
// value() return the token value
//
// Additionally, you will have to implement a couple of helper functions
// in the same namespace as the token type: a comparison operator==() to
// compare your token instances, a token_is_valid() function and different
// specializations of the Spirit customization point
// in the same namespace as the token type: a comparison operator==() to
// compare your token instances, a token_is_valid() function and different
// specializations of the Spirit customization point
// assign_to_attribute_from_value as shown below.
//
///////////////////////////////////////////////////////////////////////////
template <typename Iterator = char const*
, typename AttributeTypes = mpl::vector0<>
, typename HasState = mpl::true_
, typename Idtype = std::size_t>
, typename Idtype = std::size_t>
struct token;
///////////////////////////////////////////////////////////////////////////
@@ -130,7 +127,7 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
typedef mpl::false_ has_state;
typedef Idtype id_type;
typedef unused_type token_value_type;
typedef typename std::make_unsigned<id_type>::type uid_type;
typedef typename make_unsigned<id_type>::type uid_type;
// default constructed tokens correspond to EOI tokens
token() : id_(boost::lexer::npos) {}
@@ -156,32 +153,32 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
: id_(id) {}
#endif
// this default conversion operator is needed to allow the direct
// usage of tokens in conjunction with the primitive parsers defined
// this default conversion operator is needed to allow the direct
// usage of tokens in conjunction with the primitive parsers defined
// in Qi
operator id_type() const { return id_type(uid_type(id_)); }
// Retrieve or set the token id of this token instance.
// Retrieve or set the token id of this token instance.
id_type id() const { return id_type(uid_type(id_)); }
void id(id_type newid) { id_ = uid_type(newid); }
std::size_t state() const { return 0; } // always '0' (INITIAL state)
bool is_valid() const
{
return 0 != id_ && boost::lexer::npos != id_;
bool is_valid() const
{
return 0 != id_ && boost::lexer::npos != id_;
}
#if defined(BOOST_SPIRIT_DEBUG)
#if BOOST_WORKAROUND(BOOST_MSVC, == 1600)
// workaround for MSVC10 which has problems copying a default
// workaround for MSVC10 which has problems copying a default
// constructed iterator_range
token& operator= (token const& rhs)
{
if (this != &rhs)
if (this != &rhs)
{
id_ = rhs.id_;
if (is_valid())
if (is_valid())
matched_ = rhs.matched_;
}
return *this;
@@ -196,8 +193,8 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
#if defined(BOOST_SPIRIT_DEBUG)
template <typename Char, typename Traits, typename Iterator
, typename AttributeTypes, typename HasState, typename Idtype>
inline std::basic_ostream<Char, Traits>&
, typename AttributeTypes, typename HasState, typename Idtype>
inline std::basic_ostream<Char, Traits>&
operator<< (std::basic_ostream<Char, Traits>& os
, token<Iterator, AttributeTypes, HasState, Idtype> const& t)
{
@@ -251,11 +248,11 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
std::size_t state() const { return state_; }
#if defined(BOOST_SPIRIT_DEBUG) && BOOST_WORKAROUND(BOOST_MSVC, == 1600)
// workaround for MSVC10 which has problems copying a default
// workaround for MSVC10 which has problems copying a default
// constructed iterator_range
token& operator= (token const& rhs)
{
if (this != &rhs)
if (this != &rhs)
{
this->base_type::operator=(static_cast<base_type const&>(rhs));
state_ = rhs.state_;
@@ -269,21 +266,21 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
};
///////////////////////////////////////////////////////////////////////////
// The generic version of the token type derives from the
// specialization above and adds a single data member holding the item
// The generic version of the token type derives from the
// specialization above and adds a single data member holding the item
// data carried by the token instance.
///////////////////////////////////////////////////////////////////////////
namespace detail
{
///////////////////////////////////////////////////////////////////////
// Meta-function to calculate the type of the variant data item to be
// Meta-function to calculate the type of the variant data item to be
// stored with each token instance.
//
// Note: The iterator pair needs to be the first type in the list of
// types supported by the generated variant type (this is being
// used to identify whether the stored data item in a particular
// token instance needs to be converted from the pair of
// iterators (see the first of the assign_to_attribute_from_value
// Note: The iterator pair needs to be the first type in the list of
// types supported by the generated variant type (this is being
// used to identify whether the stored data item in a particular
// token instance needs to be converted from the pair of
// iterators (see the first of the assign_to_attribute_from_value
// specializations below).
///////////////////////////////////////////////////////////////////////
template <typename IteratorPair, typename AttributeTypes>
@@ -298,22 +295,22 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
};
///////////////////////////////////////////////////////////////////////
// The type of the data item stored with a token instance is defined
// The type of the data item stored with a token instance is defined
// by the template parameter 'AttributeTypes' and may be:
//
// lex::omit: no data item is stored with the token
// instance (this is handled by the
//
// lex::omit: no data item is stored with the token
// instance (this is handled by the
// specializations of the token class
// below)
// mpl::vector0<>: each token instance stores a pair of
// iterators pointing to the matched input
// mpl::vector0<>: each token instance stores a pair of
// iterators pointing to the matched input
// sequence
// mpl::vector<...>: each token instance stores a variant being
// able to store the pair of iterators pointing
// to the matched input sequence, or any of the
// mpl::vector<...>: each token instance stores a variant being
// able to store the pair of iterators pointing
// to the matched input sequence, or any of the
// types a specified in the mpl::vector<>
//
// All this is done to ensure the token type is as small (in terms
// All this is done to ensure the token type is as small (in terms
// of its byte-size) as possible.
///////////////////////////////////////////////////////////////////////
template <typename IteratorPair, typename AttributeTypes>
@@ -332,16 +329,16 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
struct token : token<Iterator, lex::omit, HasState, Idtype>
{
private: // precondition assertions
BOOST_STATIC_ASSERT((mpl::is_sequence<AttributeTypes>::value ||
BOOST_STATIC_ASSERT((mpl::is_sequence<AttributeTypes>::value ||
is_same<AttributeTypes, lex::omit>::value));
typedef token<Iterator, lex::omit, HasState, Idtype> base_type;
protected:
// If no additional token value types are given, the token will
protected:
// If no additional token value types are given, the token will
// hold the plain pair of iterators pointing to the matched range
// in the underlying input sequence. Otherwise the token value is
// in the underlying input sequence. Otherwise the token value is
// stored as a variant and will again hold the pair of iterators but
// is able to hold any of the given data types as well. The conversion
// is able to hold any of the given data types as well. The conversion
// from the iterator pair to the required data type is done when it is
// accessed for the first time.
typedef iterator_range<Iterator> iterpair_type;
@@ -375,14 +372,14 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
token_value_type const& value() const { return value_; }
#if BOOST_WORKAROUND(BOOST_MSVC, == 1600)
// workaround for MSVC10 which has problems copying a default
// workaround for MSVC10 which has problems copying a default
// constructed iterator_range
token& operator= (token const& rhs)
{
if (this != &rhs)
if (this != &rhs)
{
this->base_type::operator=(static_cast<base_type const&>(rhs));
if (this->is_valid())
if (this->is_valid())
value_ = rhs.value_;
}
return *this;
@@ -397,21 +394,21 @@ namespace boost { namespace spirit { namespace lex { namespace lexertl
// tokens are considered equal, if their id's match (these are unique)
template <typename Iterator, typename AttributeTypes, typename HasState
, typename Idtype>
inline bool
operator== (token<Iterator, AttributeTypes, HasState, Idtype> const& lhs,
inline bool
operator== (token<Iterator, AttributeTypes, HasState, Idtype> const& lhs,
token<Iterator, AttributeTypes, HasState, Idtype> const& rhs)
{
return lhs.id() == rhs.id();
}
///////////////////////////////////////////////////////////////////////////
// This overload is needed by the multi_pass/functor_input_policy to
// validate a token instance. It has to be defined in the same namespace
// This overload is needed by the multi_pass/functor_input_policy to
// validate a token instance. It has to be defined in the same namespace
// as the token class itself to allow ADL to find it.
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename AttributeTypes, typename HasState
, typename Idtype>
inline bool
inline bool
token_is_valid(token<Iterator, AttributeTypes, HasState, Idtype> const& t)
{
return t.is_valid();
@@ -422,8 +419,8 @@ namespace boost { namespace spirit { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// We have to provide specializations for the customization point
// assign_to_attribute_from_value allowing to extract the needed value
// from the token.
// assign_to_attribute_from_value allowing to extract the needed value
// from the token.
///////////////////////////////////////////////////////////////////////////
// This is called from the parse function of token_def if the token_def
@@ -433,15 +430,15 @@ namespace boost { namespace spirit { namespace traits
struct assign_to_attribute_from_value<Attribute
, lex::lexertl::token<Iterator, AttributeTypes, HasState, Idtype> >
{
static void
static void
call(lex::lexertl::token<Iterator, AttributeTypes, HasState, Idtype> const& t
, Attribute& attr)
{
// The goal of this function is to avoid the conversion of the pair of
// iterators (to the matched character sequence) into the token value
// of the required type being done more than once. For this purpose it
// checks whether the stored value type is still the default one (pair
// of iterators) and if yes, replaces the pair of iterators with the
// iterators (to the matched character sequence) into the token value
// of the required type being done more than once. For this purpose it
// checks whether the stored value type is still the default one (pair
// of iterators) and if yes, replaces the pair of iterators with the
// converted value to be returned from subsequent calls.
if (0 == t.value().which()) {
@@ -449,38 +446,38 @@ namespace boost { namespace spirit { namespace traits
typedef iterator_range<Iterator> iterpair_type;
iterpair_type const& ip = boost::get<iterpair_type>(t.value());
// Interestingly enough we use the assign_to() framework defined in
// Spirit.Qi allowing to convert the pair of iterators to almost any
// required type (assign_to(), if available, uses the standard Spirit
// Interestingly enough we use the assign_to() framework defined in
// Spirit.Qi allowing to convert the pair of iterators to almost any
// required type (assign_to(), if available, uses the standard Spirit
// parsers to do the conversion).
spirit::traits::assign_to(ip.begin(), ip.end(), attr);
// If you get an error during the compilation of the following
// assignment expression, you probably forgot to list one or more
// types used as token value types (in your token_def<...>
// definitions) in your definition of the token class. I.e. any token
// value type used for a token_def<...> definition has to be listed
// during the declaration of the token type to use. For instance let's
// If you get an error during the compilation of the following
// assignment expression, you probably forgot to list one or more
// types used as token value types (in your token_def<...>
// definitions) in your definition of the token class. I.e. any token
// value type used for a token_def<...> definition has to be listed
// during the declaration of the token type to use. For instance let's
// assume we have two token_def's:
//
// token_def<int> number; number = "...";
// token_def<std::string> identifier; identifier = "...";
//
// Then you'll have to use the following token type definition
// Then you'll have to use the following token type definition
// (assuming you are using the token class):
//
// typedef mpl::vector<int, std::string> token_values;
// typedef token<base_iter_type, token_values> token_type;
//
// where: base_iter_type is the iterator type used to expose the
// where: base_iter_type is the iterator type used to expose the
// underlying input stream.
//
// This token_type has to be used as the second template parameter
// This token_type has to be used as the second template parameter
// to the lexer class:
//
// typedef lexer<base_iter_type, token_type> lexer_type;
//
// again, assuming you're using the lexer<> template for your
// again, assuming you're using the lexer<> template for your
// tokenization.
typedef lex::lexertl::token<
@@ -515,7 +512,7 @@ namespace boost { namespace spirit { namespace traits
struct assign_to_container_from_value<
iterator_range<Iterator>, iterator_range<Iterator> >
{
static void
static void
call(iterator_range<Iterator> const& val, iterator_range<Iterator>& attr)
{
attr = val;
@@ -523,18 +520,18 @@ namespace boost { namespace spirit { namespace traits
};
// These are called from the parse function of token_def if the token type
// has no special attribute type assigned
// has no special attribute type assigned
template <typename Attribute, typename Iterator, typename HasState
, typename Idtype>
struct assign_to_attribute_from_value<Attribute
, lex::lexertl::token<Iterator, mpl::vector0<>, HasState, Idtype> >
{
static void
static void
call(lex::lexertl::token<Iterator, mpl::vector0<>, HasState, Idtype> const& t
, Attribute& attr)
{
// The default type returned by the token_def parser component (if
// it has no token value type assigned) is the pair of iterators
// The default type returned by the token_def parser component (if
// it has no token value type assigned) is the pair of iterators
// to the matched character sequence.
spirit::traits::assign_to(t.value().begin(), t.value().end(), attr);
}
@@ -554,12 +551,12 @@ namespace boost { namespace spirit { namespace traits
struct assign_to_attribute_from_value<Attribute
, lex::lexertl::token<Iterator, mpl::vector<>, HasState, Idtype> >
{
static void
static void
call(lex::lexertl::token<Iterator, mpl::vector<>, HasState, Idtype> const& t
, Attribute& attr)
{
// The default type returned by the token_def parser component (if
// it has no token value type assigned) is the pair of iterators
// The default type returned by the token_def parser component (if
// it has no token value type assigned) is the pair of iterators
// to the matched character sequence.
spirit::traits::assign_to(t.value().begin(), t.value().end(), attr);
}
@@ -575,14 +572,14 @@ namespace boost { namespace spirit { namespace traits
// This is called from the parse function of token_def if the token type
// has been explicitly omitted (i.e. no attribute value is used), which
// essentially means that every attribute gets initialized using default
// essentially means that every attribute gets initialized using default
// constructed values.
template <typename Attribute, typename Iterator, typename HasState
, typename Idtype>
struct assign_to_attribute_from_value<Attribute
, lex::lexertl::token<Iterator, lex::omit, HasState, Idtype> >
{
static void
static void
call(lex::lexertl::token<Iterator, lex::omit, HasState, Idtype> const&
, Attribute&)
{
@@ -605,15 +602,15 @@ namespace boost { namespace spirit { namespace traits
fusion::vector2<Idtype_, iterator_range<Iterator> >
, lex::lexertl::token<Iterator, AttributeTypes, HasState, Idtype> >
{
static void
static void
call(lex::lexertl::token<Iterator, AttributeTypes, HasState, Idtype> const& t
, fusion::vector2<Idtype_, iterator_range<Iterator> >& attr)
{
// The type returned by the lexer_def_ parser components is a
// fusion::vector containing the token id of the matched token
// The type returned by the lexer_def_ parser components is a
// fusion::vector containing the token id of the matched token
// and the pair of iterators to the matched character sequence.
typedef iterator_range<Iterator> iterpair_type;
typedef fusion::vector2<Idtype_, iterator_range<Iterator> >
typedef fusion::vector2<Idtype_, iterator_range<Iterator> >
attribute_type;
iterpair_type const& ip = boost::get<iterpair_type>(t.value());
@@ -632,7 +629,7 @@ namespace boost { namespace spirit { namespace traits
{};
///////////////////////////////////////////////////////////////////////////
// Overload debug output for a single token, this integrates lexer tokens
// Overload debug output for a single token, this integrates lexer tokens
// with Qi's simple_trace debug facilities
template <typename Iterator, typename Attribute, typename HasState
, typename Idtype>
@@ -642,7 +639,7 @@ namespace boost { namespace spirit { namespace traits
typedef lex::lexertl::token<Iterator, Attribute, HasState, Idtype> token_type;
template <typename Out>
static void print(Out& out, token_type const& val)
static void print(Out& out, token_type const& val)
{
out << '[';
spirit::traits::print_token(out, val.value());

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013-2014 Agustin Berge
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,184 +9,142 @@
#define BOOST_SPIRIT_X3_AUXILIARY_ANY_PARSER_APR_09_2014_1145PM
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/subcontext.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/assert.hpp>
#include <iterator>
#include <boost/spirit/home/x3/support/traits/is_parser.hpp>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
// Type-erased parser that holds any underlying parser which models `X3Parser<It, It>`.
template <
std::forward_iterator It, // used only for polymorphism
typename Attribute = unused_type,
typename Context = unused_type // used only for polymorphism
>
struct any_parser : parser<any_parser<It, Attribute, Context>>
typename Iterator
, typename Attribute = unused_type
, typename Context = subcontext<>>
struct any_parser : parser<any_parser<Iterator, Attribute, Context>>
{
// `any_parser` existed historically because writing a type-erased parser in C++
// was cumbersome before modern language features. Its use is now discouraged for
// technical reasons:
//
// 1) Performance: type erasure places dynamic indirection on the parsing hot path.
// Every token step must operate through type-erased iterators/contexts,
// inhibiting inlining and adding dispatch overhead.
//
// 2) Formal grounds: PEGs are deterministic (ordered choice) and do not require
// runtime reification of the grammar. The same behaviors can be expressed as
// a static composition of parsers with semantic predicates.
//
// 3) Empirical evidence: a GitHub full-text search indicates that `any_parser`
// is rarely used in practice.
//
// Reaching for `any_parser` means attempting to *define* the right-hand side of the
// grammar dynamically from the left-hand side of the input. That indirection is
// unnecessary in PEG; you can always structure the grammar statically. If more
// complex branching is required, use the symbols parser or design a fully featured
// parser class for your specific grammar.
//
// Note for X3 developers: if we allow the existence of `any_parser`, it would become
// a very undesirable technical burden which prohibits the future enhancements.
// Imagine that we're implementing an out-of-the-box packrat memoization support in
// the future. The existence of `any_parser` makes the situation undesirably complex,
// as we need to consider the *dynamic* properties of stateful parsers.
typedef Attribute attribute_type;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<Attribute, unused_type>;
static constexpr bool handles_container = traits::is_container<Attribute>::value;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
static bool const handles_container =
traits::is_container<Attribute>::value;
public:
constexpr any_parser() = default;
any_parser() = default;
template <typename Parser>
requires
(!std::is_same_v<std::remove_cvref_t<Parser>, any_parser>) &&
X3Parser<Parser, It, It>
[[deprecated(
"`any_parser` is deprecated. Prefer static grammar "
"(e.g. `a_prefix >> a_body | b_prefix >> b_body`) or "
"static branching (e.g. `x3::eps[lazy_cond_func] >> a | b`)."
)]]
constexpr any_parser(Parser&& parser)
: parser_(std::make_unique<holder<as_parser_plain_t<Parser>>>(
std::forward<Parser>(parser)
))
{}
template <typename Expr,
typename Enable = typename enable_if<traits::is_parser<Expr>>::type>
any_parser(Expr const& expr)
: _content(new holder<Expr>(expr)) {}
constexpr any_parser(any_parser const& other)
: parser_(other.parser_ ? other.parser_->clone() : nullptr)
{}
any_parser(any_parser const& other)
: _content(other._content ? other._content->clone() : nullptr) {}
constexpr any_parser(any_parser&& other) = default;
any_parser(any_parser&& other) = default;
constexpr any_parser& operator=(any_parser const& other)
any_parser& operator=(any_parser const& other)
{
parser_.reset(other.parser_ ? other.parser_->clone() : nullptr);
_content.reset(other._content ? other._content->clone() : nullptr);
return *this;
}
any_parser& operator=(any_parser&& other) = default;
// Runtime attribute is the same type as the predefined attribute type
template <std::forward_iterator It_, std::sentinel_for<It_> Se_, typename Context_>
[[nodiscard]] constexpr bool
parse(
It_& first, Se_ const& last,
Context_ const& context, unused_type, Attribute& attr
) const
template <typename Iterator_, typename Context_>
bool parse(Iterator_& first, Iterator_ const& last
, Context_ const& context, unused_type, Attribute& attr) const
{
static_assert(std::is_same_v<It_, It>, "Runtime iterator type must match `any_parser`'s iterator type");
BOOST_ASSERT_MSG(parser_ != nullptr, "Invalid use of uninitialized any_parser");
BOOST_STATIC_ASSERT_MSG(
(is_same<Iterator, Iterator_>::value)
, "Incompatible iterator used"
);
return parser_->parse(first, last, context, attr);
BOOST_ASSERT_MSG(
(_content != nullptr)
, "Invalid use of uninitialized any_parser"
);
return _content->parse(first, last, context, attr);
}
// Runtime attribute is NOT the same type as the predefined attribute type
template <std::forward_iterator It_, std::sentinel_for<It_> Se_, typename Context_, typename Attribute_>
[[nodiscard]] constexpr bool
parse(
It_& first, Se_ const& last,
Context_ const& context, unused_type, Attribute_& attr_
) const
template <typename Iterator_, typename Context_, typename Attribute_>
bool parse(Iterator_& first, Iterator_ const& last
, Context_ const& context, unused_type, Attribute_& attr_) const
{
Attribute attr; // default-initialize
if (this->parse(first, last, context, unused, attr))
Attribute attr;
if (parse(first, last, context, unused, attr))
{
traits::move_to(std::move(attr), attr_);
traits::move_to(attr, attr_);
return true;
}
return false;
}
[[nodiscard]] constexpr std::string get_x3_info() const
std::string get_info() const
{
return parser_ ? parser_->get_x3_info() : "(uninitialized `any_parser`)";
return _content ? _content->get_info() : "";
}
private:
struct placeholder
{
constexpr virtual ~placeholder() = default;
virtual placeholder* clone() const = 0;
[[nodiscard]]
constexpr virtual std::unique_ptr<placeholder> clone() const = 0;
virtual bool parse(Iterator& first, Iterator const& last
, Context const& context, Attribute& attr) const = 0;
[[nodiscard]]
constexpr virtual bool parse(
It& first, It const& last, Context const& context, Attribute& attr
) const = 0;
virtual std::string get_info() const = 0;
[[nodiscard]]
constexpr virtual std::string get_x3_info() const = 0;
virtual ~placeholder() {}
};
template <X3Parser<It, It> Parser>
template <typename Expr>
struct holder : placeholder
{
template <X3Subject Subject>
requires is_parser_constructible_v<Parser, Subject>
constexpr explicit holder(Subject&& subject)
noexcept(is_parser_nothrow_constructible_v<Parser, Subject>)
: parser_(as_parser(std::forward<Subject>(subject)))
{}
typedef typename extension::as_parser<Expr>::value_type parser_type;
[[nodiscard]]
constexpr std::unique_ptr<placeholder> clone() const override
explicit holder(Expr const& p)
: _parser(as_parser(p)) {}
holder* clone() const override
{
return std::make_unique<holder>(*this);
return new holder(*this);
}
[[nodiscard]]
constexpr bool parse(
It& first, It const& last,
Context const& context, Attribute& attr
) const override
bool parse(Iterator& first, Iterator const& last
, Context const& context, Attribute& attr) const override
{
static_assert(Parsable<Parser, It, It, Context, unused_type, Attribute>);
return parser_.parse(first, last, context, unused, attr);
return _parser.parse(first, last, context, unused, attr);
}
[[nodiscard]]
constexpr std::string get_x3_info() const override
std::string get_info() const override
{
return x3::what(parser_);
return x3::what(_parser);
}
private:
Parser parser_;
parser_type _parser;
};
std::unique_ptr<placeholder> parser_;
private:
std::unique_ptr<placeholder> _content;
};
} // boost::spirit::x3
template <typename Iterator, typename Attribute, typename Context>
struct get_info<any_parser<Iterator, Attribute, Context>>
{
typedef std::string result_type;
std::string operator()(
any_parser<Iterator, Attribute, Context> const& p) const
{
return p.get_info();
}
};
}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -12,79 +12,57 @@
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/error_handler_types.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
enum class error_handler_result
{
fail
, retry
, accept
, rethrow // see BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE for alternative behaviors
};
template <typename Subject, typename Handler>
struct guard : unary_parser<Subject, guard<Subject, Handler>>
{
static_assert(
!std::is_reference_v<Handler>,
"Reference type is disallowed for `Handler` to prevent dangling reference"
);
typedef unary_parser<Subject, guard<Subject, Handler>> base_type;
static bool const is_pass_through_unary = true;
using base_type = unary_parser<Subject, guard<Subject, Handler>>;
static constexpr bool is_pass_through_unary = true;
constexpr guard(Subject const& subject, Handler handler)
: base_type(subject), handler(handler) {}
Handler handler;
template <typename SubjectT, typename HandlerT>
requires std::is_constructible_v<Subject, SubjectT> && std::is_constructible_v<Handler, HandlerT>
constexpr guard(SubjectT&& subject, HandlerT&& handler)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT> && std::is_nothrow_constructible_v<Handler, HandlerT>)
: base_type(std::forward<SubjectT>(subject))
, handler(std::forward<HandlerT>(handler))
{}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
// never noexcept; requires complex implementation details
template <typename Iterator, typename Context
, typename RuleContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, Attribute& attr) const
{
static_assert(Parsable<Subject, It, Se, Context, RContext, Attribute>);
while (true)
for (;;)
{
It saved_it = first;
Iterator i = first;
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
try
#endif
{
if (this->subject.parse(saved_it, last, context, rcontext, attr))
if (this->subject.parse(i, last, context, rcontext, attr))
{
first = saved_it;
first = i;
return true;
}
}
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
catch (expectation_failure<It> const& x) {
catch (expectation_failure<Iterator> const& x) {
#else
if (x3::has_expectation_failure(context)) {
auto const& x = x3::get_expectation_failure(context);
if (has_expectation_failure(context)) {
auto& x = get_expectation_failure(context);
#endif
static_assert(
std::is_invocable_r_v<
error_handler_result,
Handler const&,
It const&, Se const&,
std::remove_cvref_t<decltype(x)> const&,
Context const&
>,
"x3::guard: `Handler`'s signature is wrong"
);
// X3 developer note: don't forget to sync this implementation with x3::detail::rule_parser
switch (handler(std::as_const(first), std::as_const(last), x, context))
switch (handler(first, last, x, context))
{
case error_handler_result::fail:
x3::clear_expectation_failure(context);
clear_expectation_failure(context);
return false;
case error_handler_result::retry:
@@ -104,7 +82,9 @@ namespace boost::spirit::x3
return false;
}
}
Handler handler;
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,56 +7,62 @@
#if !defined(BOOST_SPIRIT_X3_ANY_CHAR_APRIL_16_2006_1051AM)
#define BOOST_SPIRIT_X3_ANY_CHAR_APRIL_16_2006_1051AM
#include <boost/type_traits/extent.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp>
#include <boost/spirit/home/x3/char/char_set.hpp>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Encoding>
struct any_char : char_parser<any_char<Encoding>>
{
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = char_type;
static constexpr bool has_attribute = true;
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef char_type attribute_type;
static bool const has_attribute = true;
template <typename Context>
[[nodiscard]] static constexpr bool test(char_type ch, Context const&) noexcept
template <typename Char, typename Context>
bool test(Char ch_, Context const&) const
{
return encoding::ischar(ch);
return encoding::ischar(ch_);
}
[[nodiscard]] static constexpr literal_char<Encoding> operator()(char_type ch) noexcept
template <typename Char>
constexpr literal_char<Encoding> operator()(Char ch) const
{
return { ch };
}
[[nodiscard]] static constexpr literal_char<Encoding> operator()(char_type const (&ch)[2]) noexcept
template <typename Char>
constexpr literal_char<Encoding> operator()(const Char (&ch)[2]) const
{
return { ch[0] };
}
template <std::size_t N>
[[nodiscard]] static constexpr char_set<Encoding> operator()(char_type const (&ch)[N]) noexcept
template <typename Char, std::size_t N>
constexpr char_set<Encoding> operator()(const Char (&ch)[N]) const
{
return { ch };
}
[[nodiscard]] static constexpr char_range<Encoding> operator()(char_type from, char_type to) noexcept
template <typename Char>
constexpr char_range<Encoding> operator()(Char from, Char to) const
{
return { from, to };
}
[[nodiscard]] static constexpr char_range<Encoding> operator()(char_type const (&from)[2], char_type const (&to)[2]) noexcept
template <typename Char>
constexpr char_range<Encoding> operator()(Char (&from)[2], Char (&to)[2]) const
{
return { static_cast<char_type>(from[0]), static_cast<char_type>(to[0]) };
}
[[nodiscard]] static char_set<Encoding> operator()(std::basic_string_view<char_type> sv) noexcept
template <typename Char>
char_set<Encoding> operator()(std::basic_string<Char> const& s) const
{
return { std::move(sv) };
return { s };
}
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,143 +8,84 @@
#define BOOST_SPIRIT_X3_CHAR_APRIL_16_2006_1051AM
#include <boost/spirit/home/x3/char/any_char.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp>
#include <boost/spirit/home/x3/support/traits/string_traits.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/ascii.hpp> // deprecated
#include <boost/spirit/home/x3/char_encoding/iso8859_1.hpp> // deprecated
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
# include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#endif
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
#include <type_traits>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
namespace standard
{
inline constexpr any_char<char_encoding::standard> char_{};
typedef any_char<char_encoding::standard> char_type;
constexpr auto char_ = char_type{};
inline namespace helpers
constexpr literal_char<char_encoding::standard, unused_type>
lit(char ch)
{
[[nodiscard]] constexpr literal_char<char_encoding::standard, unused_type>
lit(char ch) noexcept
{
return { ch };
}
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::standard, unused_type>
lit(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
} // helpers
constexpr literal_char<char_encoding::standard, unused_type>
lit(wchar_t ch)
{
return { ch };
}
// If you see "no matching overload" on string literals (e.g. `"foo"`),
// you may need to include `x3/string/literal_string.hpp`.
// If you still see errors after the inclusion, that might be due to
// mixing incompatible string literals. Don't do that.
constexpr void lit(traits::CharIncompatibleWith<char> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char> auto) = delete; // Mixing incompatible character types is not allowed
}
inline constexpr auto const& char_ = standard::char_; // TODO: this can't overload other character types
using standard::helpers::lit;
using standard::char_type;
using standard::char_;
using standard::lit;
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
namespace standard_wide
{
inline constexpr any_char<char_encoding::standard_wide> char_{};
typedef any_char<char_encoding::standard_wide> char_type;
constexpr auto char_ = char_type{};
inline namespace helpers
constexpr literal_char<char_encoding::standard_wide, unused_type>
lit(wchar_t ch)
{
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, unused_type>
lit(wchar_t ch) noexcept
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, unused_type>
lit(traits::X3VagueArrayOf2Chars<wchar_t> auto const& ch) noexcept
{
return { ch[0] };
}
} // helpers
constexpr void lit(traits::CharIncompatibleWith<wchar_t> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<wchar_t> auto) = delete; // Mixing incompatible character types is not allowed
return { ch };
}
}
using standard_wide::helpers::lit;
#endif
#ifdef BOOST_SPIRIT_X3_UNICODE
namespace unicode
{
inline constexpr any_char<char_encoding::unicode> char_{};
inline namespace helpers
{
// TODO: add `char8_t` and `char16_t` overloads
[[nodiscard]] constexpr literal_char<char_encoding::unicode, unused_type>
lit(char32_t ch) noexcept
{
return { ch };
}
[[nodiscard]] constexpr literal_char<char_encoding::unicode, unused_type>
lit(traits::X3VagueArrayOf2Chars<char32_t> auto const& ch) noexcept
{
return { ch[0] };
}
} // helpers
constexpr void lit(traits::CharIncompatibleWith<char32_t> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char32_t> auto) = delete; // Mixing incompatible character types is not allowed
}
using unicode::helpers::lit;
#endif
namespace ascii
{
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
inline constexpr any_char<char_encoding::ascii> char_{};
typedef any_char<char_encoding::ascii> char_type;
constexpr auto char_ = char_type{};
[[nodiscard, deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
constexpr literal_char<char_encoding::ascii, unused_type>
lit(char ch) noexcept
lit(char ch)
{
return { ch };
}
constexpr void lit(traits::CharIncompatibleWith<char> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char> auto) = delete; // Mixing incompatible character types is not allowed
constexpr literal_char<char_encoding::ascii, unused_type>
lit(wchar_t ch)
{
return { ch };
}
}
namespace iso8859_1
{
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
inline constexpr any_char<char_encoding::iso8859_1> char_{};
typedef any_char<char_encoding::iso8859_1> char_type;
constexpr auto char_ = char_type{};
[[nodiscard, deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
constexpr literal_char<char_encoding::iso8859_1, unused_type>
lit(char ch) noexcept
lit(char ch)
{
return { ch };
}
constexpr void lit(traits::CharIncompatibleWith<char> auto const*) = delete; // Mixing incompatible character types is not allowed
constexpr void lit(traits::CharIncompatibleWith<char> auto) = delete; // Mixing incompatible character types is not allowed
constexpr literal_char<char_encoding::iso8859_1, unused_type>
lit(wchar_t ch)
{
return { ch };
}
}
namespace extension
@@ -153,23 +93,29 @@ namespace boost::spirit::x3
template <>
struct as_parser<char>
{
using type = literal_char<char_encoding::standard, unused_type>;
using value_type = type;
typedef literal_char<
char_encoding::standard, unused_type>
type;
[[nodiscard]] static constexpr type call(char ch) noexcept
typedef type value_type;
static constexpr type call(char ch)
{
return { ch };
}
};
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
template <>
struct as_parser<wchar_t>
{
using type = literal_char<char_encoding::standard_wide, unused_type>;
using value_type = type;
typedef literal_char<
char_encoding::standard_wide, unused_type>
type;
[[nodiscard]] static constexpr type call(wchar_t ch) noexcept
typedef type value_type;
static constexpr type call(wchar_t ch)
{
return { ch };
}
@@ -179,30 +125,37 @@ namespace boost::spirit::x3
template <>
struct as_parser<char [2]>
{
using type = literal_char<char_encoding::standard, unused_type>;
using value_type = type;
typedef literal_char<
char_encoding::standard, unused_type>
type;
[[nodiscard]] static constexpr type call(char const ch[]) noexcept
typedef type value_type;
static constexpr type call(char const ch[])
{
return { ch[0] };
}
};
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
template <>
struct as_parser<wchar_t [2]>
{
using type = literal_char<char_encoding::standard_wide, unused_type>;
using value_type = type;
typedef literal_char<
char_encoding::standard_wide, unused_type>
type;
[[nodiscard]] static constexpr type call(wchar_t const ch[]) noexcept
typedef type value_type;
static constexpr type call(wchar_t const ch[] )
{
return { ch[0] };
}
};
#endif
}
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,31 +8,30 @@
#define BOOST_SPIRIT_X3_CHAR_CLASS_APRIL_16_2006_1051AM
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/char/char_class_tags.hpp>
#include <boost/spirit/home/x3/char/detail/cast_char.hpp>
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/x3/char_encoding/ascii.hpp>
#include <boost/spirit/home/x3/char_encoding/iso8859_1.hpp>
namespace boost::spirit::x3
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/x3/char/char_class_tags.hpp>
namespace boost { namespace spirit { namespace x3
{
///////////////////////////////////////////////////////////////////////////
template <typename Encoding>
struct char_class_base
{
using char_type = typename Encoding::classify_type;
typedef typename Encoding::classify_type char_type;
#define BOOST_SPIRIT_X3_CLASSIFY(name) \
template <typename Char> \
[[nodiscard]] static constexpr bool \
is(name##_tag, Char ch) noexcept \
static bool \
is(name##_tag, Char ch) \
{ \
return (Encoding::is##name) \
return Encoding::is##name \
BOOST_PREVENT_MACRO_SUBSTITUTION \
(detail::cast_char<char_type>(ch)); \
}
} \
/***/
BOOST_SPIRIT_X3_CLASSIFY(char)
BOOST_SPIRIT_X3_CLASSIFY(alnum)
@@ -53,26 +51,28 @@ namespace boost::spirit::x3
};
template <typename Encoding, typename Tag>
struct char_class : char_parser<char_class<Encoding, Tag>>
struct char_class
: char_parser<char_class<Encoding, Tag>>
{
using encoding = Encoding;
using tag = Tag;
using char_type = typename Encoding::char_type;
using attribute_type = char_type;
static constexpr bool has_attribute = true;
typedef Encoding encoding;
typedef Tag tag;
typedef typename Encoding::char_type char_type;
typedef char_type attribute_type;
static bool const has_attribute = true;
template <typename Char, typename Context>
[[nodiscard]] constexpr bool test(Char ch, Context const& context) const noexcept
bool test(Char ch, Context const& context) const
{
return encoding::ischar(ch)
&& char_class_base<Encoding>::is(
x3::get_case_compare<Encoding>(context).get_char_class_tag(tag()), ch);
get_case_compare<Encoding>(context).get_char_class_tag(tag()), ch);
}
};
#define BOOST_SPIRIT_X3_CHAR_CLASS(encoding, name) \
using name##_type = char_class<char_encoding::encoding, name##_tag>; \
inline constexpr name##_type name{};
typedef char_class<char_encoding::encoding, name##_tag> name##_type; \
constexpr name##_type name = name##_type(); \
/***/
#define BOOST_SPIRIT_X3_CHAR_CLASSES(encoding) \
namespace encoding \
@@ -89,46 +89,44 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, space) \
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, blank) \
BOOST_SPIRIT_X3_CHAR_CLASS(encoding, upper) \
}
} \
/***/
BOOST_SPIRIT_X3_CHAR_CLASSES(standard)
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
BOOST_SPIRIT_X3_CHAR_CLASSES(standard_wide)
#endif
BOOST_SPIRIT_X3_CHAR_CLASSES(ascii)
BOOST_SPIRIT_X3_CHAR_CLASSES(iso8859_1)
#undef BOOST_SPIRIT_X3_CHAR_CLASS
#undef BOOST_SPIRIT_X3_CHAR_CLASSES
using alnum_type = standard::alnum_type;
using alpha_type = standard::alpha_type;
using digit_type = standard::digit_type;
using xdigit_type = standard::xdigit_type;
using cntrl_type = standard::cntrl_type;
using graph_type = standard::graph_type;
using lower_type = standard::lower_type;
using print_type = standard::print_type;
using punct_type = standard::punct_type;
using space_type = standard::space_type;
using blank_type = standard::blank_type;
using upper_type = standard::upper_type;
using standard::alnum_type;
using standard::alpha_type;
using standard::digit_type;
using standard::xdigit_type;
using standard::cntrl_type;
using standard::graph_type;
using standard::lower_type;
using standard::print_type;
using standard::punct_type;
using standard::space_type;
using standard::blank_type;
using standard::upper_type;
inline constexpr auto const& alnum = standard::alnum;
inline constexpr auto const& alpha = standard::alpha;
inline constexpr auto const& digit = standard::digit;
inline constexpr auto const& xdigit = standard::xdigit;
inline constexpr auto const& cntrl = standard::cntrl;
inline constexpr auto const& graph = standard::graph;
inline constexpr auto const& lower = standard::lower;
inline constexpr auto const& print = standard::print;
inline constexpr auto const& punct = standard::punct;
inline constexpr auto const& space = standard::space;
inline constexpr auto const& blank = standard::blank;
inline constexpr auto const& upper = standard::upper;
} // boost::spirit::x3
using standard::alnum;
using standard::alpha;
using standard::digit;
using standard::xdigit;
using standard::cntrl;
using standard::graph;
using standard::lower;
using standard::print;
using standard::punct;
using standard::space;
using standard::blank;
using standard::upper;
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -13,28 +12,29 @@
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/no_case.hpp>
#include <iterator>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
///////////////////////////////////////////////////////////////////////////
// The base char_parser
///////////////////////////////////////////////////////////////////////////
template <typename Derived>
struct char_parser : parser<Derived>
{
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
[[nodiscard]] constexpr bool parse(
It& first, Se const& last, Context const& context, unused_type, Attribute& attr
) const // I (saki7) don't think this can ever be noexcept, due to the nature of the operations below
template <typename Iterator, typename Context, typename Attribute>
bool parse(
Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute& attr) const
{
x3::skip_over(first, last, context);
if (first != last && this->derived().test(*first, context))
{
x3::traits::move_to(std::iter_value_t<It>{*first}, attr);
x3::traits::move_to(*first, attr);
++first;
return true;
}
return false;
}
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,73 +9,72 @@
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/char/detail/cast_char.hpp>
#include <boost/spirit/home/x3/char/detail/basic_chset.hpp>
#include <boost/spirit/home/x3/support/traits/string_traits.hpp>
#include <boost/spirit/home/x3/support/utility/utf8.hpp>
#include <boost/spirit/home/x3/support/no_case.hpp>
#include <boost/spirit/home/support/char_set/basic_chset.hpp>
#include <ranges>
#include <string_view>
#include <type_traits>
#include <boost/type_traits/is_same.hpp>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
///////////////////////////////////////////////////////////////////////////
// Parser for a character range
///////////////////////////////////////////////////////////////////////////
template <typename Encoding, typename Attribute = typename Encoding::char_type>
struct char_range : char_parser<char_range<Encoding, Attribute>>
struct char_range
: char_parser< char_range<Encoding, Attribute> >
{
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
constexpr char_range(char_type from_, char_type to_) noexcept
: from(from_), to(to_)
{}
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
constexpr char_range(char_type from_, char_type to_)
: from(from_), to(to_) {}
template <typename Char, typename Context>
requires (std::is_convertible_v<std::remove_cvref_t<Char>, char_type>)
[[nodiscard]] constexpr bool test(Char ch_, Context const& context) const noexcept
bool test(Char ch_, Context const& context) const
{
char_type ch = static_cast<char_type>(ch_); // optimize for token based parsing
return (x3::get_case_compare<encoding>(context)(ch, from) >= 0)
&& (x3::get_case_compare<encoding>(context)(ch , to) <= 0);
char_type ch = char_type(ch_); // optimize for token based parsing
return (get_case_compare<encoding>(context)(ch, from) >= 0)
&& (get_case_compare<encoding>(context)(ch , to) <= 0);
}
char_type from, to;
};
///////////////////////////////////////////////////////////////////////////
// Parser for a character set
///////////////////////////////////////////////////////////////////////////
template <typename Encoding, typename Attribute = typename Encoding::char_type>
struct char_set : char_parser<char_set<Encoding, Attribute>>
{
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
template<std::ranges::forward_range R>
constexpr char_set(R const& str)
noexcept(detail::cast_char_noexcept<std::ranges::range_value_t<R>, char_type>)
template <typename String>
char_set(String const& str)
{
static_assert(detail::cast_char_viable<std::ranges::range_value_t<R>, char_type>);
using spirit::x3::detail::cast_char;
using detail::cast_char; // ADL introduction
for (auto definition = std::ranges::begin(str); definition != std::ranges::end(str);)
auto* definition = traits::get_c_string(str);
auto ch = *definition++;
while (ch)
{
auto const ch = *definition;
auto next_definition = std::next(definition);
if (next_definition == std::ranges::end(str))
auto next = *definition++;
if (next == '-')
{
chset.set(cast_char<char_type>(ch));
break;
}
auto next_ch = *next_definition;
if (next_ch == '-')
{
next_definition = std::next(next_definition);
if (next_definition == std::ranges::end(str))
next = *definition++;
if (next == 0)
{
chset.set(cast_char<char_type>(ch));
chset.set('-');
@@ -84,47 +82,46 @@ namespace boost::spirit::x3
}
chset.set(
cast_char<char_type>(ch),
cast_char<char_type>(*next_definition)
cast_char<char_type>(next)
);
}
else
{
chset.set(cast_char<char_type>(ch));
}
definition = next_definition;
ch = next;
}
}
template <typename Char, typename Context>
[[nodiscard]] constexpr bool test(Char ch_, Context const& context) const noexcept
bool test(Char ch_, Context const& context) const
{
return x3::get_case_compare<encoding>(context).in_set(ch_, chset);
return get_case_compare<encoding>(context).in_set(ch_, chset);
}
detail::basic_chset<char_type> chset;
support::detail::basic_chset<char_type> chset;
};
template <typename Encoding, typename Attribute>
struct get_info<char_set<Encoding, Attribute>>
{
using result_type = std::string;
[[nodiscard]] constexpr std::string operator()(char_set<Encoding, Attribute> const& /* p */) const
typedef std::string result_type;
std::string operator()(char_set<Encoding, Attribute> const& /* p */) const
{
return "char-set"; // TODO: make more user-friendly
return "char-set";
}
};
template <typename Encoding, typename Attribute>
struct get_info<char_range<Encoding, Attribute>>
{
using result_type = std::string;
[[nodiscard]] constexpr std::string operator()(char_range<Encoding, Attribute> const& p) const
typedef std::string result_type;
std::string operator()(char_range<Encoding, Attribute> const& p) const
{
// TODO: make more user-friendly && make the format consistent with above
return "char_range \"" + x3::to_utf8(Encoding::toucs4(p.from)) + '-' + x3::to_utf8(Encoding::toucs4(p.to))+ '"';
return "char_range \"" + to_utf8(Encoding::toucs4(p.from)) + '-' + to_utf8(Encoding::toucs4(p.to))+ '"';
}
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,235 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2001-2009 Daniel Nuffer
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_DETAIL_BASIC_CHSET_HPP
#define BOOST_SPIRIT_X3_CHAR_DETAIL_BASIC_CHSET_HPP
#include <boost/spirit/home/x3/char/detail/char_range_run.hpp>
#include <bitset>
#include <climits>
namespace boost::spirit::x3::detail
{
// basic character set implementation using char_range_run
template <typename CharT>
struct basic_chset
{
[[nodiscard]] constexpr bool
test(CharT v) const noexcept
{
return rr.test(v);
}
constexpr void
set(CharT from, CharT to) noexcept
{
rr.set(char_range<CharT>(from, to));
}
constexpr void
set(CharT c) noexcept
{
rr.set(char_range<CharT>(c, c));
}
constexpr void
clear(CharT from, CharT to) noexcept
{
rr.clear(char_range<CharT>(from, to));
}
constexpr void
clear(CharT c) noexcept
{
rr.clear(char_range<CharT>(c, c));
}
constexpr void
clear() noexcept
{
rr.clear();
}
constexpr void
inverse() noexcept
{
basic_chset inv;
inv.set(
(std::numeric_limits<CharT>::min)(),
(std::numeric_limits<CharT>::max)()
);
inv -= *this;
swap(inv);
}
constexpr void
swap(basic_chset& x) noexcept
{
rr.swap(x.rr);
}
constexpr basic_chset&
operator|=(basic_chset const& x) noexcept
{
typedef typename char_range_run<CharT>::const_iterator const_iterator;
for (const_iterator iter = x.rr.begin(); iter != x.rr.end(); ++iter)
rr.set(*iter);
return *this;
}
constexpr basic_chset&
operator&=(basic_chset const& x) noexcept
{
basic_chset inv;
inv.set(
(std::numeric_limits<CharT>::min)(),
(std::numeric_limits<CharT>::max)()
);
inv -= x;
*this -= inv;
return *this;
}
constexpr basic_chset&
operator-=(basic_chset const& x) noexcept
{
typedef typename char_range_run<CharT>::const_iterator const_iterator;
for (const_iterator iter = x.rr.begin(); iter != x.rr.end(); ++iter)
rr.clear(*iter);
return *this;
}
constexpr basic_chset&
operator^=(basic_chset const& x) noexcept
{
basic_chset bma = x;
bma -= *this;
*this -= x;
*this |= bma;
return *this;
}
private:
char_range_run<CharT> rr;
};
#if (CHAR_BIT == 8)
///////////////////////////////////////////////////////////////////////////
//
// basic_chset: specializations for 8 bit chars using std::bitset
//
///////////////////////////////////////////////////////////////////////////
template <typename CharT>
struct basic_chset_8bit
{
[[nodiscard]] constexpr bool
test(CharT v) const noexcept
{
return bset.test((unsigned char)v);
}
constexpr void
set(CharT from, CharT to) noexcept
{
for (int i = from; i <= to; ++i)
bset.set((unsigned char)i);
}
constexpr void
set(CharT c) noexcept
{
bset.set((unsigned char)c);
}
constexpr void
clear(CharT from, CharT to) noexcept
{
for (int i = from; i <= to; ++i)
bset.reset((unsigned char)i);
}
constexpr void
clear(CharT c) noexcept
{
bset.reset((unsigned char)c);
}
constexpr void
clear() noexcept
{
bset.reset();
}
constexpr void
inverse() noexcept
{
bset.flip();
}
constexpr void
swap(basic_chset_8bit& x) noexcept
{
std::swap(bset, x.bset);
}
constexpr basic_chset_8bit&
operator|=(basic_chset_8bit const& x) noexcept
{
bset |= x.bset;
return *this;
}
constexpr basic_chset_8bit&
operator&=(basic_chset_8bit const& x) noexcept
{
bset &= x.bset;
return *this;
}
constexpr basic_chset_8bit&
operator-=(basic_chset_8bit const& x) noexcept
{
bset &= ~x.bset;
return *this;
}
constexpr basic_chset_8bit&
operator^=(basic_chset_8bit const& x) noexcept
{
bset ^= x.bset;
return *this;
}
private:
std::bitset<256> bset;
};
/////////////////////////////////
template <>
struct basic_chset<char>
: basic_chset_8bit<char> {};
/////////////////////////////////
template <>
struct basic_chset<signed char>
: basic_chset_8bit<signed char> {};
/////////////////////////////////
template <>
struct basic_chset<unsigned char>
: basic_chset_8bit<unsigned char> {};
#endif // #if (CHAR_BIT == 8)
} // boost::spirit::x3::detail
#endif

View File

@@ -1,18 +1,18 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CAST_CHAR_NOVEMBER_10_2006_0907AM
#if !defined(BOOST_SPIRIT_X3_CAST_CHAR_NOVEMBER_10_2006_0907AM)
#define BOOST_SPIRIT_X3_CAST_CHAR_NOVEMBER_10_2006_0907AM
#include <type_traits>
#include <concepts>
#include <boost/type_traits/is_signed.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/make_signed.hpp>
namespace boost::spirit::x3::detail
namespace boost { namespace spirit { namespace x3 { namespace detail
{
// Here's the thing... typical encodings (except ASCII) deal with unsigned
// integers > 127 (ASCII uses only 127). Yet, most char and wchar_t are signed.
@@ -24,19 +24,25 @@ namespace boost::spirit::x3::detail
// optimizer will optimize the if-else branches}
template <typename TargetChar, typename SourceChar>
[[nodiscard]] constexpr TargetChar cast_char(SourceChar ch) noexcept
TargetChar cast_char(SourceChar ch)
{
if constexpr (std::is_signed_v<TargetChar> != std::is_signed_v<SourceChar>)
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
#endif
if (is_signed<TargetChar>::value != is_signed<SourceChar>::value)
{
if constexpr (std::is_signed_v<SourceChar>)
if (is_signed<SourceChar>::value)
{
// source is signed, target is unsigned
return TargetChar(static_cast<std::make_unsigned_t<SourceChar>>(ch));
// source is signed, target is unsigned
typedef typename make_unsigned<SourceChar>::type USourceChar;
return TargetChar(USourceChar(ch));
}
else
{
// source is unsigned, target is signed
return TargetChar(static_cast<std::make_signed_t<SourceChar>>(ch));
// source is unsigned, target is signed
typedef typename make_signed<SourceChar>::type SSourceChar;
return TargetChar(SSourceChar(ch));
}
}
else
@@ -44,17 +50,12 @@ namespace boost::spirit::x3::detail
// source and target has same signedness
return TargetChar(ch); // just cast
}
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
}
template <typename SourceChar, typename TargetChar>
concept cast_char_viable = requires(SourceChar ch) {
{ cast_char<TargetChar>(ch) } -> std::convertible_to<TargetChar>;
};
template <typename SourceChar, typename TargetChar>
concept cast_char_noexcept = requires(SourceChar ch) {
{ cast_char<TargetChar>(ch) } noexcept -> std::convertible_to<TargetChar>;
};
} // boost::spirit::x3::detail
}}}}
#endif

View File

@@ -1,40 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_DETAIL_CHAR_RANGE_HPP
#define BOOST_SPIRIT_X3_CHAR_DETAIL_CHAR_RANGE_HPP
#include <type_traits>
#include <utility>
namespace boost::spirit::x3::detail
{
// A closed range [first, last]
template <typename CharT>
struct char_range
{
static_assert(std::is_default_constructible_v<CharT>);
static_assert(std::is_copy_constructible_v<CharT> && std::is_copy_assignable_v<CharT>);
using value_type = CharT;
constexpr char_range() noexcept(std::is_nothrow_default_constructible_v<CharT>) = default;
template<class A, class B>
requires std::is_constructible_v<CharT, A> && std::is_constructible_v<CharT, B>
constexpr char_range(A&& first, B&& last)
noexcept(std::is_nothrow_constructible_v<CharT, A> && std::is_nothrow_constructible_v<CharT, B>)
: first(std::forward<A>(first))
, last(std::forward<B>(last))
{}
CharT first{};
CharT last{};
};
} // boost::spirit::x3::detail
#endif

View File

@@ -1,108 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_DETAIL_CHAR_RANGE_FUNCTIONS_HPP
#define BOOST_SPIRIT_X3_CHAR_DETAIL_CHAR_RANGE_FUNCTIONS_HPP
#include <boost/spirit/home/x3/char/detail/char_range.hpp>
#include <limits>
#include <concepts>
namespace boost::spirit::x3::detail
{
template <typename CharT>
[[nodiscard]] constexpr bool
is_valid(char_range<CharT> const& range) noexcept
{
// test for valid ranges
return range.first <= range.last;
}
template <typename CharT>
[[nodiscard]] constexpr bool
includes(char_range<CharT> const& range, char_range<CharT> const& other) noexcept
{
// see if two ranges intersect
return (range.first <= other.first) && (range.last >= other.last);
}
template <typename CharT>
[[nodiscard]] constexpr bool
includes(char_range<CharT> const& range, CharT val) noexcept
{
// see if val is in range
return (range.first <= val) && (range.last >= val);
}
template <typename CharT>
[[nodiscard]] constexpr bool
can_merge(char_range<CharT> const& range, char_range<CharT> const& other) noexcept
{
// see if a 'range' overlaps, or is adjacent to
// another range 'other', so we can merge them
using limits = std::numeric_limits<CharT>;
CharT const decr_first =
range.first == (limits::min)()
? range.first : range.first-1;
CharT const incr_last =
range.last == (limits::max)()
? range.last : range.last+1;
return (decr_first <= other.last) && (incr_last >= other.first);
}
template <typename CharT>
constexpr void
merge(char_range<CharT>& result, char_range<CharT> const& other) noexcept
{
// merge two ranges
if (result.first > other.first)
{
result.first = other.first;
}
if (result.last < other.last)
{
result.last = other.last;
}
}
struct char_range_compare
{
using is_transparent = int;
template <typename CharT>
[[nodiscard]] constexpr bool operator()(char_range<CharT> const& x, CharT const y) const noexcept
{
return x.first < y;
}
template <typename CharT>
[[nodiscard]] constexpr bool operator()(CharT const x, char_range<CharT> const& y) const noexcept
{
return x < y.first;
}
template <typename CharT>
[[nodiscard]] constexpr bool operator()(char_range<CharT> const& x, char_range<CharT> const& y) const noexcept
{
return x.first < y.first;
}
// This overload is required to satsify `std::indirect_strict_weak_order`
template <std::integral CharT> // hack: minimal constraint to avoid obvious mistakes
[[nodiscard]] constexpr bool operator()(CharT const x, CharT const y) const noexcept
{
return x == y;
}
};
} // boost::spirit::x3::detail
#endif

View File

@@ -1,193 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_DETAIL_CHAR_RANGE_RUN_HPP
#define BOOST_SPIRIT_X3_CHAR_DETAIL_CHAR_RANGE_RUN_HPP
#include <boost/spirit/home/x3/char/detail/char_range.hpp>
#include <boost/spirit/home/x3/char/detail/char_range_functions.hpp>
#include <boost/assert.hpp>
#include <algorithm>
#include <vector>
#include <iterator>
#include <ranges>
#include <utility>
namespace boost::spirit::x3::detail
{
// An implementation of a sparse bit (boolean) set. The set uses
// a sorted vector of disjoint ranges. This class implements the
// bare minimum essentials from which the full range of set
// operators can be implemented. The set is constructed from
// ranges. Internally, adjacent or overlapping ranges are
// coalesced.
//
// range_runs are very space-economical in situations where there
// are lots of ranges and a few individual disjoint values.
// Searching is O(log n) where n is the number of ranges.
template <typename CharT>
class char_range_run
{
public:
using range_type = char_range<CharT>;
using storage_type = std::vector<range_type>; // TODO: use default_init_allocator as soon as constexpr placement new is available
[[nodiscard]] static constexpr bool
try_merge(storage_type& run, typename storage_type::iterator iter, range_type const& range)
noexcept(std::is_nothrow_move_assignable_v<CharT>)
{
// *iter intersects with or is adjacent to 'range'?
if (!detail::can_merge(*iter, range)) return false;
// merge range and *iter
detail::merge(*iter, range);
// collapse all subsequent ranges that can merge with *iter:
auto it = std::next(iter);
// 1. skip subsequent ranges completely included in *iter
while (it != run.end() && it->last <= iter->last)
{
++it;
}
// 2. collapse next range if adjacent or overlapping with *iter
if (it != run.end() && it->first-1 <= iter->last)
{
iter->last = it->last;
++it;
}
// erase all ranges that were collapsed
run.erase(std::next(iter), it);
return true;
}
[[nodiscard]] constexpr bool test(CharT val) const noexcept
{
if (run_.empty()) return false;
// search the ranges for one that potentially includes val
auto const iter = std::ranges::upper_bound(
run_, val,
char_range_compare{}
);
// return true if *(iter-1) includes val
return iter != run_.begin() && detail::includes(*std::prev(iter), val);
}
constexpr void swap(char_range_run& other) noexcept
{
run_.swap(other.run_);
}
constexpr void set(range_type const& range)
{
BOOST_ASSERT(detail::is_valid(range));
if (run_.empty())
{
// the vector is empty, insert 'range'
run_.emplace_back(range);
return;
}
// search the ranges for one that potentially includes 'range'
auto iter = std::ranges::upper_bound(run_, range, char_range_compare{});
if (iter != run_.begin())
{
// if *(iter-1) includes 'range', return early
if (detail::includes(*std::prev(iter), range))
{
return;
}
// if *(iter-1) can merge with 'range', merge them and return
if (this->try_merge(run_, std::prev(iter), range))
{
return;
}
}
// if *iter can merge with with 'range', merge them
if (iter == run_.end() || !this->try_merge(run_, iter, range))
{
// no overlap, insert 'range'
run_.insert(iter, range);
}
}
constexpr void clear(range_type const& range)
{
BOOST_ASSERT(detail::is_valid(range));
if (run_.empty()) return;
// search the ranges for one that potentially includes 'range'
auto iter = std::ranges::upper_bound(run_, range, char_range_compare{});
// 'range' starts with or after another range:
if (iter != run_.begin())
{
auto const left_iter = std::prev(iter);
// 'range' starts after '*left_iter':
if (left_iter->first < range.first)
{
// if 'range' is completely included inside '*left_iter':
// need to break it apart into two ranges (punch a hole),
if (left_iter->last > range.last)
{
auto const last_save = left_iter->last;
left_iter->last = range.first-1;
run_.insert(iter, range_type(range.last+1, last_save));
return;
}
// if 'range' contains 'left_iter->last':
// truncate '*left_iter' (clip its right)
else if (left_iter->last >= range.first)
{
left_iter->last = range.first-1;
}
}
// 'range' has the same left bound as '*left_iter': it
// must be removed or truncated by the code below
else
{
iter = left_iter;
}
}
// remove or truncate subsequent ranges that overlap with 'range':
auto it = iter;
// 1. skip subsequent ranges completely included in 'range'
while (it != run_.end() && it->last <= range.last)
{
++it;
}
// 2. clip left of next range if overlapping with 'range'
if (it != run_.end() && it->first <= range.last)
{
it->first = range.last+1;
}
// erase all ranges that 'range' contained
run_.erase(iter, it);
}
constexpr void clear() noexcept
{
run_.clear();
}
private:
storage_type run_;
};
} // boost::spirit::x3::detail
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,33 +9,27 @@
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/support/utility/utf8.hpp>
#include <boost/type_traits/is_same.hpp>
#include <type_traits>
#include <concepts>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Encoding, typename Attribute = typename Encoding::char_type>
struct literal_char : char_parser<literal_char<Encoding, Attribute>>
{
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
template <typename Char>
requires std::convertible_to<Char, char_type>
constexpr literal_char(Char ch) noexcept
: ch(static_cast<char_type>(ch))
{
static_assert(std::same_as<char_type, Char>, "Mixing incompatible character types is not allowed");
}
constexpr literal_char(Char ch)
: ch(static_cast<char_type>(ch)) {}
template <typename Char, typename Context>
[[nodiscard]] constexpr bool test(Char ch_, Context const& context) const noexcept
bool test(Char ch_, Context const& context) const
{
static_assert(std::same_as<char_type, Char>, "Mixing incompatible character types is not allowed");
return x3::get_case_compare<encoding>(context)(ch, char_type(ch_)) == 0;
return get_case_compare<encoding>(context)(ch, char_type(ch_)) == 0;
}
char_type ch;
@@ -45,12 +38,12 @@ namespace boost::spirit::x3
template <typename Encoding, typename Attribute>
struct get_info<literal_char<Encoding, Attribute>>
{
using result_type = std::string;
[[nodiscard]] std::string operator()(literal_char<Encoding, Attribute> const& p) const
typedef std::string result_type;
std::string operator()(literal_char<Encoding, Attribute> const& p) const
{
return '\'' + x3::to_utf8(Encoding::toucs4(p.ch)) + '\'';
return '\'' + to_utf8(Encoding::toucs4(p.ch)) + '\'';
}
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,12 +8,15 @@
#define BOOST_SPIRIT_X3_UNICODE_JAN_20_2012_1218AM
#include <boost/spirit/home/x3/char/char_parser.hpp>
#include <boost/spirit/home/x3/char/char.hpp>
#include <boost/spirit/home/x3/char/detail/cast_char.hpp>
#include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#include <boost/spirit/home/support/char_encoding/unicode.hpp>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
struct char_tag;
struct alnum_tag;
struct alpha_tag;
@@ -29,7 +31,9 @@ namespace boost::spirit::x3
struct lower_tag;
struct upper_tag;
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
struct letter_tag {};
struct mark_tag {};
struct number_tag {};
@@ -38,7 +42,9 @@ namespace boost::spirit::x3
struct punctuation_tag {};
struct symbol_tag {};
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
struct uppercase_letter_tag {};
struct lowercase_letter_tag {};
struct titlecase_letter_tag {};
@@ -76,7 +82,9 @@ namespace boost::spirit::x3
struct modifier_symbol_tag {};
struct other_symbol_tag {};
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
struct alphabetic_tag {};
struct uppercase_tag {};
struct lowercase_tag {};
@@ -85,7 +93,9 @@ namespace boost::spirit::x3
struct noncharacter_code_point_tag {};
struct default_ignorable_code_point_tag {};
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
struct adlam_tag {};
struct caucasian_albanian_tag {};
struct ahom_tag {};
@@ -252,10 +262,11 @@ namespace boost::spirit::x3
struct common_tag {};
struct unknown_tag {};
///////////////////////////////////////////////////////////////////////////
struct unicode_char_class_base
{
using encoding = char_encoding::unicode;
using char_type = char_encoding::unicode::char_type;
typedef char_encoding::unicode encoding;
typedef char_encoding::unicode::char_type char_type;
#define BOOST_SPIRIT_X3_BASIC_CLASSIFY(name) \
template <typename Char> \
@@ -280,7 +291,9 @@ namespace boost::spirit::x3
/***/
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_BASIC_CLASSIFY(char)
BOOST_SPIRIT_X3_BASIC_CLASSIFY(alnum)
BOOST_SPIRIT_X3_BASIC_CLASSIFY(alpha)
@@ -295,7 +308,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_BASIC_CLASSIFY(blank)
BOOST_SPIRIT_X3_BASIC_CLASSIFY(upper)
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CLASSIFY(letter)
BOOST_SPIRIT_X3_CLASSIFY(mark)
BOOST_SPIRIT_X3_CLASSIFY(number)
@@ -304,7 +319,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CLASSIFY(punctuation)
BOOST_SPIRIT_X3_CLASSIFY(symbol)
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CLASSIFY(uppercase_letter)
BOOST_SPIRIT_X3_CLASSIFY(lowercase_letter)
BOOST_SPIRIT_X3_CLASSIFY(titlecase_letter)
@@ -342,7 +359,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CLASSIFY(modifier_symbol)
BOOST_SPIRIT_X3_CLASSIFY(other_symbol)
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CLASSIFY(alphabetic)
BOOST_SPIRIT_X3_CLASSIFY(uppercase)
BOOST_SPIRIT_X3_CLASSIFY(lowercase)
@@ -351,7 +370,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CLASSIFY(noncharacter_code_point)
BOOST_SPIRIT_X3_CLASSIFY(default_ignorable_code_point)
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CLASSIFY(adlam)
BOOST_SPIRIT_X3_CLASSIFY(caucasian_albanian)
BOOST_SPIRIT_X3_CLASSIFY(ahom)
@@ -524,28 +545,34 @@ namespace boost::spirit::x3
template <typename Tag>
struct unicode_char_class
: char_parser<unicode_char_class<Tag>>
: char_parser<unicode_char_class<Tag>>
{
using encoding = char_encoding::unicode;
using tag = Tag;
using char_type = typename encoding::char_type;
using attribute_type = char_type;
static constexpr bool has_attribute = true;
typedef char_encoding::unicode encoding;
typedef Tag tag;
typedef typename encoding::char_type char_type;
typedef char_type attribute_type;
static bool const has_attribute = true;
template <typename Char, typename Context>
[[nodiscard]] constexpr bool test(Char ch, Context const&) const noexcept
bool test(Char ch, Context const&) const
{
return encoding::ischar(ch) && unicode_char_class_base::is(tag{}, ch);
return encoding::ischar(ch) && unicode_char_class_base::is(tag(), ch);
}
};
#define BOOST_SPIRIT_X3_CHAR_CLASS(name) \
using name##_type = unicode_char_class<name##_tag>; \
inline constexpr name##_type name{};
typedef unicode_char_class<name##_tag> name##_type; \
constexpr name##_type name = name##_type(); \
/***/
namespace unicode
{
// Unicode Major Categories
typedef any_char<char_encoding::unicode> char_type;
constexpr auto char_ = char_type{};
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CHAR_CLASS(alnum)
BOOST_SPIRIT_X3_CHAR_CLASS(alpha)
BOOST_SPIRIT_X3_CHAR_CLASS(digit)
@@ -559,7 +586,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CHAR_CLASS(blank)
BOOST_SPIRIT_X3_CHAR_CLASS(upper)
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Major Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CHAR_CLASS(letter)
BOOST_SPIRIT_X3_CHAR_CLASS(mark)
BOOST_SPIRIT_X3_CHAR_CLASS(number)
@@ -568,7 +597,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CHAR_CLASS(punctuation)
BOOST_SPIRIT_X3_CHAR_CLASS(symbol)
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
// Unicode General Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CHAR_CLASS(uppercase_letter)
BOOST_SPIRIT_X3_CHAR_CLASS(lowercase_letter)
BOOST_SPIRIT_X3_CHAR_CLASS(titlecase_letter)
@@ -606,7 +637,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CHAR_CLASS(modifier_symbol)
BOOST_SPIRIT_X3_CHAR_CLASS(other_symbol)
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
// Unicode Derived Categories
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CHAR_CLASS(alphabetic)
BOOST_SPIRIT_X3_CHAR_CLASS(uppercase)
BOOST_SPIRIT_X3_CHAR_CLASS(lowercase)
@@ -615,7 +648,9 @@ namespace boost::spirit::x3
BOOST_SPIRIT_X3_CHAR_CLASS(noncharacter_code_point)
BOOST_SPIRIT_X3_CHAR_CLASS(default_ignorable_code_point)
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
// Unicode Scripts
///////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_X3_CHAR_CLASS(adlam)
BOOST_SPIRIT_X3_CHAR_CLASS(caucasian_albanian)
BOOST_SPIRIT_X3_CHAR_CLASS(ahom)
@@ -785,6 +820,6 @@ namespace boost::spirit::x3
#undef BOOST_SPIRIT_X3_CHAR_CLASS
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,342 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_ENCODING_ASCII_HPP
#define BOOST_SPIRIT_X3_CHAR_ENCODING_ASCII_HPP
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/assert.hpp>
#include <climits>
#include <cstdint>
// constants used to classify the single characters
#define BOOST_SPIRIT_X3_CC_DIGIT 0x0001
#define BOOST_SPIRIT_X3_CC_XDIGIT 0x0002
#define BOOST_SPIRIT_X3_CC_ALPHA 0x0004
#define BOOST_SPIRIT_X3_CC_CTRL 0x0008
#define BOOST_SPIRIT_X3_CC_LOWER 0x0010
#define BOOST_SPIRIT_X3_CC_UPPER 0x0020
#define BOOST_SPIRIT_X3_CC_SPACE 0x0040
#define BOOST_SPIRIT_X3_CC_PUNCT 0x0080
namespace boost::spirit::x3::char_encoding
{
// The detection of isgraph(), isprint() and isblank() is done programmatically
// to keep the character type table small. Additionally, these functions are
// rather seldom used and the programmatic detection is very simple.
// Test characters for specified conditions (using ASCII)
struct ascii
{
using char_type = char;
using classify_type = unsigned char;
// ASCII character classification table
inline static constexpr unsigned char ascii_char_types[] =
{
/* NUL 0 0 */ BOOST_SPIRIT_X3_CC_CTRL,
/* SOH 1 1 */ BOOST_SPIRIT_X3_CC_CTRL,
/* STX 2 2 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ETX 3 3 */ BOOST_SPIRIT_X3_CC_CTRL,
/* EOT 4 4 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ENQ 5 5 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ACK 6 6 */ BOOST_SPIRIT_X3_CC_CTRL,
/* BEL 7 7 */ BOOST_SPIRIT_X3_CC_CTRL,
/* BS 8 8 */ BOOST_SPIRIT_X3_CC_CTRL,
/* HT 9 9 */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* NL 10 a */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* VT 11 b */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* NP 12 c */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* CR 13 d */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* SO 14 e */ BOOST_SPIRIT_X3_CC_CTRL,
/* SI 15 f */ BOOST_SPIRIT_X3_CC_CTRL,
/* DLE 16 10 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC1 17 11 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC2 18 12 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC3 19 13 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC4 20 14 */ BOOST_SPIRIT_X3_CC_CTRL,
/* NAK 21 15 */ BOOST_SPIRIT_X3_CC_CTRL,
/* SYN 22 16 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ETB 23 17 */ BOOST_SPIRIT_X3_CC_CTRL,
/* CAN 24 18 */ BOOST_SPIRIT_X3_CC_CTRL,
/* EM 25 19 */ BOOST_SPIRIT_X3_CC_CTRL,
/* SUB 26 1a */ BOOST_SPIRIT_X3_CC_CTRL,
/* ESC 27 1b */ BOOST_SPIRIT_X3_CC_CTRL,
/* FS 28 1c */ BOOST_SPIRIT_X3_CC_CTRL,
/* GS 29 1d */ BOOST_SPIRIT_X3_CC_CTRL,
/* RS 30 1e */ BOOST_SPIRIT_X3_CC_CTRL,
/* US 31 1f */ BOOST_SPIRIT_X3_CC_CTRL,
/* SP 32 20 */ BOOST_SPIRIT_X3_CC_SPACE,
/* ! 33 21 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* " 34 22 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* # 35 23 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* $ 36 24 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* % 37 25 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* & 38 26 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ' 39 27 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ( 40 28 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ) 41 29 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* * 42 2a */ BOOST_SPIRIT_X3_CC_PUNCT,
/* + 43 2b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* , 44 2c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* - 45 2d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* . 46 2e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* / 47 2f */ BOOST_SPIRIT_X3_CC_PUNCT,
/* 0 48 30 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 1 49 31 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 2 50 32 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 3 51 33 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 4 52 34 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 5 53 35 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 6 54 36 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 7 55 37 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 8 56 38 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 9 57 39 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* : 58 3a */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ; 59 3b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* < 60 3c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* = 61 3d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* > 62 3e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ? 63 3f */ BOOST_SPIRIT_X3_CC_PUNCT,
/* @ 64 40 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* A 65 41 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* B 66 42 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* C 67 43 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* D 68 44 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* E 69 45 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* F 70 46 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* G 71 47 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* H 72 48 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* I 73 49 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* J 74 4a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* K 75 4b */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* L 76 4c */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* M 77 4d */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* N 78 4e */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* O 79 4f */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* P 80 50 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* Q 81 51 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* R 82 52 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* S 83 53 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* T 84 54 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* U 85 55 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* V 86 56 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* W 87 57 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* X 88 58 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* Y 89 59 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* Z 90 5a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* [ 91 5b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* \ 92 5c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ] 93 5d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ^ 94 5e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* _ 95 5f */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ` 96 60 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* a 97 61 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* b 98 62 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* c 99 63 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* d 100 64 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* e 101 65 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* f 102 66 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* g 103 67 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* h 104 68 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* i 105 69 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* j 106 6a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* k 107 6b */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* l 108 6c */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* m 109 6d */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* n 110 6e */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* o 111 6f */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* p 112 70 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* q 113 71 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* r 114 72 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* s 115 73 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* t 116 74 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* u 117 75 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* v 118 76 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* w 119 77 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* x 120 78 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* y 121 79 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* z 122 7a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* { 123 7b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* | 124 7c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* } 125 7d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ~ 126 7e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* DEL 127 7f */ BOOST_SPIRIT_X3_CC_CTRL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static bool
isascii_(int ch)
{
return 0 == (ch & ~0x7f);
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
ischar(int ch)
{
return isascii_(ch);
}
// *** Note on assertions: The precondition is that the calls to
// these functions do not violate the required range of ch (type int)
// which is that strict_ischar(ch) should be true. It is the
// responsibility of the caller to make sure this precondition is not
// violated.
static bool
strict_ischar(int ch)
{
return ch >= 0 && ch <= 127;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isalnum(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_ALPHA)
|| (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_DIGIT);
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isalpha(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_ALPHA) ? true : false;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isdigit(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_DIGIT) ? true : false;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isxdigit(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_XDIGIT) ? true : false;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
iscntrl(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_CTRL) ? true : false;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isgraph(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return ('\x21' <= ch && ch <= '\x7e');
}
static bool
islower(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_LOWER) ? true : false;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isprint(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return ('\x20' <= ch && ch <= '\x7e');
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
ispunct(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_PUNCT) ? true : false;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isspace(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_SPACE) ? true : false;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
(isblank)(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return ('\x09' == ch || '\x20' == ch);
}
static bool
isupper(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return (ascii_char_types[ch] & BOOST_SPIRIT_X3_CC_UPPER) ? true : false;
}
// Simple character conversions
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static int
tolower(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return isupper(ch) ? (ch - 'A' + 'a') : ch;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static int
toupper(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return islower(ch) ? (ch - 'a' + 'A') : ch;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static std::uint32_t
toucs4(int ch)
{
BOOST_ASSERT(strict_ischar(ch));
return ch;
}
};
} // boost::spirit::x3::char_encoding
// undefine macros
#undef BOOST_SPIRIT_X3_CC_DIGIT
#undef BOOST_SPIRIT_X3_CC_XDIGIT
#undef BOOST_SPIRIT_X3_CC_ALPHA
#undef BOOST_SPIRIT_X3_CC_CTRL
#undef BOOST_SPIRIT_X3_CC_LOWER
#undef BOOST_SPIRIT_X3_CC_UPPER
#undef BOOST_SPIRIT_X3_CC_PUNCT
#undef BOOST_SPIRIT_X3_CC_SPACE
#endif

View File

@@ -1,21 +0,0 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_ENCODING_DETAIL_ENCODING_WARNING_HPP
#define BOOST_SPIRIT_X3_CHAR_ENCODING_DETAIL_ENCODING_WARNING_HPP
#define BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING \
"Hard-coding ASCII or Latin-1 assumptions is almost always wrong " \
"in modern applications and can introduce security vulnerabilities. " \
"Unless the input is provably ASCII-only (e.g., fixed-format data from " \
"the 1980s), the only correct interpretation uses the data's *original* " \
"encoding. Prefer transcoding to Unicode or to the implementation-defined " \
"execution character set before passing text to general-purpose parsers. " \
"For more information, refer to authoritative sources on C++ character " \
"encodings and Unicode fundamentals."
#endif

View File

@@ -1,734 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_ENCODING_ISO8859_1_HPP
#define BOOST_SPIRIT_X3_CHAR_ENCODING_ISO8859_1_HPP
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/assert.hpp>
#include <climits>
#include <cstdint>
// constants used to classify the single characters
#define BOOST_SPIRIT_X3_CC_DIGIT 0x0001
#define BOOST_SPIRIT_X3_CC_XDIGIT 0x0002
#define BOOST_SPIRIT_X3_CC_ALPHA 0x0004
#define BOOST_SPIRIT_X3_CC_CTRL 0x0008
#define BOOST_SPIRIT_X3_CC_LOWER 0x0010
#define BOOST_SPIRIT_X3_CC_UPPER 0x0020
#define BOOST_SPIRIT_X3_CC_SPACE 0x0040
#define BOOST_SPIRIT_X3_CC_PUNCT 0x0080
namespace boost::spirit::x3::char_encoding
{
// Test characters for specified conditions (using iso8859-1)
struct iso8859_1
{
using char_type = char;
using classify_type = char;
private:
// The detection of isgraph(), isprint() and isblank() is done programmatically
// to keep the character type table small. Additionally, these functions are
// rather seldom used and the programmatic detection is very simple.
// ISO 8859-1 character classification table
//
// the comments intentionally contain non-ascii characters
// boostinspect:noascii
inline static constexpr unsigned char iso8859_1_char_types[] =
{
/* NUL 0 0 */ BOOST_SPIRIT_X3_CC_CTRL,
/* SOH 1 1 */ BOOST_SPIRIT_X3_CC_CTRL,
/* STX 2 2 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ETX 3 3 */ BOOST_SPIRIT_X3_CC_CTRL,
/* EOT 4 4 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ENQ 5 5 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ACK 6 6 */ BOOST_SPIRIT_X3_CC_CTRL,
/* BEL 7 7 */ BOOST_SPIRIT_X3_CC_CTRL,
/* BS 8 8 */ BOOST_SPIRIT_X3_CC_CTRL,
/* HT 9 9 */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* NL 10 a */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* VT 11 b */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* NP 12 c */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* CR 13 d */ BOOST_SPIRIT_X3_CC_CTRL|BOOST_SPIRIT_X3_CC_SPACE,
/* SO 14 e */ BOOST_SPIRIT_X3_CC_CTRL,
/* SI 15 f */ BOOST_SPIRIT_X3_CC_CTRL,
/* DLE 16 10 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC1 17 11 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC2 18 12 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC3 19 13 */ BOOST_SPIRIT_X3_CC_CTRL,
/* DC4 20 14 */ BOOST_SPIRIT_X3_CC_CTRL,
/* NAK 21 15 */ BOOST_SPIRIT_X3_CC_CTRL,
/* SYN 22 16 */ BOOST_SPIRIT_X3_CC_CTRL,
/* ETB 23 17 */ BOOST_SPIRIT_X3_CC_CTRL,
/* CAN 24 18 */ BOOST_SPIRIT_X3_CC_CTRL,
/* EM 25 19 */ BOOST_SPIRIT_X3_CC_CTRL,
/* SUB 26 1a */ BOOST_SPIRIT_X3_CC_CTRL,
/* ESC 27 1b */ BOOST_SPIRIT_X3_CC_CTRL,
/* FS 28 1c */ BOOST_SPIRIT_X3_CC_CTRL,
/* GS 29 1d */ BOOST_SPIRIT_X3_CC_CTRL,
/* RS 30 1e */ BOOST_SPIRIT_X3_CC_CTRL,
/* US 31 1f */ BOOST_SPIRIT_X3_CC_CTRL,
/* SP 32 20 */ BOOST_SPIRIT_X3_CC_SPACE,
/* ! 33 21 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* " 34 22 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* # 35 23 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* $ 36 24 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* % 37 25 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* & 38 26 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ' 39 27 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ( 40 28 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ) 41 29 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* * 42 2a */ BOOST_SPIRIT_X3_CC_PUNCT,
/* + 43 2b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* , 44 2c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* - 45 2d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* . 46 2e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* / 47 2f */ BOOST_SPIRIT_X3_CC_PUNCT,
/* 0 48 30 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 1 49 31 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 2 50 32 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 3 51 33 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 4 52 34 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 5 53 35 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 6 54 36 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 7 55 37 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 8 56 38 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* 9 57 39 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_XDIGIT,
/* : 58 3a */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ; 59 3b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* < 60 3c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* = 61 3d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* > 62 3e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ? 63 3f */ BOOST_SPIRIT_X3_CC_PUNCT,
/* @ 64 40 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* A 65 41 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* B 66 42 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* C 67 43 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* D 68 44 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* E 69 45 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* F 70 46 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_UPPER,
/* G 71 47 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* H 72 48 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* I 73 49 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* J 74 4a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* K 75 4b */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* L 76 4c */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* M 77 4d */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* N 78 4e */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* O 79 4f */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* P 80 50 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* Q 81 51 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* R 82 52 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* S 83 53 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* T 84 54 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* U 85 55 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* V 86 56 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* W 87 57 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* X 88 58 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* Y 89 59 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* Z 90 5a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* [ 91 5b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* \ 92 5c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ] 93 5d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ^ 94 5e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* _ 95 5f */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ` 96 60 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* a 97 61 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* b 98 62 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* c 99 63 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* d 100 64 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* e 101 65 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* f 102 66 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_XDIGIT|BOOST_SPIRIT_X3_CC_LOWER,
/* g 103 67 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* h 104 68 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* i 105 69 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* j 106 6a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* k 107 6b */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* l 108 6c */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* m 109 6d */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* n 110 6e */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* o 111 6f */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* p 112 70 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* q 113 71 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* r 114 72 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* s 115 73 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* t 116 74 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* u 117 75 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* v 118 76 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* w 119 77 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* x 120 78 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* y 121 79 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* z 122 7a */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* { 123 7b */ BOOST_SPIRIT_X3_CC_PUNCT,
/* | 124 7c */ BOOST_SPIRIT_X3_CC_PUNCT,
/* } 125 7d */ BOOST_SPIRIT_X3_CC_PUNCT,
/* ~ 126 7e */ BOOST_SPIRIT_X3_CC_PUNCT,
/* DEL 127 7f */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 128 80 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 129 81 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 130 82 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 131 83 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 132 84 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 133 85 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 134 86 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 135 87 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 136 88 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 137 89 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 138 8a */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 139 8b */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 140 8c */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 141 8d */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 142 8e */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 143 8f */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 144 90 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 145 91 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 146 92 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 147 93 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 148 94 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 149 95 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 150 96 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 151 97 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 152 98 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 153 99 */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 154 9a */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 155 9b */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 156 9c */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 157 9d */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 158 9e */ BOOST_SPIRIT_X3_CC_CTRL,
/* -- 159 9f */ BOOST_SPIRIT_X3_CC_CTRL,
/* 160 a0 */ BOOST_SPIRIT_X3_CC_SPACE,
/* <20> 161 a1 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 162 a2 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 163 a3 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 164 a4 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 165 a5 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 166 a6 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 167 a7 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 168 a8 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 169 a9 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 170 aa */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 171 ab */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 172 ac */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 173 ad */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 174 ae */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 175 af */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 176 b0 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 177 b1 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 178 b2 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 179 b3 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 180 b4 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 181 b5 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 182 b6 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 183 b7 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 184 b8 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 185 b9 */ BOOST_SPIRIT_X3_CC_DIGIT|BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 186 ba */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 187 bb */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 188 bc */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 189 bd */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 190 be */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 191 bf */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 192 c0 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 193 c1 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 194 c2 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 195 c3 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 196 c4 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 197 c5 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 198 c6 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 199 c7 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 200 c8 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 201 c9 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 202 ca */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 203 cb */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 204 cc */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 205 cd */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 206 ce */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 207 cf */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 208 d0 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 209 d1 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 210 d2 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 211 d3 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 212 d4 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 213 d5 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 214 d6 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 215 d7 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 216 d8 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 217 d9 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 218 da */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 219 db */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 220 dc */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 221 dd */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 222 de */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_UPPER,
/* <20> 223 df */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 224 e0 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 225 e1 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 226 e2 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 227 e3 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 228 e4 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 229 e5 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 230 e6 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 231 e7 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 232 e8 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 233 e9 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 234 ea */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 235 eb */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 236 ec */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 237 ed */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 238 ee */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 239 ef */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 240 f0 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 241 f1 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 242 f2 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 243 f3 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 244 f4 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 245 f5 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 246 f6 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 247 f7 */ BOOST_SPIRIT_X3_CC_PUNCT,
/* <20> 248 f8 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 249 f9 */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 250 fa */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 251 fb */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 252 fc */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 253 fd */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 254 fe */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
/* <20> 255 ff */ BOOST_SPIRIT_X3_CC_ALPHA|BOOST_SPIRIT_X3_CC_LOWER,
};
// ISO 8859-1 character conversion table
inline static constexpr unsigned char iso8859_1_char_conversion[] =
{
/* NUL 0 0 */ '\0',
/* SOH 1 1 */ '\0',
/* STX 2 2 */ '\0',
/* ETX 3 3 */ '\0',
/* EOT 4 4 */ '\0',
/* ENQ 5 5 */ '\0',
/* ACK 6 6 */ '\0',
/* BEL 7 7 */ '\0',
/* BS 8 8 */ '\0',
/* HT 9 9 */ '\0',
/* NL 10 a */ '\0',
/* VT 11 b */ '\0',
/* NP 12 c */ '\0',
/* CR 13 d */ '\0',
/* SO 14 e */ '\0',
/* SI 15 f */ '\0',
/* DLE 16 10 */ '\0',
/* DC1 17 11 */ '\0',
/* DC2 18 12 */ '\0',
/* DC3 19 13 */ '\0',
/* DC4 20 14 */ '\0',
/* NAK 21 15 */ '\0',
/* SYN 22 16 */ '\0',
/* ETB 23 17 */ '\0',
/* CAN 24 18 */ '\0',
/* EM 25 19 */ '\0',
/* SUB 26 1a */ '\0',
/* ESC 27 1b */ '\0',
/* FS 28 1c */ '\0',
/* GS 29 1d */ '\0',
/* RS 30 1e */ '\0',
/* US 31 1f */ '\0',
/* SP 32 20 */ '\0',
/* ! 33 21 */ '\0',
/* " 34 22 */ '\0',
/* # 35 23 */ '\0',
/* $ 36 24 */ '\0',
/* % 37 25 */ '\0',
/* & 38 26 */ '\0',
/* ' 39 27 */ '\0',
/* ( 40 28 */ '\0',
/* ) 41 29 */ '\0',
/* * 42 2a */ '\0',
/* + 43 2b */ '\0',
/* , 44 2c */ '\0',
/* - 45 2d */ '\0',
/* . 46 2e */ '\0',
/* / 47 2f */ '\0',
/* 0 48 30 */ '\0',
/* 1 49 31 */ '\0',
/* 2 50 32 */ '\0',
/* 3 51 33 */ '\0',
/* 4 52 34 */ '\0',
/* 5 53 35 */ '\0',
/* 6 54 36 */ '\0',
/* 7 55 37 */ '\0',
/* 8 56 38 */ '\0',
/* 9 57 39 */ '\0',
/* : 58 3a */ '\0',
/* ; 59 3b */ '\0',
/* < 60 3c */ '\0',
/* = 61 3d */ '\0',
/* > 62 3e */ '\0',
/* ? 63 3f */ '\0',
/* @ 64 40 */ '\0',
/* A 65 41 */ 'a',
/* B 66 42 */ 'b',
/* C 67 43 */ 'c',
/* D 68 44 */ 'd',
/* E 69 45 */ 'e',
/* F 70 46 */ 'f',
/* G 71 47 */ 'g',
/* H 72 48 */ 'h',
/* I 73 49 */ 'i',
/* J 74 4a */ 'j',
/* K 75 4b */ 'k',
/* L 76 4c */ 'l',
/* M 77 4d */ 'm',
/* N 78 4e */ 'n',
/* O 79 4f */ 'o',
/* P 80 50 */ 'p',
/* Q 81 51 */ 'q',
/* R 82 52 */ 'r',
/* S 83 53 */ 's',
/* T 84 54 */ 't',
/* U 85 55 */ 'u',
/* V 86 56 */ 'v',
/* W 87 57 */ 'w',
/* X 88 58 */ 'x',
/* Y 89 59 */ 'y',
/* Z 90 5a */ 'z',
/* [ 91 5b */ '\0',
/* \ 92 5c */ '\0',
/* ] 93 5d */ '\0',
/* ^ 94 5e */ '\0',
/* _ 95 5f */ '\0',
/* ` 96 60 */ '\0',
/* a 97 61 */ 'A',
/* b 98 62 */ 'B',
/* c 99 63 */ 'C',
/* d 100 64 */ 'D',
/* e 101 65 */ 'E',
/* f 102 66 */ 'F',
/* g 103 67 */ 'G',
/* h 104 68 */ 'H',
/* i 105 69 */ 'I',
/* j 106 6a */ 'J',
/* k 107 6b */ 'K',
/* l 108 6c */ 'L',
/* m 109 6d */ 'M',
/* n 110 6e */ 'N',
/* o 111 6f */ 'O',
/* p 112 70 */ 'P',
/* q 113 71 */ 'Q',
/* r 114 72 */ 'R',
/* s 115 73 */ 'S',
/* t 116 74 */ 'T',
/* u 117 75 */ 'U',
/* v 118 76 */ 'V',
/* w 119 77 */ 'W',
/* x 120 78 */ 'X',
/* y 121 79 */ 'Y',
/* z 122 7a */ 'Z',
/* { 123 7b */ '\0',
/* | 124 7c */ '\0',
/* } 125 7d */ '\0',
/* ~ 126 7e */ '\0',
/* DEL 127 7f */ '\0',
/* -- 128 80 */ '\0',
/* -- 129 81 */ '\0',
/* -- 130 82 */ '\0',
/* -- 131 83 */ '\0',
/* -- 132 84 */ '\0',
/* -- 133 85 */ '\0',
/* -- 134 86 */ '\0',
/* -- 135 87 */ '\0',
/* -- 136 88 */ '\0',
/* -- 137 89 */ '\0',
/* -- 138 8a */ '\0',
/* -- 139 8b */ '\0',
/* -- 140 8c */ '\0',
/* -- 141 8d */ '\0',
/* -- 142 8e */ '\0',
/* -- 143 8f */ '\0',
/* -- 144 90 */ '\0',
/* -- 145 91 */ '\0',
/* -- 146 92 */ '\0',
/* -- 147 93 */ '\0',
/* -- 148 94 */ '\0',
/* -- 149 95 */ '\0',
/* -- 150 96 */ '\0',
/* -- 151 97 */ '\0',
/* -- 152 98 */ '\0',
/* -- 153 99 */ '\0',
/* -- 154 9a */ '\0',
/* -- 155 9b */ '\0',
/* -- 156 9c */ '\0',
/* -- 157 9d */ '\0',
/* -- 158 9e */ '\0',
/* -- 159 9f */ '\0',
/* 160 a0 */ '\0',
/* <20> 161 a1 */ '\0',
/* <20> 162 a2 */ '\0',
/* <20> 163 a3 */ '\0',
/* <20> 164 a4 */ '\0',
/* <20> 165 a5 */ '\0',
/* <20> 166 a6 */ '\0',
/* <20> 167 a7 */ '\0',
/* <20> 168 a8 */ '\0',
/* <20> 169 a9 */ '\0',
/* <20> 170 aa */ '\0',
/* <20> 171 ab */ '\0',
/* <20> 172 ac */ '\0',
/* <20> 173 ad */ '\0',
/* <20> 174 ae */ '\0',
/* <20> 175 af */ '\0',
/* <20> 176 b0 */ '\0',
/* <20> 177 b1 */ '\0',
/* <20> 178 b2 */ '\0',
/* <20> 179 b3 */ '\0',
/* <20> 180 b4 */ '\0',
/* <20> 181 b5 */ '\0',
/* <20> 182 b6 */ '\0',
/* <20> 183 b7 */ '\0',
/* <20> 184 b8 */ '\0',
/* <20> 185 b9 */ '\0',
/* <20> 186 ba */ '\0',
/* <20> 187 bb */ '\0',
/* <20> 188 bc */ '\0',
/* <20> 189 bd */ '\0',
/* <20> 190 be */ '\0',
/* <20> 191 bf */ '\0',
/* <20> 192 c0 */ 0xe0,
/* <20> 193 c1 */ 0xe1,
/* <20> 194 c2 */ 0xe2,
/* <20> 195 c3 */ 0xe3,
/* <20> 196 c4 */ 0xe4,
/* <20> 197 c5 */ 0xe5,
/* <20> 198 c6 */ 0xe6,
/* <20> 199 c7 */ 0xe7,
/* <20> 200 c8 */ 0xe8,
/* <20> 201 c9 */ 0xe9,
/* <20> 202 ca */ 0xea,
/* <20> 203 cb */ 0xeb,
/* <20> 204 cc */ 0xec,
/* <20> 205 cd */ 0xed,
/* <20> 206 ce */ 0xee,
/* <20> 207 cf */ 0xef,
/* <20> 208 d0 */ 0xf0,
/* <20> 209 d1 */ 0xf1,
/* <20> 210 d2 */ 0xf2,
/* <20> 211 d3 */ 0xf3,
/* <20> 212 d4 */ 0xf4,
/* <20> 213 d5 */ 0xf5,
/* <20> 214 d6 */ 0xf6,
/* <20> 215 d7 */ '\0',
/* <20> 216 d8 */ 0xf8,
/* <20> 217 d9 */ 0xf9,
/* <20> 218 da */ 0xfa,
/* <20> 219 db */ 0xfb,
/* <20> 220 dc */ 0xfc,
/* <20> 221 dd */ 0xfd,
/* <20> 222 de */ 0xfe,
/* <20> 223 df */ '\0',
/* <20> 224 e0 */ 0xc0,
/* <20> 225 e1 */ 0xc1,
/* <20> 226 e2 */ 0xc2,
/* <20> 227 e3 */ 0xc3,
/* <20> 228 e4 */ 0xc4,
/* <20> 229 e5 */ 0xc5,
/* <20> 230 e6 */ 0xc6,
/* <20> 231 e7 */ 0xc7,
/* <20> 232 e8 */ 0xc8,
/* <20> 233 e9 */ 0xc9,
/* <20> 234 ea */ 0xca,
/* <20> 235 eb */ 0xcb,
/* <20> 236 ec */ 0xcc,
/* <20> 237 ed */ 0xcd,
/* <20> 238 ee */ 0xce,
/* <20> 239 ef */ 0xcf,
/* <20> 240 f0 */ 0xd0,
/* <20> 241 f1 */ 0xd1,
/* <20> 242 f2 */ 0xd2,
/* <20> 243 f3 */ 0xd3,
/* <20> 244 f4 */ 0xd4,
/* <20> 245 f5 */ 0xd5,
/* <20> 246 f6 */ 0xd6,
/* <20> 247 f7 */ '\0',
/* <20> 248 f8 */ 0xd8,
/* <20> 249 f9 */ 0xd9,
/* <20> 250 fa */ 0xda,
/* <20> 251 fb */ 0xdb,
/* <20> 252 fc */ 0xdc,
/* <20> 253 fd */ 0xdd,
/* <20> 254 fe */ 0xde,
/* <20> 255 ff */ '\0',
};
public:
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isascii_(int ch)
{
return 0 == (ch & ~0x7f);
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
ischar(int ch)
{
// iso8859.1 uses all 8 bits
// we have to watch out for sign extensions
return (0 == (ch & ~0xff) || ~0 == (ch | 0xff)) != 0;
}
// *** Note on assertions: The precondition is that the calls to
// these functions do not violate the required range of ch (type int)
// which is that strict_ischar(ch) should be true. It is the
// responsibility of the caller to make sure this precondition is not
// violated.
static bool
strict_ischar(int ch)
{
return ch >= 0 && ch <= 255;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isalnum(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_ALPHA)
|| (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_DIGIT);
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isalpha(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_ALPHA) != 0;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isdigit(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_DIGIT) != 0;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isxdigit(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_XDIGIT) != 0;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
iscntrl(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_CTRL) != 0;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isgraph(int ch)
{
return ('\x21' <= ch && ch <= '\x7e') || ('\xa1' <= ch && ch <= '\xff');
}
static bool
islower(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_LOWER) != 0;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isprint(int ch)
{
return ('\x20' <= ch && ch <= '\x7e') || ('\xa0' <= ch && ch <= '\xff');
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
ispunct(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_PUNCT) != 0;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
isspace(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_SPACE) != 0;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static bool
(isblank)(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return ('\x09' == ch || '\x20' == ch || '\xa0' == ch);
}
static bool
isupper(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return (iso8859_1_char_types[ch] & BOOST_SPIRIT_X3_CC_UPPER) != 0;
}
// Simple character conversions
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static int
tolower(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return iso8859_1::isupper(ch) && '\0' != iso8859_1_char_conversion[ch] ?
iso8859_1_char_conversion[ch] : ch;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static int
toupper(int ch)
{
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return iso8859_1::islower(ch) && '\0' != iso8859_1_char_conversion[ch] ?
iso8859_1_char_conversion[ch] : ch;
}
[[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]]
static std::uint32_t
toucs4(int ch)
{
// The first 256 characters in Unicode and the UCS are
// identical to those in ISO/IEC-8859-1.
BOOST_ASSERT(iso8859_1::strict_ischar(ch));
return ch;
}
};
} // boost::spirit::x3::char_encoding
// undefine macros
#undef BOOST_SPIRIT_X3_CC_DIGIT
#undef BOOST_SPIRIT_X3_CC_XDIGIT
#undef BOOST_SPIRIT_X3_CC_ALPHA
#undef BOOST_SPIRIT_X3_CC_CTRL
#undef BOOST_SPIRIT_X3_CC_LOWER
#undef BOOST_SPIRIT_X3_CC_UPPER
#undef BOOST_SPIRIT_X3_CC_PUNCT
#undef BOOST_SPIRIT_X3_CC_SPACE
#endif

View File

@@ -1,162 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_ENCODING_STANDARD_HPP
#define BOOST_SPIRIT_X3_CHAR_ENCODING_STANDARD_HPP
#include <boost/assert.hpp>
#include <cstdint>
#include <cctype>
#include <climits>
namespace boost::spirit::x3::char_encoding
{
// Test characters for specified conditions (using std functions)
struct standard
{
using char_type = char;
using classify_type = unsigned char;
[[nodiscard]] static constexpr bool
isascii_(int ch) noexcept
{
return 0 == (ch & ~0x7f);
}
[[nodiscard]] static constexpr bool
ischar(int ch) noexcept
{
// uses all 8 bits
// we have to watch out for sign extensions
return (0 == (ch & ~0xff) || ~0 == (ch | 0xff)) != 0;
}
// *** Note on assertions: The precondition is that the calls to
// these functions do not violate the required range of ch (int)
// which is that strict_ischar(ch) should be true. It is the
// responsibility of the caller to make sure this precondition is not
// violated.
[[nodiscard]] static constexpr bool
strict_ischar(int ch) noexcept
{
// ch should be representable as an unsigned char
return ch >= 0 && ch <= UCHAR_MAX;
}
[[nodiscard]] static bool // TODO: constexpr
isalnum(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isalnum(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isalpha(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isalpha(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isdigit(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isdigit(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isxdigit(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isxdigit(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
iscntrl(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::iscntrl(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isgraph(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isgraph(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
islower(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::islower(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isprint(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isprint(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
ispunct(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::ispunct(ch) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isspace(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isspace(ch) != 0;
}
[[nodiscard]] static constexpr bool
(isblank)(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return (ch == ' ' || ch == '\t');
}
[[nodiscard]] static bool // TODO: constexpr
isupper(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::isupper(ch) != 0;
}
// Simple character conversions
[[nodiscard]] static int // TODO: constexpr
tolower(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::tolower(ch);
}
[[nodiscard]] static int // TODO: constexpr
toupper(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return std::toupper(ch);
}
[[nodiscard]] static constexpr std::uint32_t
toucs4(int ch) noexcept
{
BOOST_ASSERT(standard::strict_ischar(ch));
return static_cast<std::uint32_t>(ch);
}
};
} // boost::spirit::x3::char_encoding
#endif

View File

@@ -1,162 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_ENCODING_STANDARD_WIDE_HPP
#define BOOST_SPIRIT_X3_CHAR_ENCODING_STANDARD_WIDE_HPP
#include <boost/assert.hpp>
#include <string>
#include <type_traits>
#include <cstdint>
#include <cwctype>
namespace boost::spirit::x3::char_encoding
{
// Test characters for specified conditions (using std wchar_t functions)
struct standard_wide
{
using char_type = wchar_t;
using classify_type = wchar_t;
template <typename Char>
[[nodiscard]] static constexpr typename std::char_traits<Char>::int_type
to_int_type(Char ch) noexcept
{
return std::char_traits<Char>::to_int_type(ch);
}
template <typename Char>
[[nodiscard]] static constexpr Char
to_char_type(typename std::char_traits<Char>::int_type ch) noexcept
{
return std::char_traits<Char>::to_char_type(ch);
}
[[nodiscard]] static constexpr bool
ischar(int ch) noexcept
{
static_assert(
sizeof(wchar_t) == 1 || sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4,
"Unsupported wchar_t size"
);
constexpr unsigned mask =
sizeof(wchar_t) == 4 ? 0xffffffffu :
sizeof(wchar_t) == 2 ? 0xffffu :
0xffu;
// we have to watch out for sign extensions (casting is there to
// silence certain compilers complaining about signed/unsigned
// mismatch)
return (
std::size_t(0) ==
std::size_t(ch & ~mask) ||
std::size_t(~0) ==
std::size_t(ch | mask)
) != 0; // any wchar_t, but no other bits set
}
[[nodiscard]] static bool // TODO: constexpr
isalnum(wchar_t ch) noexcept
{
return std::iswalnum(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isalpha(wchar_t ch) noexcept
{
return std::iswalpha(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
iscntrl(wchar_t ch) noexcept
{
return std::iswcntrl(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isdigit(wchar_t ch) noexcept
{
return std::iswdigit(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isgraph(wchar_t ch) noexcept
{
return std::iswgraph(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
islower(wchar_t ch) noexcept
{
return std::iswlower(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isprint(wchar_t ch) noexcept
{
return std::iswprint(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
ispunct(wchar_t ch) noexcept
{
return std::iswpunct(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isspace(wchar_t ch) noexcept
{
return std::iswspace(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isupper(wchar_t ch) noexcept
{
return std::iswupper(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static bool // TODO: constexpr
isxdigit(wchar_t ch) noexcept
{
return std::iswxdigit(standard_wide::to_int_type(ch)) != 0;
}
[[nodiscard]] static constexpr bool
(isblank)(wchar_t ch) noexcept
{
return (ch == L' ' || ch == L'\t');
}
// Simple character conversions
[[nodiscard]] static wchar_t // TODO: constexpr
tolower(wchar_t ch) noexcept
{
return standard_wide::isupper(ch) ?
standard_wide::to_char_type<wchar_t>(std::towlower(standard_wide::to_int_type(ch))) : ch;
}
[[nodiscard]] static wchar_t // TODO: constexpr
toupper(wchar_t ch) noexcept
{
return std::islower(ch) ?
standard_wide::to_char_type<wchar_t>(std::towupper(standard_wide::to_int_type(ch))) : ch;
}
[[nodiscard]] static constexpr std::uint32_t
toucs4(wchar_t ch) noexcept
{
return static_cast<std::make_unsigned_t<wchar_t>>(ch);
}
};
} // boost::spirit::x3::char_encoding
#endif

View File

@@ -1,435 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CHAR_ENCODING_UNICODE_HPP
#define BOOST_SPIRIT_X3_CHAR_ENCODING_UNICODE_HPP
#include <boost/spirit/home/x3/char_encoding/unicode/classification.hpp>
#include <cstdint>
namespace boost::spirit::x3::char_encoding
{
struct unicode
{
using char_type = char32_t;
using classify_type = std::uint32_t;
[[nodiscard]] static constexpr bool
isascii_(char_type ch) noexcept
{
return 0 == (ch & ~0x7f);
}
[[nodiscard]] static constexpr bool
ischar(char_type ch) noexcept
{
// unicode code points in the range 0x00 to 0x10FFFF
return ch <= 0x10FFFF;
}
[[nodiscard]] static constexpr bool
isalnum(char_type ch) noexcept
{
return x3::unicode::is_alphanumeric(ch);
}
[[nodiscard]] static constexpr bool
isalpha(char_type ch) noexcept
{
return x3::unicode::is_alphabetic(ch);
}
[[nodiscard]] static constexpr bool
isdigit(char_type ch) noexcept
{
return x3::unicode::is_decimal_number(ch);
}
[[nodiscard]] static constexpr bool
isxdigit(char_type ch) noexcept
{
return x3::unicode::is_hex_digit(ch);
}
[[nodiscard]] static constexpr bool
iscntrl(char_type ch) noexcept
{
return x3::unicode::is_control(ch);
}
[[nodiscard]] static constexpr bool
isgraph(char_type ch) noexcept
{
return x3::unicode::is_graph(ch);
}
[[nodiscard]] static constexpr bool
islower(char_type ch) noexcept
{
return x3::unicode::is_lowercase(ch);
}
[[nodiscard]] static constexpr bool
isprint(char_type ch) noexcept
{
return x3::unicode::is_print(ch);
}
[[nodiscard]] static constexpr bool
ispunct(char_type ch) noexcept
{
return x3::unicode::is_punctuation(ch);
}
[[nodiscard]] static constexpr bool
isspace(char_type ch) noexcept
{
return x3::unicode::is_white_space(ch);
}
[[nodiscard]] static constexpr bool
(isblank)(char_type ch) noexcept
{
return x3::unicode::is_blank(ch);
}
[[nodiscard]] static constexpr bool
isupper(char_type ch) noexcept
{
return x3::unicode::is_uppercase(ch);
}
// Mixing character encodings is semantically wrong
static constexpr void isascii_(char) = delete;
static constexpr void isascii_(wchar_t) = delete;
static constexpr void ischar(char) = delete;
static constexpr void ischar(wchar_t) = delete;
static constexpr void isalnum(char) = delete;
static constexpr void isalnum(wchar_t) = delete;
static constexpr void isalpha(char) = delete;
static constexpr void isalpha(wchar_t) = delete;
static constexpr void isdigit(char) = delete;
static constexpr void isdigit(wchar_t) = delete;
static constexpr void isxdigit(char) = delete;
static constexpr void isxdigit(wchar_t) = delete;
static constexpr void iscntrl(char) = delete;
static constexpr void iscntrl(wchar_t) = delete;
static constexpr void isgraph(char) = delete;
static constexpr void isgraph(wchar_t) = delete;
static constexpr void islower(char) = delete;
static constexpr void islower(wchar_t) = delete;
static constexpr void isprint(char) = delete;
static constexpr void isprint(wchar_t) = delete;
static constexpr void ispunct(char) = delete;
static constexpr void ispunct(wchar_t) = delete;
static constexpr void isspace(char) = delete;
static constexpr void isspace(wchar_t) = delete;
static constexpr void isblank(char) = delete;
static constexpr void isblank(wchar_t) = delete;
static constexpr void isupper(char) = delete;
static constexpr void isupper(wchar_t) = delete;
// Simple character conversions
[[nodiscard]] static constexpr char_type
tolower(char_type ch) noexcept
{
return x3::unicode::to_lowercase(ch);
}
[[nodiscard]] static constexpr char_type
toupper(char_type ch) noexcept
{
return x3::unicode::to_uppercase(ch);
}
[[nodiscard]] static constexpr std::uint32_t
toucs4(char_type ch) noexcept
{
return ch;
}
static constexpr void tolower(char) = delete;
static constexpr void tolower(wchar_t) = delete;
static constexpr void toupper(char) = delete;
static constexpr void toupper(wchar_t) = delete;
static constexpr void toucs4(char) = delete;
static constexpr void toucs4(wchar_t) = delete;
// Major Categories
#define BOOST_SPIRIT_X3_MAJOR_CATEGORY(name) \
[[nodiscard]] static constexpr bool \
is_##name(char_type ch) noexcept \
{ \
return x3::unicode::get_major_category(ch) == x3::unicode::properties::name; \
} \
static constexpr void is_##name(char) = delete; \
static constexpr void is_##name(wchar_t) = delete;
BOOST_SPIRIT_X3_MAJOR_CATEGORY(letter)
BOOST_SPIRIT_X3_MAJOR_CATEGORY(mark)
BOOST_SPIRIT_X3_MAJOR_CATEGORY(number)
BOOST_SPIRIT_X3_MAJOR_CATEGORY(separator)
BOOST_SPIRIT_X3_MAJOR_CATEGORY(other)
BOOST_SPIRIT_X3_MAJOR_CATEGORY(punctuation)
BOOST_SPIRIT_X3_MAJOR_CATEGORY(symbol)
#undef BOOST_SPIRIT_X3_MAJOR_CATEGORY
// General Categories
#define BOOST_SPIRIT_X3_CATEGORY(name) \
[[nodiscard]] static constexpr bool \
is_##name(char_type ch) noexcept \
{ \
return x3::unicode::get_category(ch) == x3::unicode::properties::name; \
} \
static constexpr void is_##name(char) = delete; \
static constexpr void is_##name(wchar_t) = delete;
BOOST_SPIRIT_X3_CATEGORY(uppercase_letter)
BOOST_SPIRIT_X3_CATEGORY(lowercase_letter)
BOOST_SPIRIT_X3_CATEGORY(titlecase_letter)
BOOST_SPIRIT_X3_CATEGORY(modifier_letter)
BOOST_SPIRIT_X3_CATEGORY(other_letter)
BOOST_SPIRIT_X3_CATEGORY(nonspacing_mark)
BOOST_SPIRIT_X3_CATEGORY(enclosing_mark)
BOOST_SPIRIT_X3_CATEGORY(spacing_mark)
BOOST_SPIRIT_X3_CATEGORY(decimal_number)
BOOST_SPIRIT_X3_CATEGORY(letter_number)
BOOST_SPIRIT_X3_CATEGORY(other_number)
BOOST_SPIRIT_X3_CATEGORY(space_separator)
BOOST_SPIRIT_X3_CATEGORY(line_separator)
BOOST_SPIRIT_X3_CATEGORY(paragraph_separator)
BOOST_SPIRIT_X3_CATEGORY(control)
BOOST_SPIRIT_X3_CATEGORY(format)
BOOST_SPIRIT_X3_CATEGORY(private_use)
BOOST_SPIRIT_X3_CATEGORY(surrogate)
BOOST_SPIRIT_X3_CATEGORY(unassigned)
BOOST_SPIRIT_X3_CATEGORY(dash_punctuation)
BOOST_SPIRIT_X3_CATEGORY(open_punctuation)
BOOST_SPIRIT_X3_CATEGORY(close_punctuation)
BOOST_SPIRIT_X3_CATEGORY(connector_punctuation)
BOOST_SPIRIT_X3_CATEGORY(other_punctuation)
BOOST_SPIRIT_X3_CATEGORY(initial_punctuation)
BOOST_SPIRIT_X3_CATEGORY(final_punctuation)
BOOST_SPIRIT_X3_CATEGORY(math_symbol)
BOOST_SPIRIT_X3_CATEGORY(currency_symbol)
BOOST_SPIRIT_X3_CATEGORY(modifier_symbol)
BOOST_SPIRIT_X3_CATEGORY(other_symbol)
#undef BOOST_SPIRIT_X3_CATEGORY
// Derived Categories
#define BOOST_SPIRIT_X3_DERIVED_CATEGORY(name) \
[[nodiscard]] static constexpr bool \
is_##name(char_type ch) noexcept \
{ \
return x3::unicode::is_##name(ch); \
} \
static constexpr void is_##name(char) = delete; \
static constexpr void is_##name(wchar_t) = delete;
BOOST_SPIRIT_X3_DERIVED_CATEGORY(alphabetic)
BOOST_SPIRIT_X3_DERIVED_CATEGORY(uppercase)
BOOST_SPIRIT_X3_DERIVED_CATEGORY(lowercase)
BOOST_SPIRIT_X3_DERIVED_CATEGORY(white_space)
BOOST_SPIRIT_X3_DERIVED_CATEGORY(hex_digit)
BOOST_SPIRIT_X3_DERIVED_CATEGORY(noncharacter_code_point)
BOOST_SPIRIT_X3_DERIVED_CATEGORY(default_ignorable_code_point)
#undef BOOST_SPIRIT_X3_DERIVED_CATEGORY
// Scripts
#define BOOST_SPIRIT_X3_SCRIPT(name) \
[[nodiscard]] static constexpr bool \
is_##name(char_type ch) noexcept \
{ \
return x3::unicode::get_script(ch) == x3::unicode::properties::name; \
} \
static constexpr void is_##name(char) = delete; \
static constexpr void is_##name(wchar_t) = delete;
BOOST_SPIRIT_X3_SCRIPT(adlam)
BOOST_SPIRIT_X3_SCRIPT(caucasian_albanian)
BOOST_SPIRIT_X3_SCRIPT(ahom)
BOOST_SPIRIT_X3_SCRIPT(arabic)
BOOST_SPIRIT_X3_SCRIPT(imperial_aramaic)
BOOST_SPIRIT_X3_SCRIPT(armenian)
BOOST_SPIRIT_X3_SCRIPT(avestan)
BOOST_SPIRIT_X3_SCRIPT(balinese)
BOOST_SPIRIT_X3_SCRIPT(bamum)
BOOST_SPIRIT_X3_SCRIPT(bassa_vah)
BOOST_SPIRIT_X3_SCRIPT(batak)
BOOST_SPIRIT_X3_SCRIPT(bengali)
BOOST_SPIRIT_X3_SCRIPT(bhaiksuki)
BOOST_SPIRIT_X3_SCRIPT(bopomofo)
BOOST_SPIRIT_X3_SCRIPT(brahmi)
BOOST_SPIRIT_X3_SCRIPT(braille)
BOOST_SPIRIT_X3_SCRIPT(buginese)
BOOST_SPIRIT_X3_SCRIPT(buhid)
BOOST_SPIRIT_X3_SCRIPT(chakma)
BOOST_SPIRIT_X3_SCRIPT(canadian_aboriginal)
BOOST_SPIRIT_X3_SCRIPT(carian)
BOOST_SPIRIT_X3_SCRIPT(cham)
BOOST_SPIRIT_X3_SCRIPT(cherokee)
BOOST_SPIRIT_X3_SCRIPT(chorasmian)
BOOST_SPIRIT_X3_SCRIPT(coptic)
BOOST_SPIRIT_X3_SCRIPT(cypro_minoan)
BOOST_SPIRIT_X3_SCRIPT(cypriot)
BOOST_SPIRIT_X3_SCRIPT(cyrillic)
BOOST_SPIRIT_X3_SCRIPT(devanagari)
BOOST_SPIRIT_X3_SCRIPT(dives_akuru)
BOOST_SPIRIT_X3_SCRIPT(dogra)
BOOST_SPIRIT_X3_SCRIPT(deseret)
BOOST_SPIRIT_X3_SCRIPT(duployan)
BOOST_SPIRIT_X3_SCRIPT(egyptian_hieroglyphs)
BOOST_SPIRIT_X3_SCRIPT(elbasan)
BOOST_SPIRIT_X3_SCRIPT(elymaic)
BOOST_SPIRIT_X3_SCRIPT(ethiopic)
BOOST_SPIRIT_X3_SCRIPT(georgian)
BOOST_SPIRIT_X3_SCRIPT(glagolitic)
BOOST_SPIRIT_X3_SCRIPT(gunjala_gondi)
BOOST_SPIRIT_X3_SCRIPT(masaram_gondi)
BOOST_SPIRIT_X3_SCRIPT(gothic)
BOOST_SPIRIT_X3_SCRIPT(grantha)
BOOST_SPIRIT_X3_SCRIPT(greek)
BOOST_SPIRIT_X3_SCRIPT(gujarati)
BOOST_SPIRIT_X3_SCRIPT(gurmukhi)
BOOST_SPIRIT_X3_SCRIPT(hangul)
BOOST_SPIRIT_X3_SCRIPT(han)
BOOST_SPIRIT_X3_SCRIPT(hanunoo)
BOOST_SPIRIT_X3_SCRIPT(hatran)
BOOST_SPIRIT_X3_SCRIPT(hebrew)
BOOST_SPIRIT_X3_SCRIPT(hiragana)
BOOST_SPIRIT_X3_SCRIPT(anatolian_hieroglyphs)
BOOST_SPIRIT_X3_SCRIPT(pahawh_hmong)
BOOST_SPIRIT_X3_SCRIPT(nyiakeng_puachue_hmong)
BOOST_SPIRIT_X3_SCRIPT(katakana_or_hiragana)
BOOST_SPIRIT_X3_SCRIPT(old_hungarian)
BOOST_SPIRIT_X3_SCRIPT(old_italic)
BOOST_SPIRIT_X3_SCRIPT(javanese)
BOOST_SPIRIT_X3_SCRIPT(kayah_li)
BOOST_SPIRIT_X3_SCRIPT(katakana)
BOOST_SPIRIT_X3_SCRIPT(kawi)
BOOST_SPIRIT_X3_SCRIPT(kharoshthi)
BOOST_SPIRIT_X3_SCRIPT(khmer)
BOOST_SPIRIT_X3_SCRIPT(khojki)
BOOST_SPIRIT_X3_SCRIPT(khitan_small_script)
BOOST_SPIRIT_X3_SCRIPT(kannada)
BOOST_SPIRIT_X3_SCRIPT(kaithi)
BOOST_SPIRIT_X3_SCRIPT(tai_tham)
BOOST_SPIRIT_X3_SCRIPT(lao)
BOOST_SPIRIT_X3_SCRIPT(latin)
BOOST_SPIRIT_X3_SCRIPT(lepcha)
BOOST_SPIRIT_X3_SCRIPT(limbu)
BOOST_SPIRIT_X3_SCRIPT(linear_a)
BOOST_SPIRIT_X3_SCRIPT(linear_b)
BOOST_SPIRIT_X3_SCRIPT(lisu)
BOOST_SPIRIT_X3_SCRIPT(lycian)
BOOST_SPIRIT_X3_SCRIPT(lydian)
BOOST_SPIRIT_X3_SCRIPT(mahajani)
BOOST_SPIRIT_X3_SCRIPT(makasar)
BOOST_SPIRIT_X3_SCRIPT(mandaic)
BOOST_SPIRIT_X3_SCRIPT(manichaean)
BOOST_SPIRIT_X3_SCRIPT(marchen)
BOOST_SPIRIT_X3_SCRIPT(medefaidrin)
BOOST_SPIRIT_X3_SCRIPT(mende_kikakui)
BOOST_SPIRIT_X3_SCRIPT(meroitic_cursive)
BOOST_SPIRIT_X3_SCRIPT(meroitic_hieroglyphs)
BOOST_SPIRIT_X3_SCRIPT(malayalam)
BOOST_SPIRIT_X3_SCRIPT(modi)
BOOST_SPIRIT_X3_SCRIPT(mongolian)
BOOST_SPIRIT_X3_SCRIPT(mro)
BOOST_SPIRIT_X3_SCRIPT(meetei_mayek)
BOOST_SPIRIT_X3_SCRIPT(multani)
BOOST_SPIRIT_X3_SCRIPT(myanmar)
BOOST_SPIRIT_X3_SCRIPT(nag_mundari)
BOOST_SPIRIT_X3_SCRIPT(nandinagari)
BOOST_SPIRIT_X3_SCRIPT(old_north_arabian)
BOOST_SPIRIT_X3_SCRIPT(nabataean)
BOOST_SPIRIT_X3_SCRIPT(newa)
BOOST_SPIRIT_X3_SCRIPT(nko)
BOOST_SPIRIT_X3_SCRIPT(nushu)
BOOST_SPIRIT_X3_SCRIPT(ogham)
BOOST_SPIRIT_X3_SCRIPT(ol_chiki)
BOOST_SPIRIT_X3_SCRIPT(old_turkic)
BOOST_SPIRIT_X3_SCRIPT(oriya)
BOOST_SPIRIT_X3_SCRIPT(osage)
BOOST_SPIRIT_X3_SCRIPT(osmanya)
BOOST_SPIRIT_X3_SCRIPT(old_uyghur)
BOOST_SPIRIT_X3_SCRIPT(palmyrene)
BOOST_SPIRIT_X3_SCRIPT(pau_cin_hau)
BOOST_SPIRIT_X3_SCRIPT(old_permic)
BOOST_SPIRIT_X3_SCRIPT(phags_pa)
BOOST_SPIRIT_X3_SCRIPT(inscriptional_pahlavi)
BOOST_SPIRIT_X3_SCRIPT(psalter_pahlavi)
BOOST_SPIRIT_X3_SCRIPT(phoenician)
BOOST_SPIRIT_X3_SCRIPT(miao)
BOOST_SPIRIT_X3_SCRIPT(inscriptional_parthian)
BOOST_SPIRIT_X3_SCRIPT(rejang)
BOOST_SPIRIT_X3_SCRIPT(hanifi_rohingya)
BOOST_SPIRIT_X3_SCRIPT(runic)
BOOST_SPIRIT_X3_SCRIPT(samaritan)
BOOST_SPIRIT_X3_SCRIPT(old_south_arabian)
BOOST_SPIRIT_X3_SCRIPT(saurashtra)
BOOST_SPIRIT_X3_SCRIPT(signwriting)
BOOST_SPIRIT_X3_SCRIPT(shavian)
BOOST_SPIRIT_X3_SCRIPT(sharada)
BOOST_SPIRIT_X3_SCRIPT(siddham)
BOOST_SPIRIT_X3_SCRIPT(khudawadi)
BOOST_SPIRIT_X3_SCRIPT(sinhala)
BOOST_SPIRIT_X3_SCRIPT(sogdian)
BOOST_SPIRIT_X3_SCRIPT(old_sogdian)
BOOST_SPIRIT_X3_SCRIPT(sora_sompeng)
BOOST_SPIRIT_X3_SCRIPT(soyombo)
BOOST_SPIRIT_X3_SCRIPT(sundanese)
BOOST_SPIRIT_X3_SCRIPT(syloti_nagri)
BOOST_SPIRIT_X3_SCRIPT(syriac)
BOOST_SPIRIT_X3_SCRIPT(tagbanwa)
BOOST_SPIRIT_X3_SCRIPT(takri)
BOOST_SPIRIT_X3_SCRIPT(tai_le)
BOOST_SPIRIT_X3_SCRIPT(new_tai_lue)
BOOST_SPIRIT_X3_SCRIPT(tamil)
BOOST_SPIRIT_X3_SCRIPT(tangut)
BOOST_SPIRIT_X3_SCRIPT(tai_viet)
BOOST_SPIRIT_X3_SCRIPT(telugu)
BOOST_SPIRIT_X3_SCRIPT(tifinagh)
BOOST_SPIRIT_X3_SCRIPT(tagalog)
BOOST_SPIRIT_X3_SCRIPT(thaana)
BOOST_SPIRIT_X3_SCRIPT(thai)
BOOST_SPIRIT_X3_SCRIPT(tibetan)
BOOST_SPIRIT_X3_SCRIPT(tirhuta)
BOOST_SPIRIT_X3_SCRIPT(tangsa)
BOOST_SPIRIT_X3_SCRIPT(toto)
BOOST_SPIRIT_X3_SCRIPT(ugaritic)
BOOST_SPIRIT_X3_SCRIPT(vai)
BOOST_SPIRIT_X3_SCRIPT(vithkuqi)
BOOST_SPIRIT_X3_SCRIPT(warang_citi)
BOOST_SPIRIT_X3_SCRIPT(wancho)
BOOST_SPIRIT_X3_SCRIPT(old_persian)
BOOST_SPIRIT_X3_SCRIPT(cuneiform)
BOOST_SPIRIT_X3_SCRIPT(yezidi)
BOOST_SPIRIT_X3_SCRIPT(yi)
BOOST_SPIRIT_X3_SCRIPT(zanabazar_square)
BOOST_SPIRIT_X3_SCRIPT(inherited)
BOOST_SPIRIT_X3_SCRIPT(common)
BOOST_SPIRIT_X3_SCRIPT(unknown)
#undef BOOST_SPIRIT_X3_SCRIPT
};
} // boost::spirit::x3::char_encoding
#endif

View File

@@ -1,377 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
Autogenerated by MultiStageTable.py (Unicode multi-stage
table builder) (c) Peter Kankowski, 2008
==============================================================================*/
#ifndef BOOST_SPIRIT_X3_CHAR_ENCODING_UNICODE_CLASSIFICATION_HPP
#define BOOST_SPIRIT_X3_CHAR_ENCODING_UNICODE_CLASSIFICATION_HPP
#include <boost/spirit/home/x3/char_encoding/unicode/detail/category_table.hpp>
#include <boost/spirit/home/x3/char_encoding/unicode/detail/script_table.hpp>
#include <boost/spirit/home/x3/char_encoding/unicode/detail/lowercase_table.hpp>
#include <boost/spirit/home/x3/char_encoding/unicode/detail/uppercase_table.hpp>
#include <cstdint>
namespace boost::spirit::x3::unicode
{
// This header provides Basic (Level 1) Unicode Support
// See http://unicode.org/reports/tr18/ for details
namespace properties
{
// bit pattern: xxMMMCCC
// MMM: major_category
// CCC: category
enum major_category
{
letter,
mark,
number,
separator,
other,
punctuation,
symbol
};
enum category
{
uppercase_letter = 0, // [Lu] an uppercase letter
lowercase_letter, // [Ll] a lowercase letter
titlecase_letter, // [Lt] a digraphic character, with first part uppercase
modifier_letter, // [Lm] a modifier letter
other_letter, // [Lo] other letters, including syllables and ideographs
nonspacing_mark = 8, // [Mn] a nonspacing combining mark (zero advance width)
enclosing_mark, // [Me] an enclosing combining mark
spacing_mark, // [Mc] a spacing combining mark (positive advance width)
decimal_number = 16, // [Nd] a decimal digit
letter_number, // [Nl] a letterlike numeric character
other_number, // [No] a numeric character of other type
space_separator = 24, // [Zs] a space character (of various non-zero widths)
line_separator, // [Zl] U+2028 LINE SEPARATOR only
paragraph_separator, // [Zp] U+2029 PARAGRAPH SEPARATOR only
control = 32, // [Cc] a C0 or C1 control code
format, // [Cf] a format control character
private_use, // [Co] a private-use character
surrogate, // [Cs] a surrogate code point
unassigned, // [Cn] a reserved unassigned code point or a noncharacter
dash_punctuation = 40, // [Pd] a dash or hyphen punctuation mark
open_punctuation, // [Ps] an opening punctuation mark (of a pair)
close_punctuation, // [Pe] a closing punctuation mark (of a pair)
connector_punctuation, // [Pc] a connecting punctuation mark, like a tie
other_punctuation, // [Po] a punctuation mark of other type
initial_punctuation, // [Pi] an initial quotation mark
final_punctuation, // [Pf] a final quotation mark
math_symbol = 48, // [Sm] a symbol of primarily mathematical use
currency_symbol, // [Sc] a currency sign
modifier_symbol, // [Sk] a non-letterlike modifier symbol
other_symbol // [So] a symbol of other type
};
enum derived_properties
{
alphabetic = 64,
uppercase = 128,
lowercase = 256,
white_space = 512,
hex_digit = 1024,
noncharacter_code_point = 2048,
default_ignorable_code_point = 4096
};
enum script
{
adlam,
caucasian_albanian,
ahom,
arabic,
imperial_aramaic,
armenian,
avestan,
balinese,
bamum,
bassa_vah,
batak,
bengali,
bhaiksuki,
bopomofo,
brahmi,
braille,
buginese,
buhid,
chakma,
canadian_aboriginal,
carian,
cham,
cherokee,
chorasmian,
coptic,
cypro_minoan,
cypriot,
cyrillic,
devanagari,
dives_akuru,
dogra,
deseret,
duployan,
egyptian_hieroglyphs,
elbasan,
elymaic,
ethiopic,
georgian,
glagolitic,
gunjala_gondi,
masaram_gondi,
gothic,
grantha,
greek,
gujarati,
gurmukhi,
hangul,
han,
hanunoo,
hatran,
hebrew,
hiragana,
anatolian_hieroglyphs,
pahawh_hmong,
nyiakeng_puachue_hmong,
katakana_or_hiragana,
old_hungarian,
old_italic,
javanese,
kayah_li,
katakana,
kawi,
kharoshthi,
khmer,
khojki,
khitan_small_script,
kannada,
kaithi,
tai_tham,
lao,
latin,
lepcha,
limbu,
linear_a,
linear_b,
lisu,
lycian,
lydian,
mahajani,
makasar,
mandaic,
manichaean,
marchen,
medefaidrin,
mende_kikakui,
meroitic_cursive,
meroitic_hieroglyphs,
malayalam,
modi,
mongolian,
mro,
meetei_mayek,
multani,
myanmar,
nag_mundari,
nandinagari,
old_north_arabian,
nabataean,
newa,
nko,
nushu,
ogham,
ol_chiki,
old_turkic,
oriya,
osage,
osmanya,
old_uyghur,
palmyrene,
pau_cin_hau,
old_permic,
phags_pa,
inscriptional_pahlavi,
psalter_pahlavi,
phoenician,
miao,
inscriptional_parthian,
rejang,
hanifi_rohingya,
runic,
samaritan,
old_south_arabian,
saurashtra,
signwriting,
shavian,
sharada,
siddham,
khudawadi,
sinhala,
sogdian,
old_sogdian,
sora_sompeng,
soyombo,
sundanese,
syloti_nagri,
syriac,
tagbanwa,
takri,
tai_le,
new_tai_lue,
tamil,
tangut,
tai_viet,
telugu,
tifinagh,
tagalog,
thaana,
thai,
tibetan,
tirhuta,
tangsa,
toto,
ugaritic,
vai,
vithkuqi,
warang_citi,
wancho,
old_persian,
cuneiform,
yezidi,
yi,
zanabazar_square,
inherited,
common,
unknown
};
} // properties
[[nodiscard]] constexpr properties::category get_category(std::uint32_t ch) noexcept
{
return static_cast<properties::category>(detail::category_lookup(ch) & 0x3F);
}
[[nodiscard]] constexpr properties::major_category get_major_category(std::uint32_t ch) noexcept
{
return static_cast<properties::major_category>(unicode::get_category(ch) >> 3);
}
[[nodiscard]] constexpr bool is_punctuation(std::uint32_t ch) noexcept
{
return unicode::get_major_category(ch) == properties::punctuation;
}
[[nodiscard]] constexpr bool is_decimal_number(std::uint32_t ch) noexcept
{
return unicode::get_category(ch) == properties::decimal_number;
}
[[nodiscard]] constexpr bool is_hex_digit(std::uint32_t ch) noexcept
{
return (detail::category_lookup(ch) & properties::hex_digit) != 0;
}
[[nodiscard]] constexpr bool is_control(std::uint32_t ch) noexcept
{
return unicode::get_category(ch) == properties::control;
}
[[nodiscard]] constexpr bool is_alphabetic(std::uint32_t ch) noexcept
{
return (detail::category_lookup(ch) & properties::alphabetic) != 0;
}
[[nodiscard]] constexpr bool is_alphanumeric(std::uint32_t ch) noexcept
{
return unicode::is_decimal_number(ch) || unicode::is_alphabetic(ch);
}
[[nodiscard]] constexpr bool is_uppercase(std::uint32_t ch) noexcept
{
return (detail::category_lookup(ch) & properties::uppercase) != 0;
}
[[nodiscard]] constexpr bool is_lowercase(std::uint32_t ch) noexcept
{
return (detail::category_lookup(ch) & properties::lowercase) != 0;
}
[[nodiscard]] constexpr bool is_white_space(std::uint32_t ch) noexcept
{
return (detail::category_lookup(ch) & properties::white_space) != 0;
}
[[nodiscard]] constexpr bool is_blank(std::uint32_t ch) noexcept
{
switch (ch)
{
case '\n': case '\v': case '\f': case '\r':
return false;
default:
return unicode::is_white_space(ch)
&& !( unicode::get_category(ch) == properties::line_separator
|| unicode::get_category(ch) == properties::paragraph_separator
);
}
}
[[nodiscard]] constexpr bool is_graph(std::uint32_t ch) noexcept
{
return !( unicode::is_white_space(ch)
|| unicode::get_category(ch) == properties::control
|| unicode::get_category(ch) == properties::surrogate
|| unicode::get_category(ch) == properties::unassigned
);
}
[[nodiscard]] constexpr bool is_print(std::uint32_t ch) noexcept
{
return (unicode::is_graph(ch) || unicode::is_blank(ch)) && !unicode::is_control(ch);
}
[[nodiscard]] constexpr bool is_noncharacter_code_point(std::uint32_t ch) noexcept
{
return (detail::category_lookup(ch) & properties::noncharacter_code_point) != 0;
}
[[nodiscard]] constexpr bool is_default_ignorable_code_point(std::uint32_t ch) noexcept
{
return (detail::category_lookup(ch) & properties::default_ignorable_code_point) != 0;
}
[[nodiscard]] constexpr properties::script get_script(std::uint32_t ch) noexcept
{
return static_cast<properties::script>(detail::script_lookup(ch));
}
[[nodiscard]] constexpr std::uint32_t to_lowercase(std::uint32_t ch) noexcept
{
// The table returns 0 to signal that this code maps to itself
std::uint32_t r = detail::lowercase_lookup(ch);
return (r == 0)? ch : r;
}
[[nodiscard]] constexpr std::uint32_t to_uppercase(std::uint32_t ch) noexcept
{
// The table returns 0 to signal that this code maps to itself
std::uint32_t r = detail::uppercase_lookup(ch);
return (r == 0)? ch : r;
}
} // boost::spirit::x3::unicode
#endif

View File

@@ -1,754 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
AUTOGENERATED. DO NOT EDIT!!!
==============================================================================*/
#include <cstdint>
namespace boost::spirit::x3::unicode::detail
{
inline constexpr std::uint8_t lowercase_stage1[] = {
0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 9, 6, 10, 11,
6, 12, 6, 6, 13, 6, 6, 6, 6, 6, 6, 6, 14, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 15, 16, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 17,
6, 6, 6, 6, 18, 19, 6, 6, 6, 6, 6, 6, 20, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 21, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 22, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 23, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
};
inline constexpr std::uint32_t lowercase_stage2[] = {
// block 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 0, 248, 249, 250, 251, 252, 253, 254, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 1
257, 0, 259, 0, 261, 0, 263, 0, 265, 0, 267, 0, 269, 0, 271, 0,
273, 0, 275, 0, 277, 0, 279, 0, 281, 0, 283, 0, 285, 0, 287, 0,
289, 0, 291, 0, 293, 0, 295, 0, 297, 0, 299, 0, 301, 0, 303, 0,
105, 0, 307, 0, 309, 0, 311, 0, 0, 314, 0, 316, 0, 318, 0, 320,
0, 322, 0, 324, 0, 326, 0, 328, 0, 0, 331, 0, 333, 0, 335, 0,
337, 0, 339, 0, 341, 0, 343, 0, 345, 0, 347, 0, 349, 0, 351, 0,
353, 0, 355, 0, 357, 0, 359, 0, 361, 0, 363, 0, 365, 0, 367, 0,
369, 0, 371, 0, 373, 0, 375, 0, 255, 378, 0, 380, 0, 382, 0, 0,
0, 595, 387, 0, 389, 0, 596, 392, 0, 598, 599, 396, 0, 0, 477, 601,
603, 402, 0, 608, 611, 0, 617, 616, 409, 0, 0, 0, 623, 626, 0, 629,
417, 0, 419, 0, 421, 0, 640, 424, 0, 643, 0, 0, 429, 0, 648, 432,
0, 650, 651, 436, 0, 438, 0, 658, 441, 0, 0, 0, 445, 0, 0, 0,
0, 0, 0, 0, 454, 454, 0, 457, 457, 0, 460, 460, 0, 462, 0, 464,
0, 466, 0, 468, 0, 470, 0, 472, 0, 474, 0, 476, 0, 0, 479, 0,
481, 0, 483, 0, 485, 0, 487, 0, 489, 0, 491, 0, 493, 0, 495, 0,
0, 499, 499, 0, 501, 0, 405, 447, 505, 0, 507, 0, 509, 0, 511, 0,
// block 2
513, 0, 515, 0, 517, 0, 519, 0, 521, 0, 523, 0, 525, 0, 527, 0,
529, 0, 531, 0, 533, 0, 535, 0, 537, 0, 539, 0, 541, 0, 543, 0,
414, 0, 547, 0, 549, 0, 551, 0, 553, 0, 555, 0, 557, 0, 559, 0,
561, 0, 563, 0, 0, 0, 0, 0, 0, 0, 11365, 572, 0, 410, 11366, 0,
0, 578, 0, 384, 649, 652, 583, 0, 585, 0, 587, 0, 589, 0, 591, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
881, 0, 883, 0, 0, 0, 887, 0, 0, 0, 0, 0, 0, 0, 0, 1011,
0, 0, 0, 0, 0, 0, 940, 0, 941, 942, 943, 0, 972, 0, 973, 974,
0, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959,
960, 961, 0, 963, 964, 965, 966, 967, 968, 969, 970, 971, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 983,
0, 0, 0, 0, 0, 0, 0, 0, 985, 0, 987, 0, 989, 0, 991, 0,
993, 0, 995, 0, 997, 0, 999, 0, 1001, 0, 1003, 0, 1005, 0, 1007, 0,
0, 0, 0, 0, 952, 0, 0, 1016, 0, 1010, 1019, 0, 0, 891, 892, 893,
// block 4
1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119,
1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087,
1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1121, 0, 1123, 0, 1125, 0, 1127, 0, 1129, 0, 1131, 0, 1133, 0, 1135, 0,
1137, 0, 1139, 0, 1141, 0, 1143, 0, 1145, 0, 1147, 0, 1149, 0, 1151, 0,
1153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1163, 0, 1165, 0, 1167, 0,
1169, 0, 1171, 0, 1173, 0, 1175, 0, 1177, 0, 1179, 0, 1181, 0, 1183, 0,
1185, 0, 1187, 0, 1189, 0, 1191, 0, 1193, 0, 1195, 0, 1197, 0, 1199, 0,
1201, 0, 1203, 0, 1205, 0, 1207, 0, 1209, 0, 1211, 0, 1213, 0, 1215, 0,
1231, 1218, 0, 1220, 0, 1222, 0, 1224, 0, 1226, 0, 1228, 0, 1230, 0, 0,
1233, 0, 1235, 0, 1237, 0, 1239, 0, 1241, 0, 1243, 0, 1245, 0, 1247, 0,
1249, 0, 1251, 0, 1253, 0, 1255, 0, 1257, 0, 1259, 0, 1261, 0, 1263, 0,
1265, 0, 1267, 0, 1269, 0, 1271, 0, 1273, 0, 1275, 0, 1277, 0, 1279, 0,
// block 5
1281, 0, 1283, 0, 1285, 0, 1287, 0, 1289, 0, 1291, 0, 1293, 0, 1295, 0,
1297, 0, 1299, 0, 1301, 0, 1303, 0, 1305, 0, 1307, 0, 1309, 0, 1311, 0,
1313, 0, 1315, 0, 1317, 0, 1319, 0, 1321, 0, 1323, 0, 1325, 0, 1327, 0,
0, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391,
1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407,
1408, 1409, 1410, 1411, 1412, 1413, 1414, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11520, 11521, 11522, 11523, 11524, 11525, 11526, 11527, 11528, 11529, 11530, 11531, 11532, 11533, 11534, 11535,
11536, 11537, 11538, 11539, 11540, 11541, 11542, 11543, 11544, 11545, 11546, 11547, 11548, 11549, 11550, 11551,
11552, 11553, 11554, 11555, 11556, 11557, 0, 11559, 0, 0, 0, 0, 0, 11565, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43888, 43889, 43890, 43891, 43892, 43893, 43894, 43895, 43896, 43897, 43898, 43899, 43900, 43901, 43902, 43903,
43904, 43905, 43906, 43907, 43908, 43909, 43910, 43911, 43912, 43913, 43914, 43915, 43916, 43917, 43918, 43919,
43920, 43921, 43922, 43923, 43924, 43925, 43926, 43927, 43928, 43929, 43930, 43931, 43932, 43933, 43934, 43935,
43936, 43937, 43938, 43939, 43940, 43941, 43942, 43943, 43944, 43945, 43946, 43947, 43948, 43949, 43950, 43951,
43952, 43953, 43954, 43955, 43956, 43957, 43958, 43959, 43960, 43961, 43962, 43963, 43964, 43965, 43966, 43967,
5112, 5113, 5114, 5115, 5116, 5117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4304, 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319,
4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335,
4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 0, 0, 4349, 4350, 4351,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 10
7681, 0, 7683, 0, 7685, 0, 7687, 0, 7689, 0, 7691, 0, 7693, 0, 7695, 0,
7697, 0, 7699, 0, 7701, 0, 7703, 0, 7705, 0, 7707, 0, 7709, 0, 7711, 0,
7713, 0, 7715, 0, 7717, 0, 7719, 0, 7721, 0, 7723, 0, 7725, 0, 7727, 0,
7729, 0, 7731, 0, 7733, 0, 7735, 0, 7737, 0, 7739, 0, 7741, 0, 7743, 0,
7745, 0, 7747, 0, 7749, 0, 7751, 0, 7753, 0, 7755, 0, 7757, 0, 7759, 0,
7761, 0, 7763, 0, 7765, 0, 7767, 0, 7769, 0, 7771, 0, 7773, 0, 7775, 0,
7777, 0, 7779, 0, 7781, 0, 7783, 0, 7785, 0, 7787, 0, 7789, 0, 7791, 0,
7793, 0, 7795, 0, 7797, 0, 7799, 0, 7801, 0, 7803, 0, 7805, 0, 7807, 0,
7809, 0, 7811, 0, 7813, 0, 7815, 0, 7817, 0, 7819, 0, 7821, 0, 7823, 0,
7825, 0, 7827, 0, 7829, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 0,
7841, 0, 7843, 0, 7845, 0, 7847, 0, 7849, 0, 7851, 0, 7853, 0, 7855, 0,
7857, 0, 7859, 0, 7861, 0, 7863, 0, 7865, 0, 7867, 0, 7869, 0, 7871, 0,
7873, 0, 7875, 0, 7877, 0, 7879, 0, 7881, 0, 7883, 0, 7885, 0, 7887, 0,
7889, 0, 7891, 0, 7893, 0, 7895, 0, 7897, 0, 7899, 0, 7901, 0, 7903, 0,
7905, 0, 7907, 0, 7909, 0, 7911, 0, 7913, 0, 7915, 0, 7917, 0, 7919, 0,
7921, 0, 7923, 0, 7925, 0, 7927, 0, 7929, 0, 7931, 0, 7933, 0, 7935, 0,
// block 11
0, 0, 0, 0, 0, 0, 0, 0, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943,
0, 0, 0, 0, 0, 0, 0, 0, 7952, 7953, 7954, 7955, 7956, 7957, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 7968, 7969, 7970, 7971, 7972, 7973, 7974, 7975,
0, 0, 0, 0, 0, 0, 0, 0, 7984, 7985, 7986, 7987, 7988, 7989, 7990, 7991,
0, 0, 0, 0, 0, 0, 0, 0, 8000, 8001, 8002, 8003, 8004, 8005, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 8017, 0, 8019, 0, 8021, 0, 8023,
0, 0, 0, 0, 0, 0, 0, 0, 8032, 8033, 8034, 8035, 8036, 8037, 8038, 8039,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8064, 8065, 8066, 8067, 8068, 8069, 8070, 8071,
0, 0, 0, 0, 0, 0, 0, 0, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087,
0, 0, 0, 0, 0, 0, 0, 0, 8096, 8097, 8098, 8099, 8100, 8101, 8102, 8103,
0, 0, 0, 0, 0, 0, 0, 0, 8112, 8113, 8048, 8049, 8115, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8050, 8051, 8052, 8053, 8131, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8144, 8145, 8054, 8055, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8160, 8161, 8058, 8059, 8165, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8056, 8057, 8060, 8061, 8179, 0, 0, 0,
// block 12
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 969, 0, 0, 0, 107, 229, 0, 0, 0, 0,
0, 0, 8526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8560, 8561, 8562, 8563, 8564, 8565, 8566, 8567, 8568, 8569, 8570, 8571, 8572, 8573, 8574, 8575,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 8580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 13
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 9424, 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, 9433,
9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441, 9442, 9443, 9444, 9445, 9446, 9447, 9448, 9449,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 14
11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327,
11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343,
11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351, 11352, 11353, 11354, 11355, 11356, 11357, 11358, 11359,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11361, 0, 619, 7549, 637, 0, 0, 11368, 0, 11370, 0, 11372, 0, 593, 625, 592,
594, 0, 11379, 0, 0, 11382, 0, 0, 0, 0, 0, 0, 0, 0, 575, 576,
11393, 0, 11395, 0, 11397, 0, 11399, 0, 11401, 0, 11403, 0, 11405, 0, 11407, 0,
11409, 0, 11411, 0, 11413, 0, 11415, 0, 11417, 0, 11419, 0, 11421, 0, 11423, 0,
11425, 0, 11427, 0, 11429, 0, 11431, 0, 11433, 0, 11435, 0, 11437, 0, 11439, 0,
11441, 0, 11443, 0, 11445, 0, 11447, 0, 11449, 0, 11451, 0, 11453, 0, 11455, 0,
11457, 0, 11459, 0, 11461, 0, 11463, 0, 11465, 0, 11467, 0, 11469, 0, 11471, 0,
11473, 0, 11475, 0, 11477, 0, 11479, 0, 11481, 0, 11483, 0, 11485, 0, 11487, 0,
11489, 0, 11491, 0, 0, 0, 0, 0, 0, 0, 0, 11500, 0, 11502, 0, 0,
0, 0, 11507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 15
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42561, 0, 42563, 0, 42565, 0, 42567, 0, 42569, 0, 42571, 0, 42573, 0, 42575, 0,
42577, 0, 42579, 0, 42581, 0, 42583, 0, 42585, 0, 42587, 0, 42589, 0, 42591, 0,
42593, 0, 42595, 0, 42597, 0, 42599, 0, 42601, 0, 42603, 0, 42605, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42625, 0, 42627, 0, 42629, 0, 42631, 0, 42633, 0, 42635, 0, 42637, 0, 42639, 0,
42641, 0, 42643, 0, 42645, 0, 42647, 0, 42649, 0, 42651, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 16
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 42787, 0, 42789, 0, 42791, 0, 42793, 0, 42795, 0, 42797, 0, 42799, 0,
0, 0, 42803, 0, 42805, 0, 42807, 0, 42809, 0, 42811, 0, 42813, 0, 42815, 0,
42817, 0, 42819, 0, 42821, 0, 42823, 0, 42825, 0, 42827, 0, 42829, 0, 42831, 0,
42833, 0, 42835, 0, 42837, 0, 42839, 0, 42841, 0, 42843, 0, 42845, 0, 42847, 0,
42849, 0, 42851, 0, 42853, 0, 42855, 0, 42857, 0, 42859, 0, 42861, 0, 42863, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 42874, 0, 42876, 0, 7545, 42879, 0,
42881, 0, 42883, 0, 42885, 0, 42887, 0, 0, 0, 0, 42892, 0, 613, 0, 0,
42897, 0, 42899, 0, 0, 0, 42903, 0, 42905, 0, 42907, 0, 42909, 0, 42911, 0,
42913, 0, 42915, 0, 42917, 0, 42919, 0, 42921, 0, 614, 604, 609, 620, 618, 0,
670, 647, 669, 43859, 42933, 0, 42935, 0, 42937, 0, 42939, 0, 42941, 0, 42943, 0,
42945, 0, 42947, 0, 42900, 642, 7566, 42952, 0, 42954, 0, 0, 0, 0, 0, 0,
42961, 0, 0, 0, 0, 0, 42967, 0, 42969, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 42998, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 17
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359,
65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 18
66600, 66601, 66602, 66603, 66604, 66605, 66606, 66607, 66608, 66609, 66610, 66611, 66612, 66613, 66614, 66615,
66616, 66617, 66618, 66619, 66620, 66621, 66622, 66623, 66624, 66625, 66626, 66627, 66628, 66629, 66630, 66631,
66632, 66633, 66634, 66635, 66636, 66637, 66638, 66639, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66776, 66777, 66778, 66779, 66780, 66781, 66782, 66783, 66784, 66785, 66786, 66787, 66788, 66789, 66790, 66791,
66792, 66793, 66794, 66795, 66796, 66797, 66798, 66799, 66800, 66801, 66802, 66803, 66804, 66805, 66806, 66807,
66808, 66809, 66810, 66811, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 19
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66967, 66968, 66969, 66970, 66971, 66972, 66973, 66974, 66975, 66976, 66977, 0, 66979, 66980, 66981, 66982,
66983, 66984, 66985, 66986, 66987, 66988, 66989, 66990, 66991, 66992, 66993, 0, 66995, 66996, 66997, 66998,
66999, 67000, 67001, 0, 67003, 67004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68800, 68801, 68802, 68803, 68804, 68805, 68806, 68807, 68808, 68809, 68810, 68811, 68812, 68813, 68814, 68815,
68816, 68817, 68818, 68819, 68820, 68821, 68822, 68823, 68824, 68825, 68826, 68827, 68828, 68829, 68830, 68831,
68832, 68833, 68834, 68835, 68836, 68837, 68838, 68839, 68840, 68841, 68842, 68843, 68844, 68845, 68846, 68847,
68848, 68849, 68850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 21
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71872, 71873, 71874, 71875, 71876, 71877, 71878, 71879, 71880, 71881, 71882, 71883, 71884, 71885, 71886, 71887,
71888, 71889, 71890, 71891, 71892, 71893, 71894, 71895, 71896, 71897, 71898, 71899, 71900, 71901, 71902, 71903,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 22
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93792, 93793, 93794, 93795, 93796, 93797, 93798, 93799, 93800, 93801, 93802, 93803, 93804, 93805, 93806, 93807,
93808, 93809, 93810, 93811, 93812, 93813, 93814, 93815, 93816, 93817, 93818, 93819, 93820, 93821, 93822, 93823,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 23
125218, 125219, 125220, 125221, 125222, 125223, 125224, 125225, 125226, 125227, 125228, 125229, 125230, 125231, 125232, 125233,
125234, 125235, 125236, 125237, 125238, 125239, 125240, 125241, 125242, 125243, 125244, 125245, 125246, 125247, 125248, 125249,
125250, 125251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
[[nodiscard]] constexpr std::uint32_t lowercase_lookup(std::uint32_t ch) noexcept
{
std::uint32_t block_offset = lowercase_stage1[ch / 256] * 256;
return lowercase_stage2[block_offset + ch % 256];
}
} // boost::spirit::x3::unicode::detail

View File

@@ -1,811 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
AUTOGENERATED. DO NOT EDIT!!!
==============================================================================*/
#include <cstdint>
namespace boost::spirit::x3::unicode::detail
{
inline constexpr std::uint8_t uppercase_stage1[] = {
0, 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 9, 10, 11, 12,
6, 13, 6, 6, 14, 6, 6, 6, 6, 6, 6, 6, 15, 16, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 17, 18, 6, 6, 6, 19, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 20,
6, 6, 6, 6, 21, 22, 6, 6, 6, 6, 6, 6, 23, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 24, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 25, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 26, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
};
inline constexpr std::uint32_t uppercase_stage2[] = {
// block 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 924, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 0, 216, 217, 218, 219, 220, 221, 222, 376,
// block 1
0, 256, 0, 258, 0, 260, 0, 262, 0, 264, 0, 266, 0, 268, 0, 270,
0, 272, 0, 274, 0, 276, 0, 278, 0, 280, 0, 282, 0, 284, 0, 286,
0, 288, 0, 290, 0, 292, 0, 294, 0, 296, 0, 298, 0, 300, 0, 302,
0, 73, 0, 306, 0, 308, 0, 310, 0, 0, 313, 0, 315, 0, 317, 0,
319, 0, 321, 0, 323, 0, 325, 0, 327, 0, 0, 330, 0, 332, 0, 334,
0, 336, 0, 338, 0, 340, 0, 342, 0, 344, 0, 346, 0, 348, 0, 350,
0, 352, 0, 354, 0, 356, 0, 358, 0, 360, 0, 362, 0, 364, 0, 366,
0, 368, 0, 370, 0, 372, 0, 374, 0, 0, 377, 0, 379, 0, 381, 83,
579, 0, 0, 386, 0, 388, 0, 0, 391, 0, 0, 0, 395, 0, 0, 0,
0, 0, 401, 0, 0, 502, 0, 0, 0, 408, 573, 0, 0, 0, 544, 0,
0, 416, 0, 418, 0, 420, 0, 0, 423, 0, 0, 0, 0, 428, 0, 0,
431, 0, 0, 0, 435, 0, 437, 0, 0, 440, 0, 0, 0, 444, 0, 503,
0, 0, 0, 0, 0, 452, 452, 0, 455, 455, 0, 458, 458, 0, 461, 0,
463, 0, 465, 0, 467, 0, 469, 0, 471, 0, 473, 0, 475, 398, 0, 478,
0, 480, 0, 482, 0, 484, 0, 486, 0, 488, 0, 490, 0, 492, 0, 494,
0, 0, 497, 497, 0, 500, 0, 0, 0, 504, 0, 506, 0, 508, 0, 510,
// block 2
0, 512, 0, 514, 0, 516, 0, 518, 0, 520, 0, 522, 0, 524, 0, 526,
0, 528, 0, 530, 0, 532, 0, 534, 0, 536, 0, 538, 0, 540, 0, 542,
0, 0, 0, 546, 0, 548, 0, 550, 0, 552, 0, 554, 0, 556, 0, 558,
0, 560, 0, 562, 0, 0, 0, 0, 0, 0, 0, 0, 571, 0, 0, 11390,
11391, 0, 577, 0, 0, 0, 0, 582, 0, 584, 0, 586, 0, 588, 0, 590,
11375, 11373, 11376, 385, 390, 0, 393, 394, 0, 399, 0, 400, 42923, 0, 0, 0,
403, 42924, 0, 404, 0, 42893, 42922, 0, 407, 406, 42926, 11362, 42925, 0, 0, 412,
0, 11374, 413, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 11364, 0, 0,
422, 0, 42949, 425, 0, 0, 0, 42929, 430, 580, 433, 434, 581, 0, 0, 0,
0, 0, 439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42930, 42928, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 880, 0, 882, 0, 0, 0, 886, 0, 0, 0, 1021, 1022, 1023, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 902, 904, 905, 906,
0, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927,
928, 929, 931, 931, 932, 933, 934, 935, 936, 937, 938, 939, 908, 910, 911, 0,
914, 920, 0, 0, 0, 934, 928, 975, 0, 984, 0, 986, 0, 988, 0, 990,
0, 992, 0, 994, 0, 996, 0, 998, 0, 1000, 0, 1002, 0, 1004, 0, 1006,
922, 929, 1017, 895, 0, 917, 0, 0, 1015, 0, 0, 1018, 0, 0, 0, 0,
// block 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055,
1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071,
1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039,
0, 1120, 0, 1122, 0, 1124, 0, 1126, 0, 1128, 0, 1130, 0, 1132, 0, 1134,
0, 1136, 0, 1138, 0, 1140, 0, 1142, 0, 1144, 0, 1146, 0, 1148, 0, 1150,
0, 1152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1162, 0, 1164, 0, 1166,
0, 1168, 0, 1170, 0, 1172, 0, 1174, 0, 1176, 0, 1178, 0, 1180, 0, 1182,
0, 1184, 0, 1186, 0, 1188, 0, 1190, 0, 1192, 0, 1194, 0, 1196, 0, 1198,
0, 1200, 0, 1202, 0, 1204, 0, 1206, 0, 1208, 0, 1210, 0, 1212, 0, 1214,
0, 0, 1217, 0, 1219, 0, 1221, 0, 1223, 0, 1225, 0, 1227, 0, 1229, 1216,
0, 1232, 0, 1234, 0, 1236, 0, 1238, 0, 1240, 0, 1242, 0, 1244, 0, 1246,
0, 1248, 0, 1250, 0, 1252, 0, 1254, 0, 1256, 0, 1258, 0, 1260, 0, 1262,
0, 1264, 0, 1266, 0, 1268, 0, 1270, 0, 1272, 0, 1274, 0, 1276, 0, 1278,
// block 5
0, 1280, 0, 1282, 0, 1284, 0, 1286, 0, 1288, 0, 1290, 0, 1292, 0, 1294,
0, 1296, 0, 1298, 0, 1300, 0, 1302, 0, 1304, 0, 1306, 0, 1308, 0, 1310,
0, 1312, 0, 1314, 0, 1316, 0, 1318, 0, 1320, 0, 1322, 0, 1324, 0, 1326,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343,
1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359,
1360, 1361, 1362, 1363, 1364, 1365, 1366, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327,
7328, 7329, 7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343,
7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 0, 0, 7357, 7358, 7359,
// block 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 5104, 5105, 5106, 5107, 5108, 5109, 0, 0,
// block 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1042, 1044, 1054, 1057, 1058, 1058, 1066, 1122, 42570, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 42877, 0, 0, 0, 11363, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42950, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 11
0, 7680, 0, 7682, 0, 7684, 0, 7686, 0, 7688, 0, 7690, 0, 7692, 0, 7694,
0, 7696, 0, 7698, 0, 7700, 0, 7702, 0, 7704, 0, 7706, 0, 7708, 0, 7710,
0, 7712, 0, 7714, 0, 7716, 0, 7718, 0, 7720, 0, 7722, 0, 7724, 0, 7726,
0, 7728, 0, 7730, 0, 7732, 0, 7734, 0, 7736, 0, 7738, 0, 7740, 0, 7742,
0, 7744, 0, 7746, 0, 7748, 0, 7750, 0, 7752, 0, 7754, 0, 7756, 0, 7758,
0, 7760, 0, 7762, 0, 7764, 0, 7766, 0, 7768, 0, 7770, 0, 7772, 0, 7774,
0, 7776, 0, 7778, 0, 7780, 0, 7782, 0, 7784, 0, 7786, 0, 7788, 0, 7790,
0, 7792, 0, 7794, 0, 7796, 0, 7798, 0, 7800, 0, 7802, 0, 7804, 0, 7806,
0, 7808, 0, 7810, 0, 7812, 0, 7814, 0, 7816, 0, 7818, 0, 7820, 0, 7822,
0, 7824, 0, 7826, 0, 7828, 0, 0, 0, 0, 0, 7776, 0, 0, 0, 0,
0, 7840, 0, 7842, 0, 7844, 0, 7846, 0, 7848, 0, 7850, 0, 7852, 0, 7854,
0, 7856, 0, 7858, 0, 7860, 0, 7862, 0, 7864, 0, 7866, 0, 7868, 0, 7870,
0, 7872, 0, 7874, 0, 7876, 0, 7878, 0, 7880, 0, 7882, 0, 7884, 0, 7886,
0, 7888, 0, 7890, 0, 7892, 0, 7894, 0, 7896, 0, 7898, 0, 7900, 0, 7902,
0, 7904, 0, 7906, 0, 7908, 0, 7910, 0, 7912, 0, 7914, 0, 7916, 0, 7918,
0, 7920, 0, 7922, 0, 7924, 0, 7926, 0, 7928, 0, 7930, 0, 7932, 0, 7934,
// block 12
7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951, 0, 0, 0, 0, 0, 0, 0, 0,
7960, 7961, 7962, 7963, 7964, 7965, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 0, 0, 0, 0, 0, 0, 0, 0,
7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999, 0, 0, 0, 0, 0, 0, 0, 0,
8008, 8009, 8010, 8011, 8012, 8013, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 8025, 0, 8027, 0, 8029, 0, 8031, 0, 0, 0, 0, 0, 0, 0, 0,
8040, 8041, 8042, 8043, 8044, 8045, 8046, 8047, 0, 0, 0, 0, 0, 0, 0, 0,
8122, 8123, 8136, 8137, 8138, 8139, 8154, 8155, 8184, 8185, 8170, 8171, 8186, 8187, 0, 0,
8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079, 0, 0, 0, 0, 0, 0, 0, 0,
8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, 0, 0, 0, 0, 0, 0, 0, 0,
8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111, 0, 0, 0, 0, 0, 0, 0, 0,
8120, 8121, 0, 8124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 921, 0,
0, 0, 0, 8140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8152, 8153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8168, 8169, 0, 0, 0, 8172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 8188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 13
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8498, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8544, 8545, 8546, 8547, 8548, 8549, 8550, 8551, 8552, 8553, 8554, 8555, 8556, 8557, 8558, 8559,
0, 0, 0, 0, 8579, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 14
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408, 9409, 9410, 9411, 9412, 9413,
9414, 9415, 9416, 9417, 9418, 9419, 9420, 9421, 9422, 9423, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 15
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11264, 11265, 11266, 11267, 11268, 11269, 11270, 11271, 11272, 11273, 11274, 11275, 11276, 11277, 11278, 11279,
11280, 11281, 11282, 11283, 11284, 11285, 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293, 11294, 11295,
11296, 11297, 11298, 11299, 11300, 11301, 11302, 11303, 11304, 11305, 11306, 11307, 11308, 11309, 11310, 11311,
0, 11360, 0, 0, 0, 570, 574, 0, 11367, 0, 11369, 0, 11371, 0, 0, 0,
0, 0, 0, 11378, 0, 0, 11381, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 11392, 0, 11394, 0, 11396, 0, 11398, 0, 11400, 0, 11402, 0, 11404, 0, 11406,
0, 11408, 0, 11410, 0, 11412, 0, 11414, 0, 11416, 0, 11418, 0, 11420, 0, 11422,
0, 11424, 0, 11426, 0, 11428, 0, 11430, 0, 11432, 0, 11434, 0, 11436, 0, 11438,
0, 11440, 0, 11442, 0, 11444, 0, 11446, 0, 11448, 0, 11450, 0, 11452, 0, 11454,
0, 11456, 0, 11458, 0, 11460, 0, 11462, 0, 11464, 0, 11466, 0, 11468, 0, 11470,
0, 11472, 0, 11474, 0, 11476, 0, 11478, 0, 11480, 0, 11482, 0, 11484, 0, 11486,
0, 11488, 0, 11490, 0, 0, 0, 0, 0, 0, 0, 0, 11499, 0, 11501, 0,
0, 0, 0, 11506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 16
4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271,
4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287,
4288, 4289, 4290, 4291, 4292, 4293, 0, 4295, 0, 0, 0, 0, 0, 4301, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 17
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 42560, 0, 42562, 0, 42564, 0, 42566, 0, 42568, 0, 42570, 0, 42572, 0, 42574,
0, 42576, 0, 42578, 0, 42580, 0, 42582, 0, 42584, 0, 42586, 0, 42588, 0, 42590,
0, 42592, 0, 42594, 0, 42596, 0, 42598, 0, 42600, 0, 42602, 0, 42604, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 42624, 0, 42626, 0, 42628, 0, 42630, 0, 42632, 0, 42634, 0, 42636, 0, 42638,
0, 42640, 0, 42642, 0, 42644, 0, 42646, 0, 42648, 0, 42650, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 18
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 42786, 0, 42788, 0, 42790, 0, 42792, 0, 42794, 0, 42796, 0, 42798,
0, 0, 0, 42802, 0, 42804, 0, 42806, 0, 42808, 0, 42810, 0, 42812, 0, 42814,
0, 42816, 0, 42818, 0, 42820, 0, 42822, 0, 42824, 0, 42826, 0, 42828, 0, 42830,
0, 42832, 0, 42834, 0, 42836, 0, 42838, 0, 42840, 0, 42842, 0, 42844, 0, 42846,
0, 42848, 0, 42850, 0, 42852, 0, 42854, 0, 42856, 0, 42858, 0, 42860, 0, 42862,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42873, 0, 42875, 0, 0, 42878,
0, 42880, 0, 42882, 0, 42884, 0, 42886, 0, 0, 0, 0, 42891, 0, 0, 0,
0, 42896, 0, 42898, 42948, 0, 0, 42902, 0, 42904, 0, 42906, 0, 42908, 0, 42910,
0, 42912, 0, 42914, 0, 42916, 0, 42918, 0, 42920, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 42932, 0, 42934, 0, 42936, 0, 42938, 0, 42940, 0, 42942,
0, 42944, 0, 42946, 0, 0, 0, 0, 42951, 0, 42953, 0, 0, 0, 0, 0,
0, 42960, 0, 0, 0, 0, 0, 42966, 0, 42968, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 42997, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 19
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 42931, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039,
5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055,
5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071,
5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087,
5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 65313, 65314, 65315, 65316, 65317, 65318, 65319, 65320, 65321, 65322, 65323, 65324, 65325, 65326, 65327,
65328, 65329, 65330, 65331, 65332, 65333, 65334, 65335, 65336, 65337, 65338, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 21
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 66560, 66561, 66562, 66563, 66564, 66565, 66566, 66567,
66568, 66569, 66570, 66571, 66572, 66573, 66574, 66575, 66576, 66577, 66578, 66579, 66580, 66581, 66582, 66583,
66584, 66585, 66586, 66587, 66588, 66589, 66590, 66591, 66592, 66593, 66594, 66595, 66596, 66597, 66598, 66599,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 66736, 66737, 66738, 66739, 66740, 66741, 66742, 66743,
66744, 66745, 66746, 66747, 66748, 66749, 66750, 66751, 66752, 66753, 66754, 66755, 66756, 66757, 66758, 66759,
66760, 66761, 66762, 66763, 66764, 66765, 66766, 66767, 66768, 66769, 66770, 66771, 0, 0, 0, 0,
// block 22
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 66928, 66929, 66930, 66931, 66932, 66933, 66934, 66935, 66936,
66937, 66938, 0, 66940, 66941, 66942, 66943, 66944, 66945, 66946, 66947, 66948, 66949, 66950, 66951, 66952,
66953, 66954, 0, 66956, 66957, 66958, 66959, 66960, 66961, 66962, 0, 66964, 66965, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 23
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68736, 68737, 68738, 68739, 68740, 68741, 68742, 68743, 68744, 68745, 68746, 68747, 68748, 68749, 68750, 68751,
68752, 68753, 68754, 68755, 68756, 68757, 68758, 68759, 68760, 68761, 68762, 68763, 68764, 68765, 68766, 68767,
68768, 68769, 68770, 68771, 68772, 68773, 68774, 68775, 68776, 68777, 68778, 68779, 68780, 68781, 68782, 68783,
68784, 68785, 68786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 24
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71840, 71841, 71842, 71843, 71844, 71845, 71846, 71847, 71848, 71849, 71850, 71851, 71852, 71853, 71854, 71855,
71856, 71857, 71858, 71859, 71860, 71861, 71862, 71863, 71864, 71865, 71866, 71867, 71868, 71869, 71870, 71871,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 25
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93760, 93761, 93762, 93763, 93764, 93765, 93766, 93767, 93768, 93769, 93770, 93771, 93772, 93773, 93774, 93775,
93776, 93777, 93778, 93779, 93780, 93781, 93782, 93783, 93784, 93785, 93786, 93787, 93788, 93789, 93790, 93791,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// block 26
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 125184, 125185, 125186, 125187, 125188, 125189, 125190, 125191, 125192, 125193, 125194, 125195, 125196, 125197,
125198, 125199, 125200, 125201, 125202, 125203, 125204, 125205, 125206, 125207, 125208, 125209, 125210, 125211, 125212, 125213,
125214, 125215, 125216, 125217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
[[nodiscard]] constexpr std::uint32_t uppercase_lookup(std::uint32_t ch) noexcept
{
std::uint32_t block_offset = uppercase_stage1[ch / 256] * 256;
return uppercase_stage2[block_offset + ch % 256];
}
} // boost::spirit::x3::unicode::detail

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,243 +9,102 @@
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
#include <boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp>
#include <boost/spirit/home/x3/core/call.hpp>
#include <boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp>
#include <boost/range/iterator_range_core.hpp>
#ifndef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
# pragma message("Use of `boost::iterator_range` is deprecated in X3. #define BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE")
# include <boost/range/iterator_range_core.hpp>
#endif
#include <ranges>
#include <iterator>
#include <concepts>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
struct raw_attribute_type; // TODO: move this to detail
struct raw_attribute_type;
struct parse_pass_context_tag;
// Ideally we should have a context-agnostic concept that can be used
// like `X3ActionFunctor<F>`, but we technically can't.
//
// In order to check `std::invocable`, we need to know the actual context
// type passed to the `.parse(...)` function but it is unknown until
// runtime.
//
// Even if we make up the most trivial context type (i.e. `unused_type`),
// such concept will be useless because a user-provided functor always
// operates on user-specific precondition that assumes the context
// holds exact specific type provided to the entry point (`x3::parse`).
template <typename Context>
inline bool& _pass(Context const& context)
{
return x3::get<parse_pass_context_tag>(context);
}
template <typename Subject, typename Action>
struct action : unary_parser<Subject, action<Subject, Action>>
{
static_assert(
!std::is_reference_v<Action>,
"Reference type is disallowed for semantic action functor to prevent dangling reference"
);
typedef unary_parser<Subject, action<Subject, Action>> base_type;
static bool const is_pass_through_unary = true;
static bool const has_action = true;
using base_type = unary_parser<Subject, action<Subject, Action>>;
static constexpr bool is_pass_through_unary = true;
static constexpr bool has_action = true;
constexpr action(Subject const& subject, Action f)
: base_type(subject), f(f) {}
Action f;
template <typename SubjectT, typename ActionT>
requires std::is_constructible_v<base_type, SubjectT> && std::is_constructible_v<Action, ActionT>
constexpr action(SubjectT&& subject, ActionT&& f)
noexcept(std::is_nothrow_constructible_v<base_type, SubjectT> && std::is_nothrow_constructible_v<Action, ActionT>)
: base_type(std::forward<SubjectT>(subject))
, f(std::forward<ActionT>(f))
template <typename Iterator, typename Context, typename RuleContext, typename Attribute>
bool call_action(
Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, Attribute& attr) const
{
}
// attr==unused, action wants attribute
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext>
[[nodiscard]] constexpr bool
parse(
It& first, Se const& last, Context const& context, RContext& rcontext, unused_type
) const noexcept(
std::is_nothrow_default_constructible_v<traits::attribute_of_t<action<Subject, Action>, Context>> &&
noexcept(this->parse_main(first, last, context, rcontext, std::declval<traits::attribute_of_t<action<Subject, Action>, Context>&>()))
)
{
using attribute_type = traits::attribute_of_t<action<Subject, Action>, Context>;
// Synthesize the attribute since one is not supplied
attribute_type attribute; // default-initialize
return this->parse_main(first, last, context, rcontext, attribute);
}
// Catch-all overload for non-unused_type attribute
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) const noexcept(noexcept(this->parse_main(first, last, context, rcontext, attr)))
{
return this->parse_main(first, last, context, rcontext, attr);
}
private:
// Compose attr(where(val(pass(context))))
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
using composed_context_t = x3::context<
attr_context_tag,
Attribute,
x3::context<
where_context_tag,
#ifdef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
std::ranges::subrange<It, Se> const,
#else
boost::iterator_range<It> const,
#endif
x3::context<
rule_val_context_tag,
RContext,
x3::context<
parse_pass_context_tag,
bool,
Context
>
>
>
>;
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires std::invocable<Action const&, composed_context_t<It, Se, Context, RContext, Attribute> const&>
[[nodiscard]] constexpr bool
call_action(
It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) const noexcept(false) // construction of `subrange` is never noexcept as per the standard
{
#ifdef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
using where_range_t = std::ranges::subrange<It, Se>;
#else
using where_range_t = boost::iterator_range<It>;
#endif
static_assert(
std::is_void_v<std::invoke_result_t<Action const&, composed_context_t<It, Se, Context, RContext, Attribute> const&>>,
"Semantic action should not return value. Check your function signature."
);
bool pass = true;
auto const pass_context = x3::make_context<parse_pass_context_tag>(pass, context);
auto const val_context = x3::make_context<rule_val_context_tag>(rcontext, pass_context);
// TODO: Provide some trait to detect whether this is actually needed for
// each semantic actions.
//
// Although this can be assumed to be eliminated in optimized code,
// this still may introduce compile time overhead (and also runtime
// overhead, as constructing `subrange` is never noexcept).
where_range_t const where_rng(first, last);
auto const where_context = x3::make_context<where_context_tag>(where_rng, val_context);
auto const attr_context = x3::make_context<attr_context_tag>(attr, where_context);
// Sanity check (internal check to detect implementation divergence)
static_assert(std::same_as<
std::remove_cvref_t<decltype(attr_context)>,
composed_context_t<It, Se, Context, RContext, Attribute>
>);
this->f(attr_context);
auto action_context = make_context<parse_pass_context_tag>(pass, context);
call(f, first, last, action_context, rcontext, attr);
return pass;
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires (!std::invocable<Action const&, composed_context_t<It, Se, Context, RContext, Attribute> const&>)
[[nodiscard]] constexpr bool
call_action(
It&, Se const&,
Context const&, RContext&, Attribute&
) const noexcept(std::is_nothrow_invocable_v<Action const&>)
template <typename Iterator, typename Context
, typename RuleContext, typename Attribute>
bool parse_main(Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, Attribute& attr) const
{
// Explicitly make this hard error instead of emitting "no matching overload".
// This provides much more human-friendly errors.
static_assert(
std::invocable<Action const&>,
"Neither `f(ctx)` nor `f()` is well-formed for your semantic action. "
"Check your function signature. Note that some functors might need "
"`const` qualifier to satisfy the constraints."
);
static_assert(
std::is_void_v<std::invoke_result_t<Action const&>>,
"Semantic action should not return value. Check your function signature."
);
this->f();
return true;
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse_main(
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) const noexcept(
std::is_copy_assignable_v<It> &&
is_nothrow_parsable_v<Subject, It, Se, Context, RContext, Attribute> &&
noexcept(this->call_action(first, last, context, rcontext, attr))
)
{
It const saved_first = first;
Iterator save = first;
if (this->subject.parse(first, last, context, rcontext, attr))
{
if (this->call_action(first, last, context, rcontext, attr))
{
if (call_action(first, last, context, rcontext, attr))
return true;
}
// reset iterators if semantic action failed the match
// retrospectively
first = saved_first;
first = save;
}
return false;
}
// attr==raw_attribute_type, action wants iterator_range (see raw.hpp)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext>
[[nodiscard]] constexpr bool
parse_main(
It& first, Se const& last, Context const& context, RContext& rcontext, raw_attribute_type&
) const noexcept(false) // construction of `subrange` is never noexcept as per the standard
template <typename Iterator, typename Context, typename RuleContext>
bool parse_main(Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, raw_attribute_type&) const
{
#ifdef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
std::ranges::subrange<It, Se> rng;
#else
boost::iterator_range<It> rng;
#endif
boost::iterator_range<Iterator> rng;
// synthesize the attribute since one is not supplied
return this->parse_main(first, last, context, rcontext, rng);
return parse_main(first, last, context, rcontext, rng);
}
// attr==unused, action wants attribute
template <typename Iterator, typename Context, typename RuleContext>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, unused_type) const
{
typedef typename
traits::attribute_of<action<Subject, Action>, Context>::type
attribute_type;
// synthesize the attribute since one is not supplied
attribute_type attribute{};
return parse_main(first, last, context, rcontext, attribute);
}
// main parse function
template <typename Iterator, typename Context
, typename RuleContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, Attribute& attr) const
{
return parse_main(first, last, context, rcontext, attr);
}
Action f;
};
template <X3Subject Subject, typename Action>
[[nodiscard, deprecated(
"Use `operator[]` instead. The symbol `/` normally means \"ordered choice\" "
"in PEG, and is irrelevant to semantic actions. Furthermore, using C++'s "
"`operator/` for this purpose may introduce surprising behavior when it's "
"mixed with ordinary PEG operators, for instance, the unary `operator+`, "
"due to precedence."
)]]
constexpr action<as_parser_plain_t<Subject>, std::remove_cvref_t<Action>>
operator/(Subject&& p, Action&& f)
noexcept(
is_parser_nothrow_castable_v<Subject> &&
std::is_nothrow_constructible_v<
action<as_parser_plain_t<Subject>, std::remove_cvref_t<Action>>,
as_parser_t<Subject>, Action
>
)
template <typename P, typename Action>
constexpr action<typename extension::as_parser<P>::value_type, Action>
operator/(P const& p, Action f)
{
return { as_parser(std::forward<Subject>(p)), std::forward<Action>(f) };
return { as_parser(p), f };
}
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,38 +7,70 @@
#if !defined(BOOST_SPIRIT_X3_CALL_CONTEXT_MAY_26_2014_0234PM)
#define BOOST_SPIRIT_X3_CALL_CONTEXT_MAY_26_2014_0234PM
#include <type_traits>
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/utility/is_callable.hpp>
#include <boost/range/iterator_range_core.hpp>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
struct parse_pass_context_tag; // _pass
struct rule_val_context_tag; // _val
struct where_context_tag; // _where
struct attr_context_tag; // _attr
////////////////////////////////////////////////////////////////////////////
struct rule_val_context_tag;
template <typename Context>
[[nodiscard]] constexpr bool& _pass(Context const& context) noexcept
{
return x3::get<parse_pass_context_tag>(context);
}
template <typename Context>
[[nodiscard]] constexpr auto&& _val(Context const& context) noexcept
inline decltype(auto) _val(Context const& context)
{
return x3::get<rule_val_context_tag>(context);
}
////////////////////////////////////////////////////////////////////////////
struct where_context_tag;
template <typename Context>
[[nodiscard]] constexpr auto&& _where(Context const& context) noexcept
inline decltype(auto) _where(Context const& context)
{
return x3::get<where_context_tag>(context);
}
////////////////////////////////////////////////////////////////////////////
struct attr_context_tag;
template <typename Context>
[[nodiscard]] constexpr auto&& _attr(Context const& context) noexcept
inline decltype(auto) _attr(Context const& context)
{
return x3::get<attr_context_tag>(context);
}
} // boost::spirit::x3
////////////////////////////////////////////////////////////////////////////
namespace detail
{
template <typename F, typename Context>
auto call(F f, Context const& context, mpl::true_)
{
return f(context);
}
template <typename F, typename Context>
auto call(F f, Context const& /* context */, mpl::false_)
{
return f();
}
}
template <
typename F, typename Iterator
, typename Context, typename RuleContext, typename Attribute>
auto call(
F f, Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, Attribute& attr)
{
boost::iterator_range<Iterator> rng(first, last);
auto val_context = make_context<rule_val_context_tag>(rcontext, context);
auto where_context = make_context<where_context_tag>(rng, val_context);
auto attr_context = make_context<attr_context_tag>(attr, where_context);
return detail::call(f, attr_context, is_callable<F(decltype(attr_context) const&)>());
}
}}}
#endif

View File

@@ -1,45 +0,0 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CORE_CONFIG_HPP
#define BOOST_SPIRIT_X3_CORE_CONFIG_HPP
#include <boost/config.hpp>
#include <cstddef>
#if _MSC_VER
# include <CppCoreCheck/Warnings.h>
# pragma warning(default: CPPCORECHECK_LIFETIME_WARNINGS)
#endif
// <https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/#c++20-[[no_unique_address]]>
#if _MSC_VER && _MSC_VER < 1929 // VS 2019 v16.9 or before
# error "Too old MSVC version; we don't support this because it leads to ODR violation regarding the existence of [[(msvc::)no_unique_address]]"
#endif
#if _MSC_VER && __INTELLISENSE__ // Memory Layout view shows wrong layout without this workaround
# define BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS [[msvc::no_unique_address, no_unique_address]]
#elif _MSC_VER // normal MSVC
# define BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#else // other compilers
# define BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS [[no_unique_address]]
#endif
#ifndef BOOST_SPIRIT_X3_LIFETIMEBOUND
# if defined(__clang__)
# define BOOST_SPIRIT_X3_LIFETIMEBOUND [[clang::lifetimebound]]
# elif defined(_MSC_VER)
# define BOOST_SPIRIT_X3_LIFETIMEBOUND [[msvc::lifetimebound]]
# else
# define BOOST_SPIRIT_X3_LIFETIMEBOUND
# endif
#endif
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,6 +7,8 @@
#if !defined(BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM)
#define BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM
#include <type_traits>
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
#include <boost/spirit/home/x3/support/traits/pseudo_attribute.hpp>
@@ -15,23 +16,14 @@
#include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
#include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/mpl/and.hpp>
#include <boost/fusion/include/at_key.hpp>
#include <boost/fusion/include/front.hpp>
#include <boost/fusion/include/back.hpp>
// TODO: remove Boost.Variant usage
#include <boost/variant/variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <iterator> // for std::make_move_iterator
#include <ranges>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3::detail
namespace boost { namespace spirit { namespace x3 { namespace detail
{
template <typename Attribute, typename Value>
struct saver_visitor;
@@ -41,265 +33,277 @@ namespace boost::spirit::x3::detail
struct save_to_assoc_attr
{
template <typename Value, typename Attribute>
static constexpr void call(Key const&, Value&& value, Attribute& attr)
noexcept(noexcept(traits::move_to(std::move(value), fusion::at_key<Key>(attr))))
static void call(const Key, Value& value, Attribute& attr)
{
static_assert(std::is_rvalue_reference_v<Value&&>);
traits::move_to(std::move(value), fusion::at_key<Key>(attr));
traits::move_to(value, fusion::at_key<Key>(attr));
}
};
// save to associative fusion container where Key
// is variant over possible keys
template <typename... Ts>
struct save_to_assoc_attr<variant<Ts...>>
template <typename ...T>
struct save_to_assoc_attr<variant<T...> >
{
typedef variant<T...> variant_t;
template <typename Value, typename Attribute>
static constexpr void call(variant<Ts...> const& key, Value&& value, Attribute& attr)
static void call(const variant_t key, Value& value, Attribute& attr)
{
static_assert(std::is_rvalue_reference_v<Value&&>);
boost::apply_visitor(saver_visitor<Attribute, Value>(attr, std::move(value)), key);
apply_visitor(saver_visitor<Attribute, Value>(attr, value), key);
}
};
template <typename Attribute, typename Value>
struct saver_visitor : boost::static_visitor<void>
struct saver_visitor : boost::static_visitor<void>
{
constexpr saver_visitor(Attribute& attr, Value&& value) noexcept
: attr(attr)
, value(std::move(value))
{};
saver_visitor(Attribute& attr, Value& value)
: attr(attr), value(value) {};
Attribute& attr;
Value&& value;
Value& value;
template <typename Key>
constexpr void operator()(Key const& key) const
noexcept(noexcept(save_to_assoc_attr<Key>::call(key, std::move(value), attr)))
void operator()(Key) const
{
save_to_assoc_attr<Key>::call(key, std::move(value), attr);
save_to_assoc_attr<Key>::call(Key(), value,attr);
}
};
template <typename Parser, typename Container, typename Context>
struct parser_accepts_container
: traits::is_substitute<traits::attribute_of_t<Parser, Context>, Container>
: traits::is_substitute<
typename traits::attribute_of<Parser, Context>::type
, Container
>
{};
template <typename Parser, typename Container, typename Context>
constexpr bool parser_accepts_container_v = parser_accepts_container<Parser, Container, Context>::value;
template <typename Parser>
struct parse_into_container_base_impl
{
private:
// Parser has attribute (synthesize; Attribute is a container)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires (!parser_accepts_container_v<Parser, Attribute, Context>)
[[nodiscard]] static constexpr bool
call_synthesize(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) // never noexcept (requires container insertion)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
static bool call_synthesize_x(
Parser const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
{
// synthesized attribute needs to be value initialized
using value_type = traits::container_value_t<Attribute>;
value_type val; // default-initialize
using value_type = typename traits::container_value<Attribute>::type;
value_type val{};
static_assert(Parsable<Parser, It, Se, Context, RContext, value_type>);
if (!parser.parse(first, last, context, rcontext, val))
{
return false;
}
// push the parsed value into our attribute
traits::push_back(attr, std::move(val));
traits::push_back(attr, static_cast<value_type&&>(val));
return true;
}
// Parser has attribute (synthesize; Attribute is a container)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires parser_accepts_container_v<Parser, Attribute, Context>
[[nodiscard]] static constexpr bool
call_synthesize(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) noexcept(is_nothrow_parsable_v<Parser, It, Se, Context, RContext, Attribute>)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
static bool call_synthesize_x(
Parser const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
{
static_assert(Parsable<Parser, It, Se, Context, RContext, Attribute>);
return parser.parse(first, last, context, rcontext, attr);
}
// Parser has attribute && it is NOT fusion sequence
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires
traits::has_attribute_v<Parser, Context> &&
(!fusion::traits::is_sequence<Attribute>::value)
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
)
// Parser has attribute (synthesize; Attribute is a container)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
static bool call_synthesize(
Parser const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr)
{
// TODO: reduce call stack while keeping maintainability
return parse_into_container_base_impl::call_synthesize(parser, first, last, context, rcontext, attr);
typedef
parser_accepts_container<Parser, Attribute, Context>
parser_accepts_container;
return call_synthesize_x(parser, first, last, context, rcontext, attr
, parser_accepts_container());
}
// Parser has attribute && it is fusion sequence (NOT associative)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires
traits::has_attribute_v<Parser, Context> &&
fusion::traits::is_sequence<Attribute>::value &&
(!fusion::traits::is_associative<Attribute>::value)
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) noexcept(noexcept(parse_into_container_base_impl::call_synthesize(parser, first, last, context, rcontext, fusion::front(attr))))
// Parser has attribute (synthesize; Attribute is a single element fusion sequence)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
static bool call_synthesize_into_fusion_seq(Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& attr, mpl::false_ /* is_associative */)
{
static_assert(traits::has_size_v<Attribute, 1>, "Expecting a single element fusion sequence");
// TODO: reduce call stack while keeping maintainability
return parse_into_container_base_impl::call_synthesize(parser, first, last, context, rcontext, fusion::front(attr));
static_assert(traits::has_size<Attribute, 1>::value,
"Expecting a single element fusion sequence");
return call_synthesize(parser, first, last, context, rcontext,
fusion::front(attr));
}
// Parser has attribute && it is fusion sequence (associative)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires
traits::has_attribute_v<Parser, Context> &&
fusion::traits::is_sequence<Attribute>::value &&
fusion::traits::is_associative<Attribute>::value
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) // never noexcept (requires container insertion)
// Parser has attribute (synthesize; Attribute is fusion map sequence)
template <typename Iterator, typename Context, typename RContext, typename Attribute>
static bool call_synthesize_into_fusion_seq(
Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& attr, mpl::true_ /*is_associative*/)
{
using attribute_type = traits::attribute_of_t<Parser, Context>;
static_assert(traits::has_size_v<attribute_type, 2>, "To parse directly into fusion map, parser must produce 2 element attr");
using attribute_type = typename traits::attribute_of<Parser, Context>::type;
static_assert(traits::has_size<attribute_type, 2>::value,
"To parse directly into fusion map parser must produce 2 element attr");
attribute_type attr_; // default-initialize
static_assert(Parsable<Parser, It, Se, Context, RContext, attribute_type>);
// use type of first element of attribute as key
using key = typename std::remove_reference<
typename fusion::result_of::front<attribute_type>::type>::type;
attribute_type attr_;
if (!parser.parse(first, last, context, rcontext, attr_))
{
return false;
}
// Use the type of first element of attribute as key
using key = std::remove_reference_t<
typename fusion::result_of::front<attribute_type>::type
>;
save_to_assoc_attr<key>::call(std::move(fusion::front(attr_)), std::move(fusion::back(attr_)), attr);
save_to_assoc_attr<key>::call(fusion::front(attr_), fusion::back(attr_), attr);
return true;
}
// Parser has no attribute (pass unused)
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires (!traits::has_attribute_v<Parser, Context>)
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& /* attr */
) noexcept(is_nothrow_parsable_v<Parser, It, Se, Context, RContext, unused_type>)
template <typename Iterator, typename Context, typename RContext, typename Attribute>
static bool call_synthesize_dispatch_by_seq(Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& attr, mpl::true_ /*is_sequence*/)
{
return call_synthesize_into_fusion_seq(
parser, first, last, context, rcontext, attr
, fusion::traits::is_associative<Attribute>());
}
template <typename Iterator, typename Context, typename RContext, typename Attribute>
static bool call_synthesize_dispatch_by_seq(Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& attr, mpl::false_ /*is_sequence*/)
{
return call_synthesize(parser, first, last, context, rcontext, attr);
}
// Parser has attribute (synthesize)
template <typename Iterator, typename Context, typename RContext, typename Attribute>
static bool call(Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& attr, mpl::true_)
{
return call_synthesize_dispatch_by_seq(parser, first, last, context, rcontext, attr
, fusion::traits::is_sequence<Attribute>());
}
// Parser has no attribute (pass unused)
template <typename Iterator, typename Context, typename RContext, typename Attribute>
static bool call(
Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& /* attr */, mpl::false_)
{
static_assert(Parsable<Parser, It, Se, Context, RContext, unused_type>);
return parser.parse(first, last, context, rcontext, unused);
}
public:
template <typename Iterator, typename Context, typename RContext, typename Attribute>
static bool call(Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& attr)
{
return call(parser, first, last, context, rcontext, attr
, mpl::bool_<traits::has_attribute<Parser, Context>::value>());
}
};
template <typename Parser, typename Context, typename RContext, typename Enable = void>
struct parse_into_container_impl : parse_into_container_base_impl<Parser> {};
template <typename Parser, typename Iterator, typename Container, typename Context>
struct parser_attr_is_substitute_for_container_value
: traits::is_substitute<
typename traits::pseudo_attribute<
Context
, typename traits::attribute_of<Parser, Context>::type
, Iterator
>::type
, typename traits::container_value<Container>::type
>
{};
template <typename Parser, typename Context, typename RContext>
requires traits::handles_container_v<Parser, Context>
struct parse_into_container_impl<Parser, Context, RContext>
struct parse_into_container_impl<Parser, Context, RContext,
typename enable_if<traits::handles_container<Parser, Context>>::type>
{
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
static constexpr bool pass_attibute_as_is = std::disjunction_v<
parser_accepts_container<Parser, Attribute, Context>,
std::negation<traits::is_substitute< // parser attribute is substitute for container value?
traits::pseudo_attribute_t<
Context,
traits::attribute_of_t<Parser, Context>,
It, Se
>,
traits::container_value_t<Attribute>
>>
>;
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
requires (!pass_attibute_as_is<It, Se, Attribute>)
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) noexcept(noexcept(parse_into_container_base_impl<Parser>::call(
parser, first, last, context, rcontext, attr
)))
template <typename Iterator, typename Attribute>
static bool call(
Parser const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
{
return parse_into_container_base_impl<Parser>::call(
parser, first, last, context, rcontext, attr
);
parser, first, last, context, rcontext, attr);
}
template <std::forward_iterator It, std::sentinel_for<It> Se>
requires pass_attibute_as_is<It, Se, unused_type>
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, unused_type
) noexcept(is_nothrow_parsable_v<Parser, It, Se, Context, RContext, unused_type>)
template <typename Iterator>
static bool call(
Parser const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, unused_type attr, mpl::true_)
{
static_assert(Parsable<Parser, It, Se, Context, RContext, unused_type>);
return parser.parse(first, last, context, rcontext, unused);
return parser.parse(first, last, context, rcontext, attr);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
requires pass_attibute_as_is<It, Se, Attribute>
[[nodiscard]] static constexpr bool
call(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) // never noexcept (requires container insertion)
template <typename Iterator, typename Attribute>
static bool call(
Parser const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
{
static_assert(Parsable<Parser, It, Se, Context, RContext, Attribute>);
if (traits::is_empty(attr))
{
return parser.parse(first, last, context, rcontext, attr);
}
Attribute rest;
bool r = parser.parse(first, last, context, rcontext, rest);
if (r)
traits::append(attr, std::make_move_iterator(rest.begin()),
std::make_move_iterator(rest.end()));
return r;
}
Attribute rest; // default-initialize
if (!parser.parse(first, last, context, rcontext, rest))
{
return false;
}
traits::append(
attr,
std::make_move_iterator(std::ranges::begin(rest)),
std::make_move_iterator(std::ranges::end(rest))
);
return true;
template <typename Iterator, typename Attribute>
static bool call(Parser const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr)
{
typedef parser_accepts_container<
Parser, Attribute, Context>
parser_accepts_container;
typedef parser_attr_is_substitute_for_container_value<
Parser, Iterator, Attribute, Context>
parser_attr_is_substitute_for_container_value;
typedef mpl::or_<
parser_accepts_container
, mpl::not_<parser_attr_is_substitute_for_container_value>>
pass_attibute_as_is;
return call(parser, first, last, context, rcontext, attr,
pass_attibute_as_is());
}
};
template <
typename Parser, std::forward_iterator It, std::sentinel_for<It> Se,
typename Context, typename RContext, typename Attribute
>
[[nodiscard]] constexpr bool
parse_into_container(
Parser const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) noexcept(noexcept(parse_into_container_impl<Parser, Context, RContext>::call(
parser, first, last, context, rcontext, attr
)))
template <typename Parser, typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse_into_container(
Parser const& parser
, Iterator& first, Iterator const& last, Context const& context
, RContext& rcontext, Attribute& attr)
{
return parse_into_container_impl<Parser, Context, RContext>::call(
parser, first, last, context, rcontext, attr
);
parser, first, last, context, rcontext, attr);
}
} // boost::spirit::x3::detail
}}}}
#endif

View File

@@ -1,28 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2024-2025 Nana Sakisaka
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_SPIRIT_X3_CORE_ERROR_HANDLER_TYPES_HPP
#define BOOST_SPIRIT_X3_CORE_ERROR_HANDLER_TYPES_HPP
namespace boost::spirit::x3
{
// Enum type used in `on_error`.
enum class error_handler_result
{
fail,
retry,
accept,
rethrow, // see BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE for alternative behaviors
};
// Note for X3 developers:
// You must at least sync the implementation of `rule_parser` and `guard`
// when you modify the semantics of error handlers.
} // boost::spirit::x3
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,173 +8,80 @@
#define BOOST_SPIRIT_X3_PARSE_APRIL_16_2006_0442PM
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/parse_result.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/iterator/iterator_concepts.hpp>
#include <optional>
#include <iterator>
#include <ranges>
#include <string_view>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, typename Attribute>
[[nodiscard]] constexpr bool
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser, typename Attribute>
inline bool
parse_main(
It& first,
Se last,
Parser&& p,
Attribute& attr
)
Iterator& first
, Iterator last
, Parser const& p
, Attribute& attr)
{
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, unused_type, unused_type, Attribute>);
return as_parser(std::forward<Parser>(p)).parse(first, last, unused, unused, attr);
}
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, typename Attribute>
[[nodiscard]] constexpr bool
parse(
It& first,
Se last,
Parser&& p,
Attribute& attr
)
{
return x3::parse_main(first, last, std::forward<Parser>(p), attr);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, typename Attribute>
[[nodiscard]] constexpr bool
parse(
It const& first_,
Se last,
Parser&& p,
Attribute& attr
)
{
It first = first_;
return x3::parse_main(first, last, std::forward<Parser>(p), attr);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser>
[[nodiscard]] constexpr bool
parse(
It& first,
Se last,
Parser&& p
)
{
return x3::parse_main(first, last, std::forward<Parser>(p), unused);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser>
[[nodiscard]] constexpr bool
parse(
It const& first_,
Se last,
Parser&& p
)
{
It first = first_;
return x3::parse_main(first, last, std::forward<Parser>(p), unused);
// If you get an error no matching function for call to 'as_parser'
// here, then p is not a parser or there is no suitable conversion
// from p to a parser.
return as_parser(p).parse(first, last, unused, unused, attr);
}
///////////////////////////////////////////////////////////////////////////
template <std::ranges::forward_range R, X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser, typename Attribute>
[[nodiscard]] constexpr parse_result_for<R>
parse_main(
R& range,
Parser&& p,
Attribute& attr
)
{
using It = std::ranges::iterator_t<R>;
using Se = std::ranges::sentinel_t<R>;
std::optional<x3::expectation_failure<It>> expect_failure;
auto failure_ctx = x3::make_context<expectation_failure_tag>(expect_failure);
using Context = decltype(failure_ctx);
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
It first = std::ranges::begin(range);
Se last = std::ranges::end(range);
bool const ok = as_parser(std::forward<Parser>(p)).parse(first, last, failure_ctx, unused, attr);
return parse_result_for<R>{
.ok = ok,
.expect_failure = std::move(expect_failure),
.remainder = {std::move(first), std::move(last)}
};
}
template <std::ranges::forward_range R, X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser, typename Attribute>
constexpr void
parse_main(
parse_result_for<R>& res
, R& range
, Parser&& p
template <typename Iterator, typename Parser, typename Attribute>
inline bool
parse(
Iterator& first
, Iterator last
, Parser const& p
, Attribute& attr)
{
using It = std::ranges::iterator_t<R>;
using Se = std::ranges::sentinel_t<R>;
res.expect_failure.reset();
auto failure_ctx = x3::make_context<expectation_failure_tag>(res.expect_failure);
using Context = decltype(failure_ctx);
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
It first = std::ranges::begin(range);
Se last = std::ranges::end(range);
res.ok = as_parser(std::forward<Parser>(p)).parse(first, last, failure_ctx, unused, attr);
res.remainder = {std::move(first), std::move(last)};
return parse_main(first, last, p, attr);
}
template <std::ranges::forward_range R, X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser, typename Attribute>
[[nodiscard]] constexpr parse_result_for<R>
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser, typename Attribute>
inline bool
parse(
R& range
, Parser&& p
Iterator const& first_
, Iterator last
, Parser const& p
, Attribute& attr)
{
return x3::parse_main(range, std::forward<Parser>(p), attr);
Iterator first = first_;
return parse_main(first, last, p, attr);
}
template <std::ranges::forward_range R, X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser>
[[nodiscard]] constexpr parse_result_for<R>
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser>
inline bool
parse(
R& range
, Parser&& p)
Iterator& first
, Iterator last
, Parser const& p)
{
return x3::parse_main(range, std::forward<Parser>(p), unused);
return parse_main(first, last, p, unused);
}
template <std::ranges::forward_range R, X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser, typename Attribute>
constexpr void
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser>
inline bool
parse(
parse_result_for<R>& res,
R& range,
Parser&& p,
Attribute& attr
)
Iterator const& first_
, Iterator last
, Parser const& p)
{
return x3::parse_main(res, range, std::forward<Parser>(p), attr);
}
template <std::ranges::forward_range R, X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser>
constexpr void
parse(
parse_result_for<R>& res,
R& range,
Parser&& p
)
{
return x3::parse_main(res, range, std::forward<Parser>(p), unused);
Iterator first = first_;
return parse_main(first, last, p, unused);
}
///////////////////////////////////////////////////////////////////////////
@@ -185,306 +91,101 @@ namespace boost::spirit::x3
dont_post_skip // inhibit post-skipping in phrase_parse()
};
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, X3Parser<It, Se> Skipper, typename Attribute>
[[nodiscard]] constexpr bool
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser, typename Skipper, typename Attribute>
inline bool
phrase_parse_main(
It& first,
Se last,
Parser&& p,
Skipper&& s,
Attribute& attr,
skip_flag post_skip = skip_flag::post_skip
)
Iterator& first
, Iterator last
, Parser const& p
, Skipper const& s
, Attribute& attr
, skip_flag post_skip = skip_flag::post_skip)
{
auto skipper_ctx = x3::make_context<skipper_tag>(as_parser(std::forward<Skipper>(s)));
using Context = decltype(skipper_ctx);
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
// Make sure the iterator is at least a readable forward traversal iterator.
// If you got a compilation error here, then you are using a weaker iterator
// while calling this function, you need to supply a readable forward traversal
// iterator instead.
BOOST_CONCEPT_ASSERT((boost_concepts::ReadableIteratorConcept<Iterator>));
BOOST_CONCEPT_ASSERT((boost_concepts::ForwardTraversalConcept<Iterator>));
static_assert(!std::is_same<Skipper, unused_type>::value,
"Error! Skipper cannot be unused_type.");
bool const ok = as_parser(std::forward<Parser>(p)).parse(first, last, skipper_ctx, unused, attr);
// If you get an error no matching function for call to 'as_parser'
// here, for either p or s, then p or s is not a parser or there is
// no suitable conversion from p to a parser.
auto skipper_ctx = make_context<skipper_tag>(as_parser(s));
bool r = as_parser(p).parse(first, last, skipper_ctx, unused, attr);
if (post_skip == skip_flag::post_skip)
{
x3::skip_over(first, last, skipper_ctx);
}
return ok;
}
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, X3Parser<It, Se> Skipper, typename Attribute>
[[nodiscard]] constexpr bool
phrase_parse(
It& first,
Se last,
Parser&& p,
Skipper&& s,
Attribute& attr,
skip_flag post_skip = skip_flag::post_skip
)
{
return x3::phrase_parse_main(first, last, std::forward<Parser>(p), std::forward<Skipper>(s), attr, post_skip);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, X3Parser<It, Se> Skipper, typename Attribute>
[[nodiscard]] constexpr bool
phrase_parse(
It const& first_,
Se last,
Parser&& p,
Skipper&& s,
Attribute& attr,
skip_flag post_skip = skip_flag::post_skip
)
{
It first = first_;
return x3::phrase_parse_main(first, last, std::forward<Parser>(p), std::forward<Skipper>(s), attr, post_skip);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, X3Parser<It, Se> Skipper>
[[nodiscard]] constexpr bool
phrase_parse(
It& first,
Se last,
Parser&& p,
Skipper&& s,
skip_flag post_skip = skip_flag::post_skip
)
{
return x3::phrase_parse_main(first, last, std::forward<Parser>(p), std::forward<Skipper>(s), unused, post_skip);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, X3Parser<It, Se> Parser, X3Parser<It, Se> Skipper>
[[nodiscard]] constexpr bool
phrase_parse(
It const& first_,
Se last,
Parser&& p,
Skipper&& s,
skip_flag post_skip = skip_flag::post_skip
)
{
It first = first_;
return x3::phrase_parse_main(first, last, std::forward<Parser>(p), std::forward<Skipper>(s), unused, post_skip);
return r;
}
///////////////////////////////////////////////////////////////////////////
template <
std::ranges::forward_range R,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Skipper,
typename Attribute
>
[[nodiscard]] constexpr parse_result_for<R>
phrase_parse_main(
R& range,
Parser&& p,
Skipper&& s,
Attribute& attr,
skip_flag post_skip = skip_flag::post_skip
)
{
using It = std::ranges::iterator_t<R>;
using Se = std::ranges::sentinel_t<R>;
auto skipper_ctx = x3::make_context<skipper_tag>(as_parser(std::forward<Skipper>(s)));
std::optional<x3::expectation_failure<It>> expect_failure;
auto ctx = x3::make_context<expectation_failure_tag>(expect_failure, skipper_ctx);
using Context = decltype(ctx);
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
It first = std::ranges::begin(range);
Se last = std::ranges::end(range);
bool ok = as_parser(std::forward<Parser>(p)).parse(first, last, ctx, unused, attr);
if (post_skip == skip_flag::post_skip)
{
x3::skip_over(first, last, ctx);
if (expect_failure) ok = false;
}
return parse_result_for<R>{
.ok = ok,
.expect_failure = std::move(expect_failure),
.remainder = {std::move(first), std::move(last)}
};
}
template <
std::ranges::forward_range R,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Skipper,
typename Attribute
>
constexpr void
phrase_parse_main(
parse_result_for<R>& res,
R& range,
Parser&& p,
Skipper&& s,
Attribute& attr,
skip_flag post_skip = skip_flag::post_skip
)
{
using It = std::ranges::iterator_t<R>;
using Se = std::ranges::sentinel_t<R>;
auto skipper_ctx = x3::make_context<skipper_tag>(as_parser(std::forward<Skipper>(s)));
res.expect_failure.reset();
auto ctx = x3::make_context<expectation_failure_tag>(res.expect_failure, skipper_ctx);
using Context = decltype(ctx);
static_assert(Parsable<as_parser_plain_t<Parser>, It, Se, Context, unused_type, Attribute>);
It first = std::ranges::begin(range);
Se last = std::ranges::end(range);
res.ok = as_parser(std::forward<Parser>(p)).parse(first, last, ctx, unused, attr);
if (post_skip == skip_flag::post_skip)
{
x3::skip_over(first, last, ctx);
if (res.expect_failure) res.ok = false;
}
res.remainder = {std::move(first), std::move(last)};
}
template <
std::ranges::forward_range R,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Skipper,
typename Attribute
>
[[nodiscard]] constexpr parse_result_for<R>
template <typename Iterator, typename Parser, typename Skipper, typename Attribute>
inline bool
phrase_parse(
R& range,
Parser&& p,
Skipper&& s,
Attribute& attr,
skip_flag post_skip = skip_flag::post_skip
)
Iterator& first
, Iterator last
, Parser const& p
, Skipper const& s
, Attribute& attr
, skip_flag post_skip = skip_flag::post_skip)
{
return x3::phrase_parse_main(range, std::forward<Parser>(p), std::forward<Skipper>(s), attr, post_skip);
return phrase_parse_main(first, last, p, s, attr, post_skip);
}
template <
std::ranges::forward_range R,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Skipper,
typename Attribute
>
[[nodiscard]] constexpr parse_result_for<R>
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser, typename Skipper, typename Attribute>
inline bool
phrase_parse(
R& range,
Parser&& p,
Skipper&& s,
skip_flag post_skip = skip_flag::post_skip
)
Iterator const& first_
, Iterator last
, Parser const& p
, Skipper const& s
, Attribute& attr
, skip_flag post_skip = skip_flag::post_skip)
{
return x3::phrase_parse_main(range, std::forward<Parser>(p), std::forward<Skipper>(s), unused, post_skip);
Iterator first = first_;
return phrase_parse_main(first, last, p, s, attr, post_skip);
}
template <
std::ranges::forward_range R,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Skipper,
typename Attribute
>
constexpr void
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser, typename Skipper>
inline bool
phrase_parse(
parse_result_for<R>& res,
R& range,
Parser&& p,
Skipper&& s,
Attribute& attr,
skip_flag post_skip = skip_flag::post_skip
)
Iterator& first
, Iterator last
, Parser const& p
, Skipper const& s
, skip_flag post_skip = skip_flag::post_skip)
{
return x3::phrase_parse_main(res, range, std::forward<Parser>(p), std::forward<Skipper>(s), attr, post_skip);
return phrase_parse_main(first, last, p, s, unused, post_skip);
}
template <
std::ranges::forward_range R,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Parser,
X3Parser<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>> Skipper,
typename Attribute
>
constexpr void
///////////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Parser, typename Skipper>
inline bool
phrase_parse(
parse_result_for<R>& res,
R& range,
Parser&& p,
Skipper&& s,
skip_flag post_skip = skip_flag::post_skip
)
Iterator const& first_
, Iterator last
, Parser const& p
, Skipper const& s
, skip_flag post_skip = skip_flag::post_skip)
{
return x3::phrase_parse_main(res, range, std::forward<Parser>(p), std::forward<Skipper>(s), unused, post_skip);
Iterator first = first_;
return phrase_parse_main(first, last, p, s, unused, post_skip);
}
template <typename Skipper, typename ItOrRange, typename Se = void>
struct phrase_parse_context;
template <typename Skipper, typename ItOrRange, typename Se = void>
using phrase_parse_context_t = typename phrase_parse_context<Skipper, ItOrRange, Se>::type;
template <typename Skipper, std::forward_iterator It, class Se>
struct phrase_parse_context<Skipper, It, Se>
///////////////////////////////////////////////////////////////////////////
template <typename Skipper>
struct phrase_parse_context
{
using iterator_t = It;
using sentinel_t = std::conditional_t<std::is_void_v<Se>, It, Se>;
static_assert(X3Parser<Skipper, It, sentinel_t>);
using skipper_ctx_type = decltype(x3::make_context<skipper_tag>(as_parser(std::declval<Skipper const&>())));
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
using type = skipper_ctx_type;
#else
using type = decltype(x3::make_context<expectation_failure_tag>(
std::declval<std::optional<expectation_failure<It>>&>(),
std::declval<skipper_ctx_type const&>()
));
#endif
typedef decltype(
make_context<skipper_tag>(as_parser(std::declval<Skipper>())))
type;
};
template <typename Skipper, std::ranges::forward_range R>
struct phrase_parse_context<Skipper, R>
{
using iterator_t = std::ranges::iterator_t<R>;
using sentinel_t = std::ranges::sentinel_t<R>;
static_assert(X3Parser<Skipper, iterator_t, sentinel_t>);
using skipper_ctx_type = decltype(x3::make_context<skipper_tag>(as_parser(std::declval<Skipper const&>())));
using type = decltype(x3::make_context<expectation_failure_tag>(
std::declval<std::optional<expectation_failure<iterator_t>>&>(),
std::declval<skipper_ctx_type const&>()
));
};
template <typename ItOrRange, typename Se = void>
struct parse_context;
template <typename ItOrRange, typename Se = void>
using parse_context_t = typename parse_context<ItOrRange, Se>::type;
template <std::forward_iterator It>
struct parse_context<It>
{
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
using type = unused_type;
#else
using type = decltype(x3::make_context<expectation_failure_tag>(
std::declval<std::optional<expectation_failure<It>>&>()
));
#endif
};
template <std::ranges::forward_range R>
struct parse_context<R>
{
using type = decltype(x3::make_context<expectation_failure_tag>(
std::declval<std::optional<expectation_failure<std::ranges::iterator_t<R>>>&>()
));
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,90 +0,0 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_CORE_PARSE_RESULT_HPP
#define BOOST_SPIRIT_X3_CORE_PARSE_RESULT_HPP
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <optional>
#include <iterator>
#include <ranges>
#include <string_view>
#include <type_traits>
namespace boost::spirit::x3
{
template <std::forward_iterator It, std::sentinel_for<It> Se = It>
struct parse_result
{
static_assert(
BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE == 0,
"Using this class requires `#define BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE 0`"
);
using iterator_type = It;
using sentinel_type = Se;
// Strictly equivalent to the logical conjunction of the return
// values of the `.parse()` functions of all underlying parsers.
bool ok = false;
// Represents the failure of `x3::expect[p]` and `a > b`.
// Has value if and only if `ok` is `false` and any of
// the underlying parsers have encountered expectation
// failure.
std::optional<expectation_failure<It>> expect_failure;
// Represents the remaining subrange of the input, after
// applications of all (partially) successful attempts on
// underlying parsers.
std::ranges::subrange<It, Se> remainder;
// Convenient accessor, returns the string view of `remainder`.
[[nodiscard]] constexpr std::basic_string_view<std::iter_value_t<It>>
remainder_str() const
requires requires {
typename std::basic_string_view<std::iter_value_t<It>>;
requires std::is_constructible_v<std::basic_string_view<std::iter_value_t<It>>, std::ranges::subrange<It, Se> const&>;
}
{
return std::basic_string_view<std::iter_value_t<It>>{remainder};
}
[[nodiscard]] constexpr bool completed() const noexcept
{
// Cases:
// (1) The input was empty, and
// (1-a) The grammar accepts empty input and succeeded => remainder.empty() && ok
// (1-b) The grammar rejects empty input and failed => remainder.empty() && !ok
// (2) The input was NOT empty, and
// (2-a) The grammar comsumed all input and succeeded => remainder.empty() && ok
// (2-b) The grammar consumed some input and (partially) succeeded => !remainder.empty() && ok
// (2-c) The grammar consumed all input and failed (possibly via semantic action) => remainder.empty() && !ok
// (2-d) The grammar consumed some input and failed => !remainder.empty() && !ok
// `completed()` is `true` if and only if the parse result is
// either 1-a or 2-a; `false` otherwise. Note that 2-b is
// intentionally considered out of scope.
//
// This definition eliminates the need to double-check both
// the resulting `bool` and iterators on the user's part,
// which had been the long-standing burden of Spirit since
// the Qi era.
return ok && remainder.empty();
}
[[nodiscard]] constexpr explicit operator bool() const noexcept
{
return this->completed();
}
};
template <std::ranges::forward_range R>
using parse_result_for = parse_result<std::ranges::iterator_t<R>, std::ranges::sentinel_t<R>>;
} // boost::spirit::x3
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Agustin Berge
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,22 +8,24 @@
#if !defined(BOOST_SPIRIT_X3_PARSER_OCTOBER_16_2008_0254PM)
#define BOOST_SPIRIT_X3_PARSER_OCTOBER_16_2008_0254PM
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/declval.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/assert.hpp>
#include <iterator>
#include <string>
#include <type_traits>
#include <concepts>
#include <utility>
#if !defined(BOOST_SPIRIT_X3_NO_RTTI)
#include <typeinfo>
#endif
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Subject, typename Action>
struct action;
@@ -32,74 +33,32 @@ namespace boost::spirit::x3
template <typename Subject, typename Handler>
struct guard;
namespace detail
{
struct parser_base {};
struct parser_id;
} // detail
struct parser_base {};
struct parser_id;
template <typename Derived>
struct parser : detail::parser_base
struct parser : parser_base
{
static_assert(!std::is_reference_v<Derived>);
using derived_type = Derived;
typedef Derived derived_type;
static bool const handles_container = false;
static bool const is_pass_through_unary = false;
static bool const has_action = false;
static constexpr bool handles_container = false;
static constexpr bool is_pass_through_unary = false;
static constexpr bool has_action = false;
[[nodiscard]] constexpr Derived& derived() & noexcept
constexpr Derived const& derived() const
{
return static_cast<Derived&>(*this);
return *static_cast<Derived const*>(this);
}
[[nodiscard]] constexpr Derived const& derived() const& noexcept
template <typename Action>
constexpr action<Derived, Action> operator[](Action f) const
{
return static_cast<Derived const&>(*this);
return { this->derived(), f };
}
[[nodiscard]] constexpr Derived&& derived() && noexcept
template <typename Handler>
constexpr guard<Derived, Handler> on_error(Handler f) const
{
return static_cast<Derived&&>(*this);
}
[[nodiscard]] constexpr Derived const&& derived() const&& noexcept
{
return static_cast<Derived const&&>(*this);
}
template <typename Self, typename Action>
requires std::is_constructible_v<
action<Derived, std::remove_cvref_t<Action>>,
decltype(std::declval<Self>().derived()),
Action
>
[[nodiscard]] constexpr action<Derived, std::remove_cvref_t<Action>>
operator[](this Self&& self, Action&& f)
noexcept(std::is_nothrow_constructible_v<
action<Derived, std::remove_cvref_t<Action>>,
decltype(std::forward<Self>(self).derived()),
Action
>)
{
return { std::forward<Self>(self).derived(), std::forward<Action>(f) };
}
template <typename Self, typename Handler>
requires std::is_constructible_v<
guard<Derived, std::remove_cvref_t<Handler>>,
decltype(std::declval<Self>().derived()),
Handler
>
[[nodiscard]] constexpr guard<Derived, std::remove_cvref_t<Handler>>
on_error(this Self&& self, Handler&& f)
noexcept(std::is_nothrow_constructible_v<
guard<Derived, std::remove_cvref_t<Handler>>,
decltype(std::forward<Self>(self).derived()),
Handler
>)
{
return { std::forward<Self>(self).derived(), std::forward<Handler>(f) };
return { this->derived(), f };
}
};
@@ -109,20 +68,14 @@ namespace boost::spirit::x3
template <typename Subject, typename Derived>
struct unary_parser : parser<Derived>
{
using category = unary_category;
using subject_type = Subject;
static constexpr bool has_action = Subject::has_action;
typedef unary_category category;
typedef Subject subject_type;
static bool const has_action = Subject::has_action;
template <typename SubjectT>
requires
(!std::is_same_v<std::remove_cvref_t<SubjectT>, unary_parser>) &&
std::is_constructible_v<Subject, SubjectT>
constexpr unary_parser(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: subject(std::forward<SubjectT>(subject))
{}
constexpr unary_parser(Subject const& subject)
: subject(subject) {}
[[nodiscard]] constexpr unary_parser const& get_unary() const noexcept { return *this; }
unary_parser const& get_unary() const { return *this; }
Subject subject;
};
@@ -130,375 +83,139 @@ namespace boost::spirit::x3
template <typename Left, typename Right, typename Derived>
struct binary_parser : parser<Derived>
{
using category = binary_category;
using left_type = Left;
using right_type = Right;
static constexpr bool has_action = left_type::has_action || right_type::has_action;
typedef binary_category category;
typedef Left left_type;
typedef Right right_type;
static bool const has_action =
left_type::has_action || right_type::has_action;
template <typename LeftT, typename RightT>
requires std::is_constructible_v<Left, LeftT> && std::is_constructible_v<Right, RightT>
constexpr binary_parser(LeftT&& left, RightT&& right)
noexcept(std::is_nothrow_constructible_v<Left, LeftT> && std::is_nothrow_constructible_v<Right, RightT>)
: left(std::forward<LeftT>(left))
, right(std::forward<RightT>(right))
{}
constexpr binary_parser(Left const& left, Right const& right)
: left(left), right(right) {}
[[nodiscard]] constexpr binary_parser const& get_binary() const noexcept { return *this; }
binary_parser const& get_binary() const { return *this; }
Left left;
Right right;
};
///////////////////////////////////////////////////////////////////////////
// as_parser: convert a type, T, into a parser.
///////////////////////////////////////////////////////////////////////////
namespace extension
{
// In short: if you want to customize the `as_parser(p)` behavior, just
// specialize `x3::extension::as_parser` for your class.
//
// Older versions of X3 specified the signature `as_spirit_parser(p)` to be
// used for the ADL adaptation of user-defined types. However, many parts in
// X3 were instead using ADL of the form `as_parser(p)` to dispatch any types
// in the first place. This makes it impossible for the control to reach the
// `as_spirit_parser(p)` call if any user-defined `as_parser(p)` is *more
// constrained* than `as_spirit_parser(p)`.
//
// In other words, the old signature `as_spirit_parser(p)` has never been
// implemented correctly since its very first introduction to X3.
//
// Additionally, GitHub fulltext search shows that there exists zero usage of
// `as_spirit_parser` except for the unmaintained blog post written by the
// original inventor. Therefore, we simply removed the feature.
//
// Furthermore, the current maintainer of X3 believes there are no practical
// use cases of ADL adaptation on user-defined types. As such, we make the
// `x3::as_parser` (not to be confused with `x3::extension::as_parser`) to
// model a C++20-ish CPO to inhibit undesired ADL in the first place.
namespace detail
{
namespace as_parser_guard
{
void as_spirit_parser(...);
template <typename T>
struct as_parser; // not defined
template<typename T, typename R =
decltype(as_spirit_parser(boost::declval<T const&>()))>
struct deduce_as_parser
{
typedef R type;
typedef typename
boost::remove_cv<
typename boost::remove_reference<R>::type
>::type
value_type;
static type call(T const& v)
{
return as_spirit_parser(v);
}
};
template<typename T>
struct deduce_as_parser<T, void>
{};
}
using as_parser_guard::deduce_as_parser;
}
template <typename T, typename Enable = void>
struct as_parser : detail::deduce_as_parser<T> {};
template <>
struct as_parser<unused_type>
{
using value_type [[deprecated("Use x3::as_parser_plain_t")]] = unused_type;
template <typename T>
[[nodiscard]] static constexpr auto&& call(T&& unused_) noexcept
typedef unused_type type;
typedef unused_type value_type;
static constexpr type call(unused_type)
{
return std::forward<T>(unused_);
return unused;
}
};
template <typename Derived>
requires std::is_base_of_v<detail::parser_base, std::remove_cvref_t<Derived>>
struct as_parser<Derived>
struct as_parser<Derived
, typename enable_if<is_base_of<parser_base, Derived>>::type>
{
using value_type [[deprecated("Use x3::as_parser_plain_t")]] = std::remove_cvref_t<Derived>;
template <typename T>
[[nodiscard]] static constexpr auto&& call(T&& p) noexcept
typedef Derived const& type;
typedef Derived value_type;
static constexpr type call(Derived const& p)
{
return std::forward<T>(p);
return p;
}
};
template <typename Derived>
struct as_parser<parser<Derived>>
{
using value_type [[deprecated("Use x3::as_parser_plain_t")]] = Derived;
template <typename T>
[[nodiscard]] static constexpr auto&& call(T&& p) noexcept
typedef Derived const& type;
typedef Derived value_type;
static constexpr type call(parser<Derived> const& p)
{
return std::forward<T>(p).derived();
return p.derived();
}
};
}
namespace detail
template <typename T>
constexpr typename extension::as_parser<T>::type
as_parser(T const& x)
{
struct as_parser_fn
{
template <typename T>
static void operator()(T&&) = delete; // If you reach here, your specialization of `x3::extension::as_parser` has a wrong signature, or the type is simply incompatible.
return extension::as_parser<T>::call(x);
}
// catch-all default fallback
template <typename T>
requires std::is_base_of_v<
parser_base,
std::remove_cvref_t<decltype(extension::as_parser<std::remove_cvref_t<T>>::call(std::declval<T>()))>
>
[[nodiscard]] static constexpr decltype(auto)
operator()(T&& x) noexcept(noexcept(extension::as_parser<std::remove_cvref_t<T>>::call(std::forward<T>(x))))
{
return extension::as_parser<std::remove_cvref_t<T>>::call(std::forward<T>(x));
}
template <typename Derived>
[[nodiscard]] static constexpr auto&&
operator()(parser<Derived>& p) noexcept
{
return p.derived();
}
template <typename Derived>
[[nodiscard]] static constexpr auto&&
operator()(parser<Derived> const& p) noexcept
{
return p.derived();
}
template <typename Derived>
[[nodiscard]] static constexpr auto&&
operator()(parser<Derived>&& p) noexcept
{
return std::move(p).derived();
}
template <typename Derived>
[[nodiscard]] static constexpr auto&&
operator()(parser<Derived> const&& p) noexcept
{
return std::move(p).derived();
}
}; // as_parser_fn
} // detail
inline namespace cpos
template <typename Derived>
constexpr Derived const&
as_parser(parser<Derived> const& p)
{
inline constexpr detail::as_parser_fn as_parser{};
} // cpos
return p.derived();
}
template <typename T>
using as_parser_t = decltype(as_parser(std::declval<T>())); // no ADL
template <typename T>
using as_parser_plain_t = std::remove_cvref_t<as_parser_t<T>>;
// This is a very low level API provided for consistency with
// `is_parser_nothrow_castable`. Most users should use `X3Subject`
// instead.
template <typename T>
struct is_parser_castable : std::bool_constant<
requires {
{ x3::as_parser(std::declval<T>()) };
}
> {};
template <typename T>
constexpr bool is_parser_castable_v = is_parser_castable<T>::value;
// This trait can be used primarily for multi-parameter constructors.
// For example, `a op b` normally requires the below condition to
// become fully noexcept:
// is_parser_nothrow_castable_v<A> &&
// is_parser_nothrow_castable_v<B> &&
// std::is_nothrow_constructible_v<op_parser, as_parser_t<A>, as_parser_t<B>>
template <typename T>
struct is_parser_nothrow_castable : std::bool_constant<
requires {
{ x3::as_parser(std::declval<T>()) } noexcept;
}
> {};
template <typename T>
constexpr bool is_parser_nothrow_castable_v = is_parser_nothrow_castable<T>::value;
// A type that models `X3Subject` can be used in generic directives
// and operators. Note that this concept is iterator-agnostic.
///////////////////////////////////////////////////////////////////////////
// The main what function
//
// For example, let `p` denote an object of `T`. Then, `!p` is a
// well-formed NOT predicate in X3's domain (with "NOT predicate"
// referring to that of the PEG semantics) if and only if `T`
// models `X3Subject`.
template <typename T>
concept X3Subject =
is_parser_castable_v<T> && // `as_parser(t)` is valid?
std::is_base_of_v<detail::parser_base, as_parser_plain_t<T>>;
// Checks whether `Parser(as_parser(t))` is valid.
//
// This trait can be used for checking whether a "Parser" is constructible
// with some arbitrary argument `T`. In our (X3 core) use cases, the `Parser`
// is usually a concrete type (e.g. `some_parser<as_parser_plain_t<Subject>>`)
// whereas the `T` is some user-provided arbitrary type (e.g. `X3Subject Subject`).
//
// This interface can only be used to check whether `Parser`'s single-parameter
// constructor is available. For multi-parameter construction, manually combine
// `is_parser_castable` with `std::is_constructible`.
template <X3Subject Parser, X3Subject T>
struct is_parser_constructible : std::false_type {};
template <X3Subject Parser, X3Subject T>
requires std::is_constructible_v<Parser, as_parser_t<T>>
struct is_parser_constructible<Parser, T> : std::true_type {};
template <X3Subject Parser, X3Subject T>
constexpr bool is_parser_constructible_v = is_parser_constructible<Parser, T>::value;
// Checks whether `Parser(as_parser(t))` is noexcept.
//
// This interface can only be used to check whether `Parser`'s single-parameter
// constructor is available. For multi-parameter construction, manually combine
// `is_parser_nothrow_castable` with `std::is_nothrow_constructible`.
template <X3Subject Parser, X3Subject T>
struct is_parser_nothrow_constructible : std::false_type {};
template <X3Subject Parser, X3Subject T>
requires
is_parser_nothrow_castable_v<T> &&
std::is_nothrow_constructible_v<Parser, as_parser_t<T>>
struct is_parser_nothrow_constructible<Parser, T> : std::true_type {};
template <X3Subject Parser, X3Subject T>
constexpr bool is_parser_nothrow_constructible_v = is_parser_nothrow_constructible<Parser, T>::value;
template <
typename Parser,
typename It, // Don't constrain these; just let `static_assert` be engaged for friendly errors
typename Se,
typename Context,
typename RContext,
typename Attribute
>
struct is_parsable
{
static_assert(X3Subject<Parser>);
static_assert(!std::is_reference_v<It>);
static_assert(std::forward_iterator<It>);
static_assert(std::sentinel_for<Se, It>);
static_assert(!std::is_reference_v<Context>);
static_assert(!std::is_reference_v<RContext>);
static_assert(!std::is_reference_v<Attribute>);
static constexpr bool value = requires(Parser const& p) // mutable parser use case is currently unknown
{
{
p.parse(
std::declval<It&>(), // first
std::declval<Se>(), // last
std::declval<Context const&>(), // context
std::declval<RContext&>(), // rcontext
std::declval<Attribute&>() // attr
)
} -> std::convertible_to<bool>;
};
};
template <typename Parser, typename It, typename Se, typename Context, typename RContext, typename Attribute>
constexpr bool is_parsable_v = is_parsable<Parser, It, Se, Context, RContext, Attribute>::value;
// TODO: handle `parse_into_container` case
template <typename Parser, typename It, typename Se, typename Context, typename RContext, typename Attribute>
concept Parsable = is_parsable<Parser, It, Se, Context, RContext, Attribute>::value;
// ^^^ this must be concept in order to provide better diagnostics (e.g. on MSVC)
template <
typename Parser,
typename It, // Don't constrain these; just let `static_assert` be engaged for friendly errors
typename Se,
typename Context,
typename RContext,
typename Attribute
>
struct is_nothrow_parsable
{
static_assert(X3Subject<Parser>);
static_assert(!std::is_reference_v<It>);
static_assert(std::forward_iterator<It>);
static_assert(std::sentinel_for<Se, It>);
static_assert(!std::is_reference_v<Context>);
static_assert(!std::is_reference_v<RContext>);
static_assert(!std::is_reference_v<Attribute>);
static constexpr bool value = requires(Parser const& p) // mutable parser use case is currently unknown
{
{
p.parse(
std::declval<It&>(), // first
std::declval<Se>(), // last
std::declval<Context const&>(), // context
std::declval<RContext&>(), // rcontext
std::declval<Attribute&>() // attr
)
} noexcept -> std::convertible_to<bool>;
};
};
template <typename Parser, typename It, typename Se, typename Context, typename RContext, typename Attribute>
constexpr bool is_nothrow_parsable_v = is_nothrow_parsable<Parser, It, Se, Context, RContext, Attribute>::value;
// The primary "parser" concept of X3, applicable in iterator-aware contexts.
//
// Let `it` denote an lvalue reference of `It`, and let `se` denote a prvalue of `Se`.
// Let `p` denote an lvalue reference of `Parser`.
//
// For `Parser` to model `X3Parser`, the following conditions must be satisfied:
// -- the expression `x3::as_parser(p)` is well-formed in unevaluated context, and
// -- the expression `cp.parse(it, se, x3::unused, x3::unused, x3::unused)`
// is well-formed and the return type is convertible to `bool`, where `cp` denotes a
// const lvalue reference to the result of the expression `x3::as_parser(p)`.
//
// Although some exotic user-defined parser could be designed to operate on the very
// specific context type and/or attribute type, we require the parser to at least
// accept `unused_type` for `RContext`, `Context` and `Attribute`. This is because
// core parsers of Spirit have historically been assuming natural use of `unused_type`
// in many locations.
template <typename Parser, class It, class Se>
concept X3Parser =
X3Subject<Parser> &&
is_parsable_v<as_parser_plain_t<Parser>, It, Se, unused_type, unused_type, unused_type>;
// The runtime type info that can be obtained via `x3::what(p)`.
template <X3Subject Subject, typename Enabled = void>
// Note: unlike Spirit2, spirit parsers are no longer required to have a
// "what" member function. In X3, we specialize the get_info struct
// below where needed. If a specialization is not provided, the default
// below will be used. The default "what" result will be the typeid
// name of the parser if BOOST_SPIRIT_X3_NO_RTTI is not defined, otherwise
// "undefined"
///////////////////////////////////////////////////////////////////////////
template <typename Parser, typename Enable = void>
struct get_info
{
[[nodiscard]] static constexpr std::string operator()(Subject const& subject)
typedef std::string result_type;
std::string operator()(Parser const&) const
{
if constexpr (requires {
{ subject.get_x3_info() } -> std::convertible_to<std::string>;
})
{
return subject.get_x3_info();
}
else
{
(void)subject;
#ifndef BOOST_SPIRIT_X3_NO_RTTI
return typeid(Subject).name();
#else
return "(get_info undefined)";
#endif
}
#if !defined(BOOST_SPIRIT_X3_NO_RTTI)
return typeid(Parser).name();
#else
return "undefined";
#endif
}
};
namespace detail
template <typename Parser>
std::string what(Parser const& p)
{
// "what" is an extremely common identifier that can be defined in many user-specific
// namespaces. We should avoid ADL usage for such generic names in the first place.
// (Note: CPO inhibits ADL in general.)
struct what_fn
{
template <X3Subject Subject>
[[nodiscard]] static constexpr std::string operator()(Subject const& p)
{
return get_info<Subject>{}(p);
}
};
} // detail
return get_info<Parser>()(p);
}
}}}
inline namespace cpos
{
inline constexpr detail::what_fn what{}; // no ADL
} // cpos
} // boost::spirit::x3
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename Subject, typename Derived, typename Context>
struct has_attribute<x3::unary_parser<Subject, Derived>, Context>
@@ -506,7 +223,8 @@ namespace boost::spirit::x3::traits
template <typename Left, typename Right, typename Derived, typename Context>
struct has_attribute<x3::binary_parser<Left, Right, Derived>, Context>
: std::disjunction<has_attribute<Left, Context>, has_attribute<Right, Context>> {};
} // boost::spirit::x3::traits
: mpl::bool_<has_attribute<Left, Context>::value ||
has_attribute<Right, Context>::value> {};
}}}}
#endif

View File

@@ -0,0 +1,51 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2017 wanghan02
Copyright (c) 2024 Nana Sakisaka
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_PROXY_FEBRUARY_1_2013_0211PM)
#define BOOST_SPIRIT_X3_PROXY_FEBRUARY_1_2013_0211PM
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
namespace boost { namespace spirit { namespace x3
{
template <typename Subject, typename Derived>
struct proxy : unary_parser<Subject, Derived>
{
static bool const is_pass_through_unary = true;
constexpr proxy(Subject const& subject)
: unary_parser<Subject, Derived>(subject) {}
// Overload this when appropriate. The proxy parser will pick up
// the most derived overload.
template <typename Iterator, typename Context
, typename RuleContext, typename Attribute, typename Category>
bool parse_subject(Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, Attribute& attr, Category) const
{
this->subject.parse(first, last, context, rcontext, attr);
return !has_expectation_failure(context);
}
// Main entry point.
template <typename Iterator, typename Context
, typename RuleContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RuleContext& rcontext, Attribute& attr) const
{
return this->derived().parse_subject(first, last, context, rcontext, attr
, typename traits::attribute_category<Attribute>::type());
}
};
}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -13,86 +13,61 @@
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/declval.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <iterator>
#include <type_traits>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
// Tag used to find the skipper from the context
struct skipper_tag;
///////////////////////////////////////////////////////////////////////////
// Move the /first/ iterator to the first non-matching position
// given a skip-parser. The function is a no-op if unused_type or
// unused_skipper is passed as the skip-parser.
template <X3Subject Skipper>
struct [[nodiscard]] unused_skipper
///////////////////////////////////////////////////////////////////////////
template <typename Skipper>
struct unused_skipper : unused_type
{
constexpr unused_skipper(Skipper const& skipper) noexcept
: skipper(skipper)
{}
unused_skipper(Skipper const& skipper)
: skipper(skipper) {}
Skipper const& skipper;
};
template <typename Context>
using unused_skipper_t = unused_skipper<std::remove_cvref_t<decltype(x3::get<skipper_tag>(std::declval<Context>()))>>;
namespace detail
{
template <typename Skipper>
struct is_unused_skipper : std::false_type
{
static_assert(X3Subject<Skipper>);
};
struct is_unused_skipper
: mpl::false_ {};
template <typename Skipper>
struct is_unused_skipper<unused_skipper<Skipper>> : std::true_type {};
struct is_unused_skipper<unused_skipper<Skipper>>
: mpl::true_ {};
template <>
struct is_unused_skipper<unused_type> : std::true_type {};
struct is_unused_skipper<unused_type>
: mpl::true_ {};
template <typename Skipper>
[[nodiscard]] constexpr Skipper const&
get_unused_skipper(Skipper const& skipper) noexcept
inline Skipper const&
get_unused_skipper(Skipper const& skipper)
{
static_assert(X3Subject<Skipper>);
return skipper;
}
template <typename Skipper>
[[nodiscard]] constexpr Skipper const&
get_unused_skipper(unused_skipper<Skipper> const& unused_skipper) noexcept
inline Skipper const&
get_unused_skipper(unused_skipper<Skipper> const& unused_skipper)
{
static_assert(X3Subject<Skipper>);
return unused_skipper.skipper;
}
template <typename Context>
struct skip_over_context
{
using type = unused_type;
};
template <typename Context>
requires (!std::is_same_v<expectation_failure_t<Context>, unused_type>)
struct skip_over_context<Context>
{
using type = std::remove_cvref_t<decltype(x3::make_context<expectation_failure_tag>(
x3::get<expectation_failure_tag>(std::declval<Context const&>())
))>;
};
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, X3Subject Skipper>
constexpr void skip_over(
It& first, Se const& last, Context& context, Skipper const& skipper
)
noexcept(is_nothrow_parsable_v<Skipper, It, Se, typename skip_over_context<Context>::type, unused_type, unused_type>)
template <typename Iterator, typename Context, typename Skipper>
inline void skip_over(
Iterator& first, Iterator const& last, Context& context, Skipper const& skipper)
{
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
(void)context;
boost::ignore_unused(context);
while (skipper.parse(first, last, unused, unused, unused))
/* loop */;
#else
@@ -142,7 +117,7 @@ namespace boost::spirit::x3
// For this reason we're going to cherry-pick the reference
// and repack it into a brand new context.
auto const local_ctx = x3::make_context<expectation_failure_tag>(
auto const local_ctx = make_context<expectation_failure_tag>(
x3::get<expectation_failure_tag>(context));
while (skipper.parse(first, last, local_ctx, unused, unused))
@@ -151,33 +126,35 @@ namespace boost::spirit::x3
#endif
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context>
constexpr void skip_over(It&, Se const&, Context&, unused_type) noexcept
template <typename Iterator, typename Context>
inline void skip_over(Iterator&, Iterator const&, Context&, unused_type)
{
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Skipper>
constexpr void skip_over(It&, Se const&, Context&, unused_skipper<Skipper> const&) noexcept
template <typename Iterator, typename Context, typename Skipper>
inline void skip_over(
Iterator&, Iterator const&, Context&, unused_skipper<Skipper> const&)
{
}
}
// this tag is used to find the skipper from the context
struct skipper_tag;
template <typename Context>
struct has_skipper
: std::bool_constant<!detail::is_unused_skipper<
std::remove_cvref_t<decltype(x3::get<skipper_tag>(std::declval<Context>()))>
>::value>
{};
: mpl::not_<detail::is_unused_skipper<
typename remove_cv<typename remove_reference<
decltype(x3::get<skipper_tag>(boost::declval<Context>()))
>::type>::type
>> {};
template <typename Context>
constexpr bool has_skipper_v = has_skipper<Context>::value;
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context>
constexpr void skip_over(It& first, Se const& last, Context& context)
noexcept(noexcept(detail::skip_over(first, last, context, x3::get<skipper_tag>(context))))
template <typename Iterator, typename Context>
inline void skip_over(
Iterator& first, Iterator const& last, Context& context)
{
detail::skip_over(first, last, context, x3::get<skipper_tag>(context));
}
} // boost::spirit::x3
}}}
#endif

View File

@@ -2,7 +2,7 @@
Copyright (c) 2009 Chris Hoeppler
Copyright (c) 2014 Lee Clagett
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -13,124 +13,82 @@
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template<typename Prefix, typename Subject, typename Postfix>
struct confix_directive :
unary_parser<Subject, confix_directive<Prefix, Subject, Postfix>>
{
using base_type = unary_parser<Subject, confix_directive<Prefix, Subject, Postfix>>;
static constexpr bool is_pass_through_unary = true;
static constexpr bool handles_container = Subject::handles_container;
typedef unary_parser<
Subject, confix_directive<Prefix, Subject, Postfix>> base_type;
static bool const is_pass_through_unary = true;
static bool const handles_container = Subject::handles_container;
template <typename PrefixT, typename SubjectT, typename PostfixT>
requires
std::is_constructible_v<Prefix, PrefixT> &&
std::is_constructible_v<Subject, SubjectT> &&
std::is_constructible_v<Postfix, PostfixT>
constexpr confix_directive(PrefixT&& prefix, SubjectT&& subject, PostfixT&& postfix)
noexcept(
std::is_nothrow_constructible_v<Prefix, PrefixT> &&
std::is_nothrow_constructible_v<Subject, SubjectT> &&
std::is_nothrow_constructible_v<Postfix, PostfixT>
)
: base_type(std::forward<SubjectT>(subject))
, prefix_(std::forward<PrefixT>(prefix))
, postfix_(std::forward<PostfixT>(postfix))
constexpr confix_directive(Prefix const& prefix
, Subject const& subject
, Postfix const& postfix) :
base_type(subject),
prefix(prefix),
postfix(postfix)
{
}
template<std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) const noexcept(
std::is_nothrow_copy_assignable_v<It> &&
is_nothrow_parsable_v<Prefix, It, Se, Context, RContext, unused_type> &&
is_nothrow_parsable_v<Subject, It, Se, Context, RContext, Attribute> &&
is_nothrow_parsable_v<Postfix, It, Se, Context, RContext, unused_type>
)
template<typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(
Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
It const saved_first = first;
Iterator save = first;
if (!(prefix_.parse(first, last, context, rcontext, unused) &&
if (!(prefix.parse(first, last, context, rcontext, unused) &&
this->subject.parse(first, last, context, rcontext, attr) &&
postfix_.parse(first, last, context, rcontext, unused))
) {
postfix.parse(first, last, context, rcontext, unused)))
{
#if !BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
if (x3::has_expectation_failure(context))
if (has_expectation_failure(context))
{
// don't rollback iterator (mimicking exception-like behavior)
return false;
}
#endif
first = saved_first;
first = save;
return false;
}
return true;
}
private:
Prefix prefix_;
Postfix postfix_;
Prefix prefix;
Postfix postfix;
};
namespace detail
template<typename Prefix, typename Postfix>
struct confix_gen
{
template <X3Subject Prefix, X3Subject Postfix>
struct [[nodiscard]] confix_gen
template<typename Subject>
constexpr confix_directive<
Prefix, typename extension::as_parser<Subject>::value_type, Postfix>
operator[](Subject const& subject) const
{
template <X3Subject Subject>
[[nodiscard]] constexpr confix_directive<Prefix, as_parser_plain_t<Subject>, Postfix>
operator[](Subject&& subject) const
noexcept(
is_parser_nothrow_castable_v<Subject> &&
std::is_nothrow_constructible_v<
confix_directive<Prefix, as_parser_plain_t<Subject>, Postfix>,
Prefix const&,
as_parser_t<Subject>,
Postfix const&
>
)
{
return { prefix, as_parser(std::forward<Subject>(subject)), postfix };
}
return { prefix, as_parser(subject), postfix };
}
Prefix prefix;
Postfix postfix;
};
Prefix prefix;
Postfix postfix;
};
struct confix_fn
{
template <X3Subject Prefix, X3Subject Postfix>
static constexpr confix_gen<as_parser_plain_t<Prefix>, as_parser_plain_t<Postfix>>
operator()(Prefix&& prefix, Postfix&& postfix)
noexcept(
is_parser_nothrow_castable_v<Prefix> &&
is_parser_nothrow_castable_v<Postfix> &&
std::is_nothrow_constructible_v<
detail::confix_gen<as_parser_plain_t<Prefix>, as_parser_plain_t<Postfix>>,
as_parser_t<Prefix>, as_parser_t<Postfix>
>
)
{
return { as_parser(std::forward<Prefix>(prefix)), as_parser(std::forward<Postfix>(postfix)) };
}
};
} // detail
inline namespace cpos
template<typename Prefix, typename Postfix>
constexpr confix_gen<typename extension::as_parser<Prefix>::value_type,
typename extension::as_parser<Postfix>::value_type>
confix(Prefix const& prefix, Postfix const& postfix)
{
inline constexpr detail::confix_fn confix{};
} // cpos
} // boost::spirit::x3
return { as_parser(prefix), as_parser(postfix) };
}
}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -14,30 +14,21 @@
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Subject>
struct expect_directive : unary_parser<Subject, expect_directive<Subject>>
{
using base_type = unary_parser<Subject, expect_directive<Subject>>;
static constexpr bool is_pass_through_unary = true;
typedef unary_parser<Subject, expect_directive<Subject> > base_type;
static bool const is_pass_through_unary = true;
template <typename SubjectT>
requires std::is_constructible_v<Subject, SubjectT>
constexpr expect_directive(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
{}
constexpr expect_directive(Subject const& subject)
: base_type(subject) {}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) const // never noexcept; expectation failure requires construction of debug information
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
bool const r = this->subject.parse(first, last, context, rcontext, attr);
@@ -45,12 +36,12 @@ namespace boost::spirit::x3
{
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
boost::throw_exception(
expectation_failure<It>(
first, x3::what(this->subject)));
expectation_failure<Iterator>(
first, what(this->subject)));
#else
if (!x3::has_expectation_failure(context))
if (!has_expectation_failure(context))
{
x3::set_expectation_failure(first, this->subject, context);
set_expectation_failure(first, this->subject, context);
}
#endif
}
@@ -58,59 +49,50 @@ namespace boost::spirit::x3
}
};
namespace detail
struct expect_gen
{
struct expect_gen
template <typename Subject>
constexpr expect_directive<typename extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
template <X3Subject Subject>
[[nodiscard]] constexpr expect_directive<as_parser_plain_t<Subject>>
operator[](Subject&& subject) const
noexcept(is_parser_nothrow_constructible_v<expect_directive<as_parser_plain_t<Subject>>, Subject>)
{
return { as_parser(std::forward<Subject>(subject)) };
}
};
} // detail
return { as_parser(subject) };
}
};
inline namespace cpos
{
inline constexpr detail::expect_gen expect{};
} // cpos
constexpr auto expect = expect_gen{};
}}}
} // boost::spirit::x3
namespace boost::spirit::x3::detail
namespace boost { namespace spirit { namespace x3 { namespace detail
{
// Special case handling for expect expressions.
template <typename Subject, typename Context, typename RContext>
struct parse_into_container_impl<expect_directive<Subject>, Context, RContext>
{
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
[[nodiscard]] static constexpr bool
call(
expect_directive<Subject> const& parser,
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) // never noexcept; expectation failure requires construction of debug information
template <typename Iterator, typename Attribute>
static bool call(
expect_directive<Subject> const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr)
{
bool const r = detail::parse_into_container(
bool const r = parse_into_container(
parser.subject, first, last, context, rcontext, attr);
if (!r)
{
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
boost::throw_exception(
expectation_failure<It>(
first, x3::what(parser.subject)));
expectation_failure<Iterator>(
first, what(parser.subject)));
#else
if (!x3::has_expectation_failure(context))
if (!has_expectation_failure(context))
{
x3::set_expectation_failure(first, parser.subject, context);
set_expectation_failure(first, parser.subject, context);
}
#endif
}
return r;
}
};
} // boost::spirit::x3::detail
}}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -12,85 +11,68 @@
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/enable_if.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Subject>
struct lexeme_directive : unary_parser<Subject, lexeme_directive<Subject>>
{
using base_type = unary_parser<Subject, lexeme_directive<Subject>>;
static constexpr bool is_pass_through_unary = true;
static constexpr bool handles_container = Subject::handles_container;
typedef unary_parser<Subject, lexeme_directive<Subject> > base_type;
static bool const is_pass_through_unary = true;
static bool const handles_container = Subject::handles_container;
template <typename SubjectT>
requires std::is_constructible_v<Subject, SubjectT>
constexpr lexeme_directive(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<base_type, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
{}
constexpr lexeme_directive(Subject const& subject)
: base_type(subject) {}
template <typename Context>
using pre_skip_context_t = std::remove_cvref_t<decltype(
x3::make_context<skipper_tag>(std::declval<unused_skipper_t<Context>&>(), std::declval<Context const&>())
)>;
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires has_skipper_v<Context>
[[nodiscard]] constexpr bool parse(
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) const
noexcept(
noexcept(x3::skip_over(first, last, context)) &&
is_nothrow_parsable_v<Subject, It, Se, pre_skip_context_t<Context>, RContext, Attribute>
)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
typename enable_if<has_skipper<Context>, bool>::type
parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
x3::skip_over(first, last, context);
auto const& skipper = x3::get<skipper_tag>(context);
unused_skipper_t<Context> unused_skipper(skipper);
typedef unused_skipper<
typename remove_reference<decltype(skipper)>::type>
unused_skipper_type;
unused_skipper_type unused_skipper(skipper);
return this->subject.parse(
first, last,
x3::make_context<skipper_tag>(unused_skipper, context),
rcontext,
attr
);
first, last
, make_context<skipper_tag>(unused_skipper, context)
, rcontext
, attr);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires (!has_skipper_v<Context>)
[[nodiscard]] constexpr bool parse(
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) const
noexcept(is_nothrow_parsable_v<Subject, It, Se, Context, RContext, Attribute>)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
typename disable_if<has_skipper<Context>, bool>::type
parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
// no need to pre-skip if skipper is unused
return this->subject.parse(first, last, context, rcontext, attr);
return this->subject.parse(
first, last
, context
, rcontext
, attr);
}
};
namespace detail
struct lexeme_gen
{
struct lexeme_gen
template <typename Subject>
constexpr lexeme_directive<typename extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
template <X3Subject Subject>
[[nodiscard]] constexpr lexeme_directive<as_parser_plain_t<Subject>>
operator[](Subject&& subject) const
noexcept(is_parser_nothrow_constructible_v<lexeme_directive<as_parser_plain_t<Subject>>, Subject>)
{
return { as_parser(std::forward<Subject>(subject)) };
}
};
} // detail
return { as_parser(subject) };
}
};
inline namespace cpos
{
inline constexpr detail::lexeme_gen lexeme{};
}
} // boost::spirit::x3
constexpr auto lexeme = lexeme_gen{};
}}}
#endif

View File

@@ -2,7 +2,7 @@
Copyright (c) 2015 Mario Lang
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -15,64 +15,45 @@
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Subject>
struct matches_directive : unary_parser<Subject, matches_directive<Subject>>
{
using base_type = unary_parser<Subject, matches_directive<Subject>>;
static constexpr bool has_attribute = true;
static bool const has_attribute = true;
using attribute_type = bool;
template <typename SubjectT>
requires std::is_constructible_v<Subject, SubjectT>
constexpr matches_directive(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
{}
constexpr matches_directive(Subject const& subject) : base_type(subject) {}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
noexcept(
is_nothrow_parsable_v<Subject, It, Se, Context, RContext, unused_type> &&
noexcept(traits::move_to(std::declval<bool const&>(), attr))
)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
bool const matched = this->subject.parse(first, last, context, rcontext, unused);
bool const result = this->subject.parse(
first, last, context, rcontext, unused);
#if !BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
if (x3::has_expectation_failure(context)) return false;
if (has_expectation_failure(context)) return false;
#endif
traits::move_to(matched, attr);
traits::move_to(result, attr);
return true;
}
};
namespace detail
struct matches_gen
{
struct matches_gen
template <typename Subject>
constexpr matches_directive<typename extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
template <X3Subject Subject>
[[nodiscard]] constexpr matches_directive<as_parser_plain_t<Subject>>
operator[](Subject&& subject) const
noexcept(is_parser_nothrow_constructible_v<matches_directive<as_parser_plain_t<Subject>>, Subject>)
{
return { as_parser(std::forward<Subject>(subject)) };
}
};
} // detail
return { as_parser(subject) };
}
};
inline namespace cpos
{
inline constexpr detail::matches_gen matches{};
} // cpos
} // boost::spirit::x3
constexpr auto matches = matches_gen{};
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,58 +10,42 @@
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
// `omit_directive` forces the attribute of subject parser
// to be `unused_type`
///////////////////////////////////////////////////////////////////////////
// omit_directive forces the attribute of subject parser
// to be unused_type
///////////////////////////////////////////////////////////////////////////
template <typename Subject>
struct omit_directive : unary_parser<Subject, omit_directive<Subject>>
{
using base_type = unary_parser<Subject, omit_directive<Subject>>;
using attribute_type = unused_type;
using subject_type = Subject;
static constexpr bool has_attribute = false;
typedef unary_parser<Subject, omit_directive<Subject> > base_type;
typedef unused_type attribute_type;
static bool const has_attribute = false;
template <typename SubjectT>
requires std::is_constructible_v<Subject, SubjectT>
constexpr omit_directive(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
{}
typedef Subject subject_type;
constexpr omit_directive(Subject const& subject)
: base_type(subject) {}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext>
[[nodiscard]] constexpr bool
parse(
It& first, Se const& last, Context const& context, RContext& rcontext, unused_type
) const noexcept(is_nothrow_parsable_v<Subject, It, Se, Context, RContext, unused_type>)
template <typename Iterator, typename Context, typename RContext>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, unused_type) const
{
static_assert(Parsable<Subject, It, Se, Context, RContext, unused_type>);
return this->subject.parse(first, last, context, rcontext, unused);
}
};
namespace detail
struct omit_gen
{
struct omit_gen
template <typename Subject>
constexpr omit_directive<typename extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
template <X3Subject Subject>
[[nodiscard]] constexpr omit_directive<as_parser_plain_t<Subject>>
operator[](Subject&& subject) const
noexcept(is_parser_nothrow_constructible_v<omit_directive<as_parser_plain_t<Subject>>, as_parser_t<Subject>>)
{
return { as_parser(std::forward<Subject>(subject)) };
}
};
} // detail
return { as_parser(subject) };
}
};
inline namespace cpos
{
inline constexpr detail::omit_gen omit{};
}
} // boost::spirit::x3
constexpr auto omit = omit_gen{};
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -12,20 +11,11 @@
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/traits/pseudo_attribute.hpp>
#include <boost/range/iterator_range_core.hpp>
#ifndef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
# pragma message("Use of `boost::iterator_range` is deprecated in X3. #define BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE")
# include <boost/range/iterator_range_core.hpp>
#endif
#include <ranges>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
// Pseudo attribute type indicating that the parser wants the
// this is a pseudo attribute type indicating that the parser wants the
// iterator range pointing to the [first, last) matching characters from
// the input iterators.
struct raw_attribute_type {};
@@ -33,83 +23,64 @@ namespace boost::spirit::x3
template <typename Subject>
struct raw_directive : unary_parser<Subject, raw_directive<Subject>>
{
using base_type = unary_parser<Subject, raw_directive<Subject>>;
using attribute_type = raw_attribute_type;
using subject_type = Subject;
typedef unary_parser<Subject, raw_directive<Subject> > base_type;
typedef raw_attribute_type attribute_type;
static bool const handles_container = true;
typedef Subject subject_type;
static constexpr bool handles_container = true;
constexpr raw_directive(Subject const& subject)
: base_type(subject) {}
template <typename SubjectT>
requires std::is_constructible_v<Subject, SubjectT>
constexpr raw_directive(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
{}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
// never noexcept; construction of `std::ranges::subrange` is never noexcept
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
static_assert(Parsable<Subject, It, Se, Context, RContext, unused_type>);
x3::skip_over(first, last, context);
It local_it = first;
if (this->subject.parse(local_it, last, context, rcontext, unused))
Iterator i = first;
if (this->subject.parse(i, last, context, rcontext, unused))
{
traits::move_to(first, local_it, attr);
first = local_it;
traits::move_to(first, i, attr);
first = i;
return true;
}
return false;
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, unused_type) const
noexcept(is_nothrow_parsable_v<Subject, It, Se, Context, RContext, unused_type>)
template <typename Iterator, typename Context, typename RContext>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, unused_type) const
{
return this->subject.parse(first, last, context, rcontext, unused);
}
};
namespace detail
struct raw_gen
{
struct raw_gen
template <typename Subject>
constexpr raw_directive<typename extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
template <X3Subject Subject>
[[nodiscard]] constexpr raw_directive<as_parser_plain_t<Subject>>
operator[](Subject&& subject) const
noexcept(is_parser_nothrow_constructible_v<raw_directive<as_parser_plain_t<Subject>>, as_parser_t<Subject>>)
{
return { as_parser(std::forward<Subject>(subject)) };
}
};
} // detail
return { as_parser(subject) };
}
};
inline namespace cpos
{
inline constexpr detail::raw_gen raw{};
}
constexpr auto raw = raw_gen{};
namespace traits
{
template <typename Context, std::forward_iterator It>
struct pseudo_attribute<Context, raw_attribute_type, It>
template <typename Context, typename Iterator>
struct pseudo_attribute<Context, raw_attribute_type, Iterator>
{
using attribute_type = raw_attribute_type;
#ifdef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
using type = std::ranges::subrange<It>;
#else
using type = boost::iterator_range<It>;
#endif
using type = boost::iterator_range<Iterator>;
[[nodiscard]] static constexpr type call(It& first, std::sentinel_for<It> auto const& last, raw_attribute_type)
static type call(Iterator& first, Iterator const& last, attribute_type)
{
return { first, last };
}
};
}
} // boost::spirit::x3
}}}
#endif

View File

@@ -3,7 +3,7 @@
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2014 Thomas Bernard
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -15,192 +15,144 @@
#include <boost/spirit/home/x3/operator/kleene.hpp>
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <iterator>
#include <type_traits>
#include <concepts>
#include <utility>
namespace boost::spirit::x3::detail
namespace boost { namespace spirit { namespace x3 { namespace detail
{
template <std::integral T>
template <typename T>
struct exact_count // handles repeat(exact)[p]
{
using value_type = T;
[[nodiscard]] constexpr bool got_max(T i) const noexcept { return i >= exact_value; }
[[nodiscard]] constexpr bool got_min(T i) const noexcept { return i >= exact_value; }
typedef T type;
bool got_max(T i) const { return i >= exact_value; }
bool got_min(T i) const { return i >= exact_value; }
T exact_value;
T const exact_value;
};
template <std::integral T>
template <typename T>
struct finite_count // handles repeat(min, max)[p]
{
using value_type = T;
[[nodiscard]] constexpr bool got_max(T i) const noexcept { return i >= max_value; }
[[nodiscard]] constexpr bool got_min(T i) const noexcept { return i >= min_value; }
typedef T type;
bool got_max(T i) const { return i >= max_value; }
bool got_min(T i) const { return i >= min_value; }
T min_value;
T max_value;
T const min_value;
T const max_value;
};
template <std::integral T>
template <typename T>
struct infinite_count // handles repeat(min, inf)[p]
{
using value_type = T;
[[nodiscard]] constexpr bool got_max(T /*i*/) const noexcept { return false; }
[[nodiscard]] constexpr bool got_min(T i) const noexcept { return i >= min_value; }
typedef T type;
bool got_max(T /*i*/) const { return false; }
bool got_min(T i) const { return i >= min_value; }
T min_value;
T const min_value;
};
} // boost::spirit::x3::detail
}}}}
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
namespace detail
template<typename Subject, typename RepeatCountLimit>
struct repeat_directive : unary_parser<Subject, repeat_directive<Subject,RepeatCountLimit>>
{
template <typename Bounds>
concept RepeatBounds = requires(std::remove_cvref_t<Bounds> const& bounds) {
typename std::remove_cvref_t<Bounds>::value_type;
{ bounds.got_max(std::declval<typename std::remove_cvref_t<Bounds>::value_type>()) } -> std::same_as<bool>;
{ bounds.got_min(std::declval<typename std::remove_cvref_t<Bounds>::value_type>()) } -> std::same_as<bool>;
};
} // detail
typedef unary_parser<Subject, repeat_directive<Subject,RepeatCountLimit>> base_type;
static bool const is_pass_through_unary = true;
static bool const handles_container = true;
template <typename Subject, detail::RepeatBounds Bounds>
struct repeat_directive : unary_parser<Subject, repeat_directive<Subject, Bounds>>
{
using base_type = unary_parser<Subject, repeat_directive<Subject, Bounds>>;
static constexpr bool is_pass_through_unary = true;
static constexpr bool handles_container = true;
template <typename SubjectT, detail::RepeatBounds BoundsT>
requires std::is_constructible_v<base_type, SubjectT> && std::is_constructible_v<Bounds, BoundsT>
constexpr repeat_directive(SubjectT&& subject, BoundsT&& bounds)
noexcept(std::is_nothrow_constructible_v<base_type, SubjectT> && std::is_nothrow_constructible_v<Bounds, BoundsT>)
: base_type(std::forward<SubjectT>(subject))
, bounds_(std::forward<BoundsT>(bounds))
constexpr repeat_directive(Subject const& subject, RepeatCountLimit const& repeat_limit_)
: base_type(subject)
, repeat_limit(repeat_limit_)
{}
template<std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
// never noexcept (requires container insertion)
template<typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(
Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
It local_it = first;
typename Bounds::value_type i{};
for (; !bounds_.got_min(i); ++i)
Iterator local_iterator = first;
typename RepeatCountLimit::type i{};
for (/**/; !repeat_limit.got_min(i); ++i)
{
if (!detail::parse_into_container(this->subject, local_it, last, context, rcontext, attr))
{
if (!detail::parse_into_container(
this->subject, local_iterator, last, context, rcontext, attr))
return false;
}
}
first = local_it;
first = local_iterator;
// parse some more up to the maximum specified
for (; !bounds_.got_max(i); ++i)
for (/**/; !repeat_limit.got_max(i); ++i)
{
if (!detail::parse_into_container(this->subject, first, last, context, rcontext, attr))
{
if (!detail::parse_into_container(
this->subject, first, last, context, rcontext, attr))
break;
}
}
return !x3::has_expectation_failure(context);
return !has_expectation_failure(context);
}
private:
Bounds bounds_;
RepeatCountLimit repeat_limit;
};
namespace detail
// Infinite loop tag type
struct inf_type {};
constexpr inf_type inf = inf_type();
struct repeat_gen
{
// Infinite loop tag type
struct repeat_inf_type
template<typename Subject>
constexpr auto operator[](Subject const& subject) const
{
constexpr explicit repeat_inf_type() noexcept = default;
};
} // detail
return *as_parser(subject);
}
inline namespace cpos
{
// Infinite loop tag type
[[deprecated("Use `x3::repeat_inf`")]]
inline constexpr detail::repeat_inf_type inf{};
// Infinite loop tag type
inline constexpr detail::repeat_inf_type repeat_inf{};
}
namespace detail
{
struct repeat_gen
template <typename T>
struct repeat_gen_lvl1
{
template <X3Subject Subject>
[[nodiscard, deprecated("`repeat[p]` has the exact same meaning as `*p`. Use `*p` instead.")]]
constexpr auto operator[](Subject&& subject) const
noexcept(noexcept(*as_parser(std::forward<Subject>(subject))))
constexpr repeat_gen_lvl1(T&& repeat_limit_)
: repeat_limit(repeat_limit_)
{}
template<typename Subject>
constexpr repeat_directive< typename extension::as_parser<Subject>::value_type, T>
operator[](Subject const& subject) const
{
return *as_parser(std::forward<Subject>(subject));
return { as_parser(subject),repeat_limit };
}
template <RepeatBounds Bounds>
struct [[nodiscard]] repeat_gen_impl
{
template <X3Subject Subject>
[[nodiscard]] constexpr repeat_directive<as_parser_plain_t<Subject>, Bounds>
operator[](Subject&& subject) const
noexcept(
is_parser_nothrow_castable_v<Subject> &&
std::is_nothrow_constructible_v<
repeat_directive<as_parser_plain_t<Subject>, Bounds>,
as_parser_t<Subject>,
Bounds const&
>
)
{
return { as_parser(std::forward<Subject>(subject)), bounds };
}
Bounds bounds;
};
template <std::integral T>
static constexpr repeat_gen_impl<exact_count<T>>
operator()(T const exact) noexcept
{
return { exact_count<T>{exact} };
}
template <std::integral T>
static constexpr repeat_gen_impl<finite_count<T>>
operator()(T const min_val, T const max_val) noexcept
{
return { finite_count<T>{min_val, max_val} };
}
template <std::integral T>
static constexpr repeat_gen_impl<infinite_count<T>>
operator()(T const min_val, repeat_inf_type const&) noexcept
{
return { infinite_count<T>{min_val} };
}
T repeat_limit;
};
} // detail
inline namespace cpos
{
inline constexpr detail::repeat_gen repeat{};
}
template <typename T>
constexpr repeat_gen_lvl1<detail::exact_count<T>>
operator()(T const exact) const
{
return { detail::exact_count<T>{exact} };
}
} // boost::spirit::x3
template <typename T>
constexpr repeat_gen_lvl1<detail::finite_count<T>>
operator()(T const min_val, T const max_val) const
{
return { detail::finite_count<T>{min_val,max_val} };
}
namespace boost::spirit::x3::traits
template <typename T>
constexpr repeat_gen_lvl1<detail::infinite_count<T>>
operator()(T const min_val, inf_type const &) const
{
return { detail::infinite_count<T>{min_val} };
}
};
constexpr auto repeat = repeat_gen{};
}}}
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename Subject, typename Bounds, typename Context>
struct attribute_of<x3::repeat_directive<Subject, Bounds>, Context>
: build_container<attribute_of_t<Subject, Context>>
{};
} // boost::spirit::x3::traits
template <typename Subject, typename RepeatCountLimit, typename Context>
struct attribute_of<x3::repeat_directive<Subject,RepeatCountLimit>, Context>
: build_container<typename attribute_of<Subject, Context>::type> {};
}}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Agustin Berge
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -14,94 +14,67 @@
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/utility/enable_if.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Subject>
struct reskip_directive : unary_parser<Subject, reskip_directive<Subject>>
{
using base_type = unary_parser<Subject, reskip_directive<Subject>>;
static constexpr bool is_pass_through_unary = true;
static constexpr bool handles_container = Subject::handles_container;
typedef unary_parser<Subject, reskip_directive<Subject>> base_type;
static bool const is_pass_through_unary = true;
static bool const handles_container = Subject::handles_container;
template <typename SubjectT>
requires
(!std::is_same_v<std::remove_cvref_t<SubjectT>, reskip_directive>) &&
std::is_constructible_v<Subject, SubjectT>
constexpr reskip_directive(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
{}
constexpr reskip_directive(Subject const& subject)
: base_type(subject) {}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires has_skipper_v<Context>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
noexcept(is_nothrow_parsable_v<Subject, It, Se, Context, RContext, Attribute>)
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
typename disable_if<has_skipper<Context>, bool>::type
parse(Iterator& first, Iterator const& last
, Context& context, RContext& rcontext, Attribute& attr) const
{
static_assert(Parsable<Subject, It, Se, Context, RContext, Attribute>);
return this->subject.parse(first, last, context, rcontext, attr);
}
auto const& skipper =
detail::get_unused_skipper(x3::get<skipper_tag>(context));
private:
template <typename Context>
using context_t = x3::context<
skipper_tag,
decltype(detail::get_unused_skipper(x3::get<skipper_tag>(std::declval<Context const&>()))),
Context
>;
public:
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires (!has_skipper_v<Context>)
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
// never noexcept (requires expectation failure modification)
{
static_assert(Parsable<Subject, It, Se, context_t<Context>, RContext, Attribute>);
auto const& skipper = detail::get_unused_skipper(x3::get<skipper_tag>(context));
auto const local_ctx = x3::make_context<skipper_tag>(skipper, context);
auto const local_ctx = make_context<skipper_tag>(skipper, context);
bool const r = this->subject.parse(first, last, local_ctx, rcontext, attr);
#if !BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
if (x3::has_expectation_failure(local_ctx))
if (has_expectation_failure(local_ctx))
{
x3::set_expectation_failure(x3::get_expectation_failure(local_ctx), context);
set_expectation_failure(get_expectation_failure(local_ctx), context);
}
#endif
return r;
}
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
typename enable_if<has_skipper<Context>, bool>::type
parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
return this->subject.parse(first, last, context, rcontext, attr);
}
};
template <typename Subject, typename Skipper>
struct skip_directive : unary_parser<Subject, skip_directive<Subject, Skipper>>
{
using base_type = unary_parser<Subject, skip_directive<Subject, Skipper>>;
static constexpr bool is_pass_through_unary = true;
static constexpr bool handles_container = Subject::handles_container;
typedef unary_parser<Subject, skip_directive<Subject, Skipper>> base_type;
static bool const is_pass_through_unary = true;
static bool const handles_container = Subject::handles_container;
template <typename SubjectT, typename SkipperT>
requires std::is_constructible_v<Subject, SubjectT> && std::is_constructible_v<Skipper, SkipperT>
constexpr skip_directive(SubjectT&& subject, SkipperT&& skipper)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT> && std::is_nothrow_constructible_v<Skipper, SkipperT>)
: base_type(std::forward<SubjectT>(subject))
, skipper_(skipper)
constexpr skip_directive(Subject const& subject, Skipper const& skipper)
: base_type(subject)
, skipper(skipper)
{}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, unused_type const&, RContext& rcontext, Attribute& attr) const
noexcept(is_nothrow_parsable_v<Subject, It, Se, x3::context<skipper_tag, Skipper>, RContext, Attribute>)
template <typename Iterator, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, unused_type const&, RContext& rcontext, Attribute& attr) const
{
static_assert(Parsable<Subject, It, Se, x3::context<skipper_tag, Skipper>, RContext, Attribute>);
// It is perfectly fine to omit the expectation_failure context
// even in non-throwing mode if and only if the skipper itself
// is expectation-less.
@@ -121,126 +94,73 @@ namespace boost::spirit::x3
// Anyways, we don't need to repack the expectation context
// into our brand new skipper context, in contrast to the
// repacking process done in `x3::skip_over`.
return this->subject.parse(
first, last, x3::make_context<skipper_tag>(skipper_), rcontext, attr
);
return this->subject.parse(first, last,
make_context<skipper_tag>(skipper), rcontext, attr);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
// never noexcept (requires expectation failure modification)
template <typename Iterator, typename Context, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
static_assert(Parsable<Subject, It, Se, x3::context<skipper_tag, Context>, RContext, Attribute>);
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
return this->subject.parse(first, last, x3::make_context<skipper_tag>(skipper_, context), rcontext, attr);
return this->subject.parse(first, last, make_context<skipper_tag>(skipper, context), rcontext, attr);
#else
static_assert(
!std::is_same_v<expectation_failure_t<Context>, unused_type>,
"Context type was not specified for x3::expectation_failure_tag. "
"You probably forgot: `x3::with<x3::expectation_failure_tag>(failure)[p]`. "
"Note that you must also bind the context to your skipper."
);
"Note that you must also bind the context to your skipper.");
// This logic is heavily related to the instantiation chain;
// see `x3::skip_over` for details.
auto const local_ctx = x3::make_context<skipper_tag>(skipper_, context);
auto const local_ctx = make_context<skipper_tag>(skipper, context);
bool const r = this->subject.parse(first, last, local_ctx, rcontext, attr);
if (x3::has_expectation_failure(local_ctx))
if (has_expectation_failure(local_ctx))
{
x3::set_expectation_failure(x3::get_expectation_failure(local_ctx), context);
set_expectation_failure(get_expectation_failure(local_ctx), context);
}
return r;
#endif
}
private:
Skipper skipper_;
Skipper const skipper;
};
namespace detail
struct reskip_gen
{
template <X3Subject Skipper>
struct skip_gen_impl
{
// Unreference rvalue reference, but hold lvalue reference as-is
using skipper_type = std::conditional_t<
std::is_rvalue_reference_v<Skipper>,
std::remove_reference_t<Skipper>,
Skipper
>;
template <typename SkipperT>
requires std::is_same_v<std::remove_cvref_t<SkipperT>, std::remove_cvref_t<Skipper>>
constexpr skip_gen_impl(SkipperT&& skipper)
noexcept(std::is_nothrow_constructible_v<skipper_type, SkipperT>)
: skipper_(std::forward<SkipperT>(skipper))
{}
template <X3Subject Subject>
[[nodiscard]] constexpr skip_directive<as_parser_plain_t<Subject>, std::remove_cvref_t<Skipper>>
operator[](Subject&& subject) const
noexcept(
is_parser_nothrow_castable_v<Subject> &&
std::is_nothrow_constructible_v<
skip_directive<as_parser_plain_t<Subject>, std::remove_cvref_t<Skipper>>,
as_parser_t<Subject>,
skipper_type const&
>
)
{
return { as_parser(std::forward<Subject>(subject)), skipper_ };
}
private:
skipper_type skipper_;
};
template <typename Skipper>
struct skip_gen
{
template <X3Subject Skipper>
[[nodiscard]]
static constexpr skip_gen_impl<as_parser_t<Skipper>>
operator()(Skipper&& skipper)
noexcept(
is_parser_nothrow_castable_v<Skipper> &&
std::is_nothrow_constructible_v<skip_gen_impl<as_parser_t<Skipper>>, as_parser_t<Skipper>>
)
{
return { as_parser(std::forward<Skipper>(skipper)) };
}
constexpr skip_gen(Skipper const& skipper)
: skipper_(skipper) {}
template <typename Subject>
[[nodiscard, deprecated("Use `x3::reskip[p]`.")]]
/* static */ constexpr reskip_directive<as_parser_plain_t<Subject>>
operator[](Subject&& subject) const // MSVC 2022 bug: cannot define `static operator[]` even in C++26 mode
noexcept(is_parser_nothrow_constructible_v<reskip_directive<as_parser_plain_t<Subject>>, Subject>)
constexpr skip_directive<typename extension::as_parser<Subject>::value_type, Skipper>
operator[](Subject const& subject) const
{
return { as_parser(std::forward<Subject>(subject)) };
return { as_parser(subject), skipper_ };
}
Skipper skipper_;
};
struct reskip_gen
template <typename Skipper>
constexpr skip_gen<Skipper> const operator()(Skipper const& skipper) const
{
template <X3Subject Subject>
[[nodiscard]]
/* static */ constexpr reskip_directive<as_parser_plain_t<Subject>>
operator[](Subject&& subject) const // MSVC 2022 bug: cannot define `static operator[]` even in C++26 mode
noexcept(is_parser_nothrow_constructible_v<reskip_directive<as_parser_plain_t<Subject>>, Subject>)
{
return { as_parser(std::forward<Subject>(subject)) };
}
};
} // detail
return { skipper };
}
inline namespace cpos
{
inline constexpr detail::skip_gen skip{};
inline constexpr detail::reskip_gen reskip{};
}
} // boost::spirit::x3
template <typename Subject>
constexpr reskip_directive<typename extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
return { as_parser(subject) };
}
};
constexpr auto skip = reskip_gen{};
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,201 +10,77 @@
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Subject, typename ID, typename T>
struct with_directive;
namespace detail
///////////////////////////////////////////////////////////////////////////
// with directive injects a value into the context prior to parsing.
///////////////////////////////////////////////////////////////////////////
template <typename Subject, typename Derived, typename T>
struct with_value_holder
: unary_parser<Subject, Derived>
{
template <typename Subject, typename ID, typename T>
struct with_directive_impl
: unary_parser<Subject, with_directive<Subject, ID, T>>
{
using base_type = unary_parser<Subject, with_directive<Subject, ID, T>>;
mutable T val_;
template <typename SubjectT, typename U>
requires
std::is_constructible_v<Subject, SubjectT> &&
std::is_constructible_v<T, U>
constexpr with_directive_impl(SubjectT&& subject, U&& val)
noexcept(
std::is_nothrow_constructible_v<Subject, SubjectT> &&
std::is_nothrow_constructible_v<T, U>
)
: base_type(std::forward<SubjectT>(subject))
, val_(std::forward<U>(val))
{}
};
template <typename Subject, typename ID, typename T>
struct with_directive_impl<Subject, ID, T const>
: unary_parser<Subject, with_directive<Subject, ID, T const>>
{
using base_type = unary_parser<Subject, with_directive<Subject, ID, T const>>;
/* not mutable */ T const val_;
template <typename SubjectT, typename U>
requires
std::is_constructible_v<Subject, SubjectT> &&
std::is_constructible_v<T const, U>
constexpr with_directive_impl(SubjectT&& subject, U&& val)
noexcept(
std::is_nothrow_constructible_v<Subject, SubjectT> &&
std::is_nothrow_constructible_v<T const, U>
)
: base_type(std::forward<SubjectT>(subject))
, val_(std::forward<U>(val))
{}
};
template <typename Subject, typename ID, typename T>
struct with_directive_impl<Subject, ID, T&>
: unary_parser<Subject, with_directive<Subject, ID, T&>>
{
using base_type = unary_parser<Subject, with_directive<Subject, ID, T&>>;
T& val_;
template <typename SubjectT, typename U>
requires
std::is_constructible_v<Subject, SubjectT> &&
std::is_constructible_v<T&, U&>
constexpr with_directive_impl(SubjectT&& subject, U& val)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
, val_(val)
{}
};
} // detail
// `with` directive injects a value into the context prior to parsing.
// Holds lvalue references by reference, holds rvalue reference by value.
template <typename Subject, typename ID, typename T>
struct with_directive : detail::with_directive_impl<Subject, ID, T>
typedef unary_parser<Subject, Derived> base_type;
mutable T val;
constexpr with_value_holder(Subject const& subject, T&& val)
: base_type(subject)
, val(std::forward<T>(val)) {}
};
template <typename Subject, typename Derived, typename T>
struct with_value_holder<Subject, Derived, T&>
: unary_parser<Subject, Derived>
{
static_assert(
!std::is_rvalue_reference_v<T>,
"`x3::with`: rvalue reference is prohibited to prevent dangling reference"
);
static_assert(
std::is_lvalue_reference_v<T> || std::is_move_constructible_v<T>,
"Passing an rvalue to `x3::with` requires the type to be move-constructible "
"so it can be stored by value."
);
using subject_type = Subject;
using id_type = ID;
using value_type = T;
using base_type = detail::with_directive_impl<Subject, ID, T>;
static constexpr bool is_pass_through_unary = true;
static constexpr bool handles_container = Subject::handles_container;
template <typename SubjectT, typename U>
requires std::is_constructible_v<base_type, SubjectT, U>
constexpr with_directive(SubjectT&& subject, U&& val)
noexcept(std::is_nothrow_constructible_v<base_type, SubjectT, U>)
: base_type(std::forward<SubjectT>(subject), std::forward<U>(val))
{}
// The internal context type. This can be used to determine the composed
// context type used in `x3::parse`/`x3::phrase_parse`. It is required for
// the argument of `BOOST_SPIRIT_X3_INSTANTIATE`.
template <typename Context>
using context_t = context<ID, std::remove_reference_t<T>, Context>;
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
noexcept(is_nothrow_parsable_v<Subject, It, Se, context_t<Context>, RContext, Attribute>)
{
static_assert(Parsable<Subject, It, Se, context_t<Context>, RContext, Attribute>);
return this->subject.parse(
first, last,
x3::make_context<ID>(this->val_, context),
rcontext, attr
);
}
private:
using base_type::val_;
typedef unary_parser<Subject, Derived> base_type;
T& val;
constexpr with_value_holder(Subject const& subject, T& val)
: base_type(subject)
, val(val) {}
};
namespace detail
template <typename Subject, typename ID, typename T>
struct with_directive
: with_value_holder<Subject, with_directive<Subject, ID, T>, T>
{
template <typename ID, typename T>
struct [[nodiscard]] with_gen
typedef with_value_holder<Subject, with_directive<Subject, ID, T>, T> base_type;
static bool const is_pass_through_unary = true;
static bool const handles_container = Subject::handles_container;
typedef Subject subject_type;
constexpr with_directive(Subject const& subject, T&& val)
: base_type(subject, std::forward<T>(val)) {}
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
static_assert(!std::is_rvalue_reference_v<T>);
T val;
template <X3Subject Subject>
[[nodiscard]] constexpr with_directive<as_parser_plain_t<Subject>, ID, T>
operator[](Subject&& subject) &&
noexcept(
is_parser_nothrow_castable_v<Subject> &&
std::is_nothrow_constructible_v<
with_directive<as_parser_plain_t<Subject>, ID, T>,
as_parser_t<Subject>,
T&& // lvalue or rvalue, forwarded
>
)
{
// with rvalue `with_gen`, the held value can always be forwarded
return { as_parser(std::forward<Subject>(subject)), std::forward<T>(val) };
}
template <X3Subject Subject>
[[nodiscard]] constexpr with_directive<as_parser_plain_t<Subject>, ID, T>
operator[](Subject&& subject) const&
noexcept(
is_parser_nothrow_castable_v<Subject> &&
std::is_nothrow_constructible_v<
with_directive<as_parser_plain_t<Subject>, ID, T>,
as_parser_t<Subject>,
T& // lvalue
>
)
{
static_assert(
std::is_lvalue_reference_v<T> || std::is_copy_constructible_v<T>,
"When you have passed an rvalue to `x3::with` and saved the functor "
"as a local variable, it requires the held type to be copy-constructible. "
"If your type is move only, then apply `std::move` to your `x3::with<ID>(val)` "
"instance."
);
return { as_parser(std::forward<Subject>(subject)), val };
}
};
template <typename ID>
struct with_fn
{
template <typename T>
static constexpr with_gen<ID, T> operator()(T&& val)
noexcept(
std::is_lvalue_reference_v<T> ||
std::is_nothrow_move_constructible_v<T>
)
{
return { std::forward<T>(val) };
}
};
} // detail
inline namespace cpos
return this->subject.parse(
first, last
, make_context<ID>(this->val, context)
, rcontext
, attr);
}
};
template <typename ID, typename T>
struct with_gen
{
// `with` directive injects a value into the context prior to parsing.
// Holds lvalue references by reference, holds rvalue reference by value.
template <typename ID>
inline constexpr detail::with_fn<ID> with{};
} // cpos
} // boost::spirit::x3
T&& val;
template <typename Subject>
constexpr with_directive<typename extension::as_parser<Subject>::value_type, ID, T>
operator[](Subject const& subject) const
{
return { as_parser(subject), std::forward<T>(val) };
}
};
template <typename ID, typename T>
constexpr with_gen<ID, T> with(T&& val)
{
return { std::forward<T>(val) };
}
}}}
#endif

View File

@@ -0,0 +1,370 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2017 wanghan02
Copyright (c) 2024 Nana Sakisaka
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM)
#define BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM
#include <boost/core/ignore_unused.hpp>
#include <boost/spirit/home/x3/auxiliary/guard.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/directive/expect.hpp>
#include <boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp>
#include <boost/utility/addressof.hpp>
#if defined(BOOST_SPIRIT_X3_DEBUG)
#include <boost/spirit/home/x3/nonterminal/simple_trace.hpp>
#endif
#include <type_traits>
namespace boost { namespace spirit { namespace x3
{
template <typename ID>
struct identity;
template <typename ID, typename Attribute = unused_type, bool force_attribute = false>
struct rule;
struct parse_pass_context_tag;
namespace detail
{
template <typename ID>
struct rule_id {};
// we use this so we can detect if the default parse_rule
// is the being called.
struct default_parse_rule_result
{
default_parse_rule_result(bool r)
: r(r) {}
operator bool() const { return r; }
bool r;
};
}
// default parse_rule implementation
template <typename ID, typename Iterator
, typename Context, typename ActualAttribute>
inline detail::default_parse_rule_result
parse_rule(
detail::rule_id<ID>
, Iterator& first, Iterator const& last
, Context const& context, ActualAttribute& attr);
}}}
namespace boost { namespace spirit { namespace x3 { namespace detail
{
#if defined(BOOST_SPIRIT_X3_DEBUG)
template <typename Iterator, typename Attribute>
struct context_debug
{
context_debug(
char const* rule_name
, Iterator const& first, Iterator const& last
, Attribute const& attr
, bool const& ok_parse //was parse successful?
)
: ok_parse(ok_parse), rule_name(rule_name)
, first(first), last(last)
, attr(attr)
, f(detail::get_simple_trace())
{
f(first, last, attr, pre_parse, rule_name);
}
~context_debug()
{
auto status = ok_parse ? successful_parse : failed_parse ;
f(first, last, attr, status, rule_name);
}
bool const& ok_parse;
char const* rule_name;
Iterator const& first;
Iterator const& last;
Attribute const& attr;
detail::simple_trace_type& f;
};
#endif
template <typename ID, typename Iterator, typename Context, typename Enable = void>
struct has_on_error : mpl::false_ {};
template <typename ID, typename Iterator, typename Context>
struct has_on_error<ID, Iterator, Context,
decltype(void(
std::declval<ID>().on_error(
std::declval<Iterator&>()
, std::declval<Iterator>()
, std::declval<expectation_failure<Iterator>>()
, std::declval<Context>()
)
))
>
: mpl::true_
{};
template <typename ID, typename Iterator, typename Attribute, typename Context, typename Enable = void>
struct has_on_success : mpl::false_ {};
template <typename ID, typename Iterator, typename Attribute, typename Context>
struct has_on_success<ID, Iterator, Context, Attribute,
decltype(void(
std::declval<ID>().on_success(
std::declval<Iterator&>()
, std::declval<Iterator&>()
, std::declval<Attribute&>()
, std::declval<Context>()
)
))
>
: mpl::true_
{};
template <typename ID>
struct make_id
{
typedef identity<ID> type;
};
template <typename ID>
struct make_id<identity<ID>>
{
typedef identity<ID> type;
};
template <typename ID, typename RHS, typename Context>
Context const&
make_rule_context(RHS const& /* rhs */, Context const& context
, mpl::false_ /* is_default_parse_rule */)
{
return context;
}
template <typename ID, typename RHS, typename Context>
auto make_rule_context(RHS const& rhs, Context const& context
, mpl::true_ /* is_default_parse_rule */ )
{
return make_unique_context<ID>(rhs, context);
}
template <typename Attribute, typename ID, bool skip_definition_injection = false>
struct rule_parser
{
template <typename Iterator, typename Context, typename ActualAttribute>
static bool call_on_success(
Iterator& /* before */, Iterator& /* after */
, Context const& /* context */, ActualAttribute& /* attr */
, mpl::false_ /* No on_success handler */ )
{
return true;
}
template <typename Iterator, typename Context, typename ActualAttribute>
static bool call_on_success(
Iterator& before, Iterator& after
, Context const& context, ActualAttribute& attr
, mpl::true_ /* Has on_success handler */)
{
x3::skip_over(before, after, context);
bool pass = true;
ID().on_success(
before
, after
, attr
, make_context<parse_pass_context_tag>(pass, context)
);
return pass;
}
template <typename RHS, typename Iterator, typename Context
, typename RContext, typename ActualAttribute>
static bool parse_rhs_main(
RHS const& rhs
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, ActualAttribute& attr
, mpl::false_)
{
// see if the user has a BOOST_SPIRIT_DEFINE for this rule
typedef
decltype(parse_rule(
detail::rule_id<ID>{}, first, last
, make_unique_context<ID>(rhs, context), std::declval<Attribute&>()))
parse_rule_result;
// If there is no BOOST_SPIRIT_DEFINE for this rule,
// we'll make a context for this rule tagged by its ID
// so we can extract the rule later on in the default
// (generic) parse_rule function.
typedef
is_same<parse_rule_result, default_parse_rule_result>
is_default_parse_rule;
Iterator start = first;
bool r = rhs.parse(
first
, last
, make_rule_context<ID>(rhs, context, std::conditional_t<skip_definition_injection, mpl::false_, is_default_parse_rule>())
, rcontext
, attr
);
if (r)
{
r = call_on_success(start, first, context, attr
, has_on_success<ID, Iterator, Context, ActualAttribute>());
}
return r;
}
template <typename RHS, typename Iterator, typename Context
, typename RContext, typename ActualAttribute>
static bool parse_rhs_main(
RHS const& rhs
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, ActualAttribute& attr
, mpl::true_ /* on_error is found */)
{
for (;;)
{
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
try
#endif
{
if (parse_rhs_main(
rhs, first, last, context, rcontext, attr, mpl::false_()))
{
return true;
}
}
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
catch (expectation_failure<Iterator> const& x) {
#else
if (has_expectation_failure(context)) {
auto& x = get_expectation_failure(context);
#endif
// X3 developer note: don't forget to sync this implementation with x3::guard
switch (ID().on_error(first, last, x, context))
{
case error_handler_result::fail:
clear_expectation_failure(context);
return false;
case error_handler_result::retry:
continue;
case error_handler_result::accept:
return true;
case error_handler_result::rethrow:
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
throw;
#else
return false; // TODO: design decision required
#endif
}
}
return false;
}
}
template <typename RHS, typename Iterator
, typename Context, typename RContext, typename ActualAttribute>
static bool parse_rhs_main(
RHS const& rhs
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, ActualAttribute& attr)
{
return parse_rhs_main(
rhs, first, last, context, rcontext, attr
, has_on_error<ID, Iterator, Context>()
);
}
template <typename RHS, typename Iterator
, typename Context, typename RContext, typename ActualAttribute>
static bool parse_rhs(
RHS const& rhs
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, ActualAttribute& attr
, mpl::false_)
{
return parse_rhs_main(rhs, first, last, context, rcontext, attr);
}
template <typename RHS, typename Iterator
, typename Context, typename RContext, typename ActualAttribute>
static bool parse_rhs(
RHS const& rhs
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, ActualAttribute& /* attr */
, mpl::true_)
{
return parse_rhs_main(rhs, first, last, context, rcontext, unused);
}
template <typename RHS, typename Iterator, typename Context
, typename ActualAttribute, typename ExplicitAttrPropagation>
static bool call_rule_definition(
RHS const& rhs
, char const* rule_name
, Iterator& first, Iterator const& last
, Context const& context, ActualAttribute& attr
, ExplicitAttrPropagation)
{
boost::ignore_unused(rule_name);
// do down-stream transformation, provides attribute for
// rhs parser
typedef traits::transform_attribute<
ActualAttribute, Attribute, parser_id>
transform;
typedef typename transform::type transform_attr;
transform_attr attr_ = transform::pre(attr);
bool ok_parse
//Creates a place to hold the result of parse_rhs
//called inside the following scope.
;
{
// Create a scope to cause the dbg variable below (within
// the #if...#endif) to call it's DTOR before any
// modifications are made to the attribute, attr_ passed
// to parse_rhs (such as might be done in
// transform::post when, for example,
// ActualAttribute is a recursive variant).
#if defined(BOOST_SPIRIT_X3_DEBUG)
context_debug<Iterator, transform_attr>
dbg(rule_name, first, last, attr_, ok_parse);
#endif
ok_parse = parse_rhs(rhs, first, last, context, attr_, attr_
, mpl::bool_
< ( RHS::has_action
&& !ExplicitAttrPropagation::value
)
>()
);
}
if (ok_parse)
{
// do up-stream transformation, this integrates the results
// back into the original attribute value, if appropriate
transform::post(attr, std::forward<transform_attr>(attr_));
}
return ok_parse;
}
};
}}}}
#endif

View File

@@ -1,454 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM)
#define BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/spirit/home/x3/core/error_handler_types.hpp>
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/directive/expect.hpp>
#include <boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp>
#if defined(BOOST_SPIRIT_X3_DEBUG)
#include <boost/spirit/home/x3/nonterminal/simple_trace.hpp>
#endif
#include <iterator>
#include <type_traits>
#include <concepts>
#include <utility>
namespace boost::spirit::x3
{
template <typename ID, typename Attribute = unused_type, bool force_attribute = false>
struct rule;
struct parse_pass_context_tag;
namespace detail
{
template <typename ID>
struct rule_id {};
// Placeholder type to detect whether the default `parse_rule(...)` is called
enum struct default_parse_rule_result : bool {};
template <typename ID, typename Context>
constexpr bool context_has_rule_id = !std::is_same_v<
std::remove_cvref_t<decltype(x3::get<ID>(std::declval<Context const&>()))>,
unused_type
>;
} // detail
// The default `parse_rule` definition.
//
// This overload will only be selected when there exists no user-defined
// definition for `parse_rule`.
//
// When a user invokes `BOOST_SPIRIT_X3_DEFINE_`, an unconstrained overload
// is generated at the user's namespace scope. It will never conflict with
// this (vvvvv) overload, as the generated one is never directly called with
// a context containing `ID`.
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
requires detail::context_has_rule_id<ID, Context>
[[nodiscard]] constexpr detail::default_parse_rule_result
parse_rule(
detail::rule_id<ID>,
It& first, Se const& last,
Context const& context, Attribute& attr
)
{
auto&& rule_ = x3::get<ID>(context);
return static_cast<detail::default_parse_rule_result>(
rule_.parse(first, last, context, unused, attr)
);
}
// This overload is selected only when the user *declares* their `parse_rule`
// in the user's namespace scope AND the function definition is not found.
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
requires (!detail::context_has_rule_id<ID, Context>)
constexpr void
parse_rule(
detail::rule_id<ID>,
It&, Se const&,
Context const&, Attribute&
) = delete; // BOOST_SPIRIT_X3_DEFINE undefined for this rule
} // boost::spirit::x3
namespace boost::spirit::x3::detail
{
#if defined(BOOST_SPIRIT_X3_DEBUG)
// TODO: This should be customizable by users
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
struct scoped_debug
{
scoped_debug(
char const* rule_name,
It const& first, Se const& last,
Attribute const& attr,
bool const& parse_ok
)
: parse_ok(parse_ok)
, rule_name(rule_name)
, first(first)
, last(last)
, attr(attr)
, f(detail::get_simple_trace())
{
f(first, last, attr, pre_parse, rule_name);
}
~scoped_debug()
{
f(first, last, attr, parse_ok ? successful_parse : failed_parse, rule_name);
}
bool const& parse_ok;
char const* rule_name = nullptr;
It const& first;
Se const& last;
Attribute const& attr;
detail::simple_trace_type& f;
};
#endif
template <typename ID, typename It, typename Se, typename Context>
concept HasImmutableOnErrorOverload =
std::forward_iterator<It> &&
std::sentinel_for<Se, It> &&
requires(ID& id) { // Note: `ID` should be non-const
id.on_error(
std::declval<It const&>(),
std::declval<Se const&>(),
std::declval<expectation_failure<It> const&>(),
std::declval<Context const&>()
);
};
template <typename ID, typename It, typename Se, typename Context>
concept HasMutableOnErrorOverload =
std::forward_iterator<It> &&
std::sentinel_for<Se, It> &&
requires(ID& id) { // Note: `ID` should be non-const
id.on_error(
std::declval<It&>(),
std::declval<Se&>(),
std::declval<expectation_failure<It> const&>(),
std::declval<Context const&>()
);
};
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Context>
struct has_on_error : std::false_type {};
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Context>
requires HasImmutableOnErrorOverload<ID, It, Se, Context>
struct has_on_error<ID, It, Se, Context> : std::true_type
{
// We intentionally make this hard error to prevent error-prone definition
static_assert(
std::convertible_to<
decltype(std::declval<ID&>().on_error(
std::declval<It const&>(),
std::declval<Se const&>(),
std::declval<expectation_failure<It> const&>(),
std::declval<Context const&>()
)),
x3::error_handler_result
>,
"The return type of `on_error` should be convertible to `x3::error_handler_result`."
);
};
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Context>
requires
(!HasImmutableOnErrorOverload<ID, It, Se, Context>) &&
HasMutableOnErrorOverload<ID, It, Se, Context>
struct has_on_error<ID, It, Se, Context> : std::false_type
{
// Historically, Spirit has passed mutable lvalue references of the iterators *as-is*
// to the `on_success`/`on_error` handlers. This behavior was simply a mistake, because:
// (1) `on_success`/`on_error` mechanism was designed to be grammar-agnostic, and
// (2) it does not make sense to modify the grammar-specific iterator on the
// grammar-agnostic callback.
//
// Furthermore, any modification to X3's internal iterator variables may invoke
// undefined behavior, since we never provide any kind of guarantee on how the
// intermediate iterator variables are processed in X3's implementation details.
static_assert(
false,
"The `on_error` callback should only accept const reference or passed-by-value iterators."
);
};
template <typename ID, typename It, typename Se, typename Attribute, typename Context>
concept HasImmutableOnSuccessOverload =
std::forward_iterator<It> &&
std::sentinel_for<Se, It> &&
requires(ID& id) { // Note: `ID` should be non-const
id.on_success(
std::declval<It const&>(),
std::declval<Se const&>(),
std::declval<Attribute&>(),
std::declval<Context const&>()
);
};
template <typename ID, typename It, typename Se, typename Attribute, typename Context>
concept HasMutableOnSuccessOverload =
std::forward_iterator<It> &&
std::sentinel_for<Se, It> &&
requires(ID& id) { // Note: `ID` should be non-const
id.on_success(
std::declval<It&>(),
std::declval<Se&>(),
std::declval<Attribute&>(),
std::declval<Context const&>()
);
};
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename Context>
struct has_on_success : std::false_type {};
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename Context>
requires HasImmutableOnSuccessOverload<ID, It, Se, Attribute, Context>
struct has_on_success<ID, It, Se, Attribute, Context> : std::true_type
{
// We intentionally make this hard error to prevent error-prone definition
static_assert(
std::is_void_v<
decltype(std::declval<ID&>().on_success(
std::declval<It const&>(),
std::declval<Se const&>(),
std::declval<Attribute&>(),
std::declval<Context const&>()
))
>,
"The return type of `on_success` should be `void`."
);
};
template <typename ID, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename Context>
requires
(!HasImmutableOnSuccessOverload<ID, It, Se, Attribute, Context>) &&
HasMutableOnSuccessOverload<ID, It, Se, Attribute, Context>
struct has_on_success<ID, It, Se, Attribute, Context> : std::false_type
{
// For details, see the comments on `has_on_error`.
static_assert(
false,
"The `on_success` callback should only accept const reference or passed-by-value iterators."
);
};
template <typename Attribute, typename ID, bool SkipDefinitionInjection = false>
struct rule_parser
{
template <
typename RHS, std::forward_iterator It, std::sentinel_for<It> Se,
typename Context, typename RContext, typename ActualAttribute
>
[[nodiscard]] static constexpr bool
parse_rhs(
RHS const& rhs, It& first, Se const& last,
Context const& context, RContext& rcontext, ActualAttribute& attr
) // never noexcept; requires complex handling
{
It start = first;
// See if the user has a BOOST_SPIRIT_DEFINE for this rule
using parse_rule_result_type = decltype(
parse_rule( // ADL
std::declval<detail::rule_id<ID>>(), first, last,
std::declval<decltype(x3::make_unique_context<ID>(rhs, context))>(),
std::declval<Attribute&>()
)
);
constexpr bool is_default_parse_rule = std::is_same_v<
parse_rule_result_type, default_parse_rule_result
>;
bool ok;
if constexpr (SkipDefinitionInjection || !is_default_parse_rule)
{
ok = rhs.parse(first, last, context, rcontext, attr);
}
else
{
// If there is no BOOST_SPIRIT_DEFINE for this rule,
// we'll make a context for this rule tagged by its ID
// so we can extract the rule later on in the default
// parse_rule function.
auto rule_id_context = x3::make_unique_context<ID>(rhs, context);
ok = rhs.parse(first, last, rule_id_context, rcontext, attr);
}
// Note: this check uses `It, It` because the value is actually iterator-iterator pair
if constexpr (has_on_success<ID, It, It, ActualAttribute, Context>::value)
{
if (!ok) return false;
x3::skip_over(start, first, context);
bool pass = true;
ID().on_success(
std::as_const(start), std::as_const(first), attr,
x3::make_context<parse_pass_context_tag>(pass, context)
);
return pass;
}
else
{
return ok;
}
}
template <
typename RHS, std::forward_iterator It, std::sentinel_for<It> Se,
typename Context, typename RContext, typename ActualAttribute
>
[[nodiscard]] static constexpr bool
parse_rhs_with_on_error(
RHS const& rhs, It& first, Se const& last,
Context const& context, RContext& rcontext, ActualAttribute& attr
) // never noexcept; requires complex handling
{
while (true)
{
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
try
#endif
{
if (rule_parser::parse_rhs(rhs, first, last, context, rcontext, attr))
{
return true;
}
}
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
catch (expectation_failure<It> const& x) {
#else
if (x3::has_expectation_failure(context)) {
auto const& x = x3::get_expectation_failure(context);
#endif
// X3 developer note: don't forget to sync this implementation with x3::guard
switch (ID{}.on_error(std::as_const(first), std::as_const(last), x, context))
{
case error_handler_result::fail:
x3::clear_expectation_failure(context);
return false;
case error_handler_result::retry:
continue;
case error_handler_result::accept:
return true;
case error_handler_result::rethrow:
#if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
throw;
#else
return false; // TODO: design decision required
#endif
}
}
return false;
}
}
template <
bool ForceAttribute,
typename RHS, std::forward_iterator It, std::sentinel_for<It> Se,
typename Context, typename ActualAttribute
>
[[nodiscard]] static constexpr bool
call_rule_definition(
RHS const& rhs, char const* rule_name,
It& first, Se const& last,
Context const& context, ActualAttribute& attr
)
{
// Do down-stream transformation, provides attribute for rhs parser
using transform = traits::transform_attribute<ActualAttribute, Attribute, parser_id>;
using transform_attr = typename transform::type;
transform_attr attr_ = transform::pre(attr);
// Creates a place to hold the result of parse_rhs
// called inside the following scope.
bool parse_ok;
{
#ifdef BOOST_SPIRIT_X3_DEBUG
// Create a scope to cause the dbg variable below (within
// the #if...#endif) to call it's DTOR before any
// modifications are made to the attribute, attr_ passed
// to parse_rhs (such as might be done in
// transform::post when, for example,
// ActualAttribute is a recursive variant).
scoped_debug<It, Se, transform_attr>
dbg(rule_name, first, last, attr_, parse_ok);
#else
(void)rule_name;
#endif
// In theory, these calls can be overloaded using tag dispatches.
// However we should get over those legacy technique already, as they
// lead to enormous amount of call stack, generating unreadable
// compilation errors. Even when we have a single layer of tag dispatch,
// we should generally avoid it because the "true_type/false_type"
// argument placed at the very last param of the overload is virtually
// indistinguishable in messages and has serious QoL issue in debuggers.
constexpr bool rhs_has_on_error = has_on_error<ID, It, Se, Context>::value;
// The existence of semantic action inhibits attribute materialization
// _unless_ it is explicitly required by the user (primarily via `%=`).
if constexpr (RHS::has_action && !ForceAttribute)
{
if constexpr (rhs_has_on_error)
{
parse_ok = rule_parser::parse_rhs_with_on_error(
rhs, first, last, context, attr_ /* rcontext */, unused
);
}
else
{
parse_ok = rule_parser::parse_rhs(
rhs, first, last, context, attr_ /* rcontext */, unused
);
}
}
else // attribute is required
{
if constexpr (rhs_has_on_error)
{
parse_ok = rule_parser::parse_rhs_with_on_error(
rhs, first, last, context, attr_ /* rcontext */, attr_
);
}
else
{
parse_ok = rule_parser::parse_rhs(
rhs, first, last, context, attr_ /* rcontext */, attr_
);
}
}
}
if (parse_ok)
{
// do up-stream transformation, this integrates the results
// back into the original attribute value, if appropriate
transform::post(attr, std::forward<transform_attr>(attr_));
}
return parse_ok;
}
};
} // boost::spirit::x3::detail
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,34 +10,24 @@
#include <boost/spirit/home/x3/support/traits/transform_attribute.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace x3
{
namespace detail
{
struct parser_id;
} // detail
struct parser_id;
template <typename Exposed, typename Transformed>
requires std::is_assignable_v<Exposed&, Transformed&&>
struct default_transform_attribute
{
using type = Transformed;
typedef Transformed type;
static constexpr Transformed pre(Exposed&)
noexcept(std::is_nothrow_default_constructible_v<Transformed>)
{
return Transformed{};
}
static Transformed pre(Exposed&) { return Transformed(); }
template <typename TransformedT>
static constexpr void post(Exposed& val, TransformedT&& attribute)
noexcept(noexcept(traits::move_to(std::forward<TransformedT>(attribute), val)))
static void post(Exposed& val, Transformed&& attribute)
{
traits::move_to(std::forward<TransformedT>(attribute), val);
traits::move_to(std::forward<Transformed>(attribute), val);
}
};
@@ -46,59 +35,58 @@ namespace boost::spirit::x3
template <typename Attribute>
struct default_transform_attribute<Attribute, Attribute>
{
using type = Attribute&;
static constexpr Attribute& pre(Attribute& val) noexcept { return val; }
static constexpr void post(Attribute&, Attribute const&) noexcept {}
typedef Attribute& type;
static Attribute& pre(Attribute& val) { return val; }
static void post(Attribute&, Attribute const&) {}
};
// main specialization for x3
template <typename Exposed, typename Transformed, typename Enable = void>
requires std::is_assignable_v<Exposed&, Transformed&&>
struct transform_attribute
: default_transform_attribute<Exposed, Transformed> {};
: default_transform_attribute<Exposed, Transformed> {};
// unused_type needs some special handling as well
template <>
struct transform_attribute<unused_type, unused_type>
{
using type = unused_type;
static constexpr unused_type pre(unused_type) noexcept { return unused; }
static constexpr void post(unused_type, unused_type) noexcept {}
typedef unused_type type;
static unused_type pre(unused_type) { return unused; }
static void post(unused_type, unused_type) {}
};
template <>
struct transform_attribute<unused_type const, unused_type>
: transform_attribute<unused_type, unused_type> {};
: transform_attribute<unused_type, unused_type> {};
template <typename Attribute>
struct transform_attribute<unused_type, Attribute>
: transform_attribute<unused_type, unused_type> {};
: transform_attribute<unused_type, unused_type> {};
template <typename Attribute>
struct transform_attribute<unused_type const, Attribute>
: transform_attribute<unused_type, unused_type> {};
: transform_attribute<unused_type, unused_type> {};
template <typename Attribute>
struct transform_attribute<Attribute, unused_type>
: transform_attribute<unused_type, unused_type> {};
: transform_attribute<unused_type, unused_type> {};
template <typename Attribute>
struct transform_attribute<Attribute const, unused_type>
: transform_attribute<unused_type, unused_type> {};
} // boost::spirit::x3
: transform_attribute<unused_type, unused_type> {};
}}}
///////////////////////////////////////////////////////////////////////////////
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename Exposed, typename Transformed>
requires std::is_assignable_v<Exposed&, Transformed&&>
struct transform_attribute<Exposed, Transformed, x3::detail::parser_id>
: x3::transform_attribute<Exposed, Transformed>
struct transform_attribute<Exposed, Transformed, x3::parser_id>
: x3::transform_attribute<Exposed, Transformed>
{
static_assert(!std::is_reference_v<Exposed>, "Exposed cannot be a reference type");
static_assert(!std::is_reference_v<Transformed>, "Transformed cannot be a reference type");
static_assert(!std::is_reference<Exposed>::value,
"Exposed cannot be a reference type");
static_assert(!std::is_reference<Transformed>::value,
"Transformed cannot be a reference type");
};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,330 +7,254 @@
#if !defined(BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM)
#define BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM
#include <boost/spirit/home/x3/nonterminal/detail/rule_parser.hpp>
#include <boost/spirit/home/x3/nonterminal/detail/rule.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/variadic/elem.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/config/helper_macros.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
#if !defined(BOOST_SPIRIT_X3_NO_RTTI)
#include <typeinfo>
#endif
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename ID, X3Subject RHS, typename Attribute, bool ForceAttribute, bool SkipDefinitionInjection = false>
struct rule_definition : parser<rule_definition<ID, RHS, Attribute, ForceAttribute, SkipDefinitionInjection>>
// default parse_rule implementation
template <typename ID, typename Iterator
, typename Context, typename ActualAttribute>
inline detail::default_parse_rule_result
parse_rule(
detail::rule_id<ID>
, Iterator& first, Iterator const& last
, Context const& context, ActualAttribute& attr)
{
using this_type = rule_definition<ID, RHS, Attribute, ForceAttribute, SkipDefinitionInjection>;
using id = ID;
using rhs_type = RHS;
using lhs_type = rule<ID, Attribute, ForceAttribute>;
using attribute_type = Attribute;
static_assert(!is_same<decltype(x3::get<ID>(context)), unused_type>::value,
"BOOST_SPIRIT_DEFINE undefined for this rule.");
return x3::get<ID>(context).parse(first, last, context, unused, attr);
}
static constexpr bool has_attribute = !std::is_same_v<Attribute, unused_type>;
static constexpr bool handles_container = traits::is_container<Attribute>::value;
static constexpr bool force_attribute = ForceAttribute;
template <typename ID, typename RHS, typename Attribute, bool force_attribute_, bool skip_definition_injection = false>
struct rule_definition : parser<rule_definition<ID, RHS, Attribute, force_attribute_, skip_definition_injection>>
{
typedef rule_definition<ID, RHS, Attribute, force_attribute_, skip_definition_injection> this_type;
typedef ID id;
typedef RHS rhs_type;
typedef rule<ID, Attribute, force_attribute_> lhs_type;
typedef Attribute attribute_type;
template <typename RHS_T>
requires std::is_constructible_v<RHS, RHS_T>
constexpr rule_definition(RHS_T&& rhs, char const* name)
noexcept(std::is_nothrow_constructible_v<RHS, RHS_T>)
: rhs(std::forward<RHS_T>(rhs))
, name(name)
{}
static bool const has_attribute =
!is_same<Attribute, unused_type>::value;
static bool const handles_container =
traits::is_container<Attribute>::value;
static bool const force_attribute =
force_attribute_;
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute_>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, unused_type, Attribute_& attr) const
// never noexcept; requires very complex implementation details
constexpr rule_definition(RHS const& rhs, char const* name)
: rhs(rhs), name(name) {}
template <typename Iterator, typename Context, typename Attribute_>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute_& attr) const
{
return detail::rule_parser<attribute_type, ID, SkipDefinitionInjection>
::template call_rule_definition<ForceAttribute>(
rhs, name, first, last, context, attr
);
return detail::rule_parser<attribute_type, ID, skip_definition_injection>
::call_rule_definition(
rhs, name, first, last
, context
, attr
, mpl::bool_<force_attribute>());
}
RHS rhs;
char const* name = "unnamed";
char const* name;
};
template <typename ID, typename Attribute, bool ForceAttribute>
struct rule : parser<rule<ID, Attribute, ForceAttribute>>
template <typename ID, typename Attribute, bool force_attribute_>
struct rule : parser<rule<ID, Attribute, force_attribute_>>
{
static_assert(!std::is_reference_v<Attribute>, "Reference qualifier on rule attribute type is meaningless");
static_assert(!std::is_reference<Attribute>::value,
"Reference qualifier on rule attribute type is meaningless");
using id = ID;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<std::remove_const_t<Attribute>, unused_type>;
static constexpr bool handles_container = traits::is_container<Attribute>::value;
static constexpr bool force_attribute = ForceAttribute;
typedef ID id;
typedef Attribute attribute_type;
static bool const has_attribute =
!std::is_same<std::remove_const_t<Attribute>, unused_type>::value;
static bool const handles_container =
traits::is_container<Attribute>::value;
static bool const force_attribute = force_attribute_;
#if !defined(BOOST_SPIRIT_X3_NO_RTTI)
rule() : name(typeid(rule).name()) {}
#else
constexpr rule() noexcept : name("unnamed") {}
constexpr rule() : name("unnamed") {}
#endif
constexpr rule(char const* name) noexcept
: name(name)
{}
constexpr rule(char const* name)
: name(name) {}
constexpr rule(rule const& r) noexcept
: name(r.name)
constexpr rule(rule const& r)
: name(r.name)
{
// Assert that we are not copying an unitialized static rule. If
// the static is in another TU, it may be initialized after we copy
// it. If so, its name member will be nullptr.
BOOST_ASSERT_MSG(r.name != nullptr, "uninitialized rule"); // static initialization order fiasco
BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco
}
template <X3Subject RHS>
[[nodiscard]] constexpr rule_definition<ID, as_parser_plain_t<RHS>, Attribute, ForceAttribute>
operator=(RHS&& rhs) const&
noexcept(
is_parser_nothrow_castable_v<RHS> &&
std::is_nothrow_constructible_v<
rule_definition<ID, as_parser_plain_t<RHS>, Attribute, ForceAttribute>,
as_parser_t<RHS>, char const*
>
)
template <typename RHS>
constexpr rule_definition<
ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_>
operator=(RHS const& rhs) const&
{
return { as_parser(std::forward<RHS>(rhs)), name };
return { as_parser(rhs), name };
}
template <X3Subject RHS>
[[nodiscard]] constexpr rule_definition<ID, as_parser_plain_t<RHS>, Attribute, true>
operator%=(RHS&& rhs) const&
noexcept(
is_parser_nothrow_castable_v<RHS> &&
std::is_nothrow_constructible_v<
rule_definition<ID, as_parser_plain_t<RHS>, Attribute, true>,
as_parser_t<RHS>, char const*
>
)
template <typename RHS>
constexpr rule_definition<
ID, typename extension::as_parser<RHS>::value_type, Attribute, true>
operator%=(RHS const& rhs) const&
{
return { as_parser(std::forward<RHS>(rhs)), name };
return { as_parser(rhs), name };
}
// When a rule placeholder constructed and immediately consumed it cannot be used recursively,
// that's why the rule definition injection into a parser context can be skipped.
// This optimization has a huge impact on compile times because immediate rules are commonly
// used to cast an attribute like `as`/`attr_cast` does in Qi.
template <X3Subject RHS>
[[nodiscard]] constexpr rule_definition<ID, as_parser_plain_t<RHS>, Attribute, ForceAttribute, true>
operator=(RHS&& rhs) const&&
noexcept(
is_parser_nothrow_castable_v<RHS> &&
std::is_nothrow_constructible_v<
rule_definition<ID, as_parser_plain_t<RHS>, Attribute, ForceAttribute, true>,
as_parser_t<RHS>, char const*
>
)
template <typename RHS>
constexpr rule_definition<
ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_, true>
operator=(RHS const& rhs) const&&
{
return { as_parser(std::forward<RHS>(rhs)), name };
return { as_parser(rhs), name };
}
template <X3Subject RHS>
[[nodiscard]] constexpr rule_definition<ID, as_parser_plain_t<RHS>, Attribute, true, true>
operator%=(RHS&& rhs) const&&
noexcept(
is_parser_nothrow_castable_v<RHS> &&
std::is_nothrow_constructible_v<
rule_definition<ID, as_parser_plain_t<RHS>, Attribute, true, true>,
as_parser_t<RHS>, char const*
>
)
template <typename RHS>
constexpr rule_definition<
ID, typename extension::as_parser<RHS>::value_type, Attribute, true, true>
operator%=(RHS const& rhs) const&&
{
return { as_parser(std::forward<RHS>(rhs)), name };
return { as_parser(rhs), name };
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Exposed>
requires (!std::is_same_v<std::remove_const_t<Exposed>, unused_type>)
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, unused_type, Exposed& exposed_attr) const
// never noexcept; requires very complex implementation details
template <typename Iterator, typename Context, typename Attribute_>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute_& attr) const
{
static_assert(has_attribute, "A rule must have an attribute. Check your rule definition.");
static_assert(has_attribute,
"The rule does not have an attribute. Check your parser.");
static_assert(
traits::Transformable<Exposed, Attribute, detail::parser_id>,
"Attribute type mismatch; the rule's attribute is not assignable to "
"the exposed attribute, and no eligible specialization of "
"`x3::traits::transform_attribute` was found."
);
using transform = traits::transform_attribute<
Attribute_, attribute_type, parser_id>;
using transform = traits::transform_attribute<Exposed, Attribute, detail::parser_id>;
using transformed_type = typename transform::type;
transformed_type transformed_attr = transform::pre(exposed_attr);
using transform_attr = typename transform::type;
transform_attr attr_ = transform::pre(attr);
// ADL
if (static_cast<bool>(parse_rule(detail::rule_id<ID>{}, first, last, context, transformed_attr))) {
transform::post(exposed_attr, std::forward<transformed_type>(transformed_attr));
if (parse_rule(detail::rule_id<ID>{}, first, last, context, attr_)) {
transform::post(attr, std::forward<transform_attr>(attr_));
return true;
}
return false;
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, unused_type, unused_type) const
// never noexcept; requires very complex implementation details
template <typename Iterator, typename Context>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, unused_type) const
{
// make sure we pass exactly the rule attribute type
attribute_type no_attr; // default-initialize
// ADL
return static_cast<bool>(parse_rule(detail::rule_id<ID>{}, first, last, context, no_attr));
attribute_type no_attr{};
return parse_rule(detail::rule_id<ID>{}, first, last, context, no_attr);
}
char const* name = "unnamed";
char const* name;
};
namespace traits
{
template <typename T, typename Enable = void>
struct is_rule : std::false_type {};
struct is_rule : mpl::false_ {};
template <typename T>
constexpr bool is_rule_v = is_rule<T>::value;
template <typename ID, typename Attribute, bool force_attribute>
struct is_rule<rule<ID, Attribute, force_attribute>> : mpl::true_ {};
template <typename ID, typename Attribute, bool ForceAttribute>
struct is_rule<rule<ID, Attribute, ForceAttribute>> : std::true_type {};
template <typename ID, typename Attribute, typename RHS, bool ForceAttribute, bool SkipDefinitionInjection>
struct is_rule<rule_definition<ID, RHS, Attribute, ForceAttribute, SkipDefinitionInjection>> : std::true_type {};
template <typename ID, typename Attribute, typename RHS, bool force_attribute, bool skip_definition_injection>
struct is_rule<rule_definition<ID, RHS, Attribute, force_attribute, skip_definition_injection>> : mpl::true_ {};
}
template <typename T>
requires traits::is_rule_v<T>
struct get_info<T>
struct get_info<T, typename enable_if<traits::is_rule<T>>::type>
{
using result_type = std::string;
[[nodiscard]] std::string operator()(T const& r) const
typedef std::string result_type;
std::string operator()(T const& r) const
{
BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco
return r.name? r.name : "uninitialized";
}
};
// -------------------------------------------------------------
#define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \
template <typename Iterator, typename Context> \
bool parse_rule( \
::boost::spirit::x3::detail::rule_id<rule_type::id> \
, Iterator& first, Iterator const& last \
, Context const& context, rule_type::attribute_type& attr); \
/***/
#define BOOST_SPIRIT_X3_DEPRECATED_MACRO_WARN_I(x) _Pragma(#x)
#define BOOST_SPIRIT_X3_DEPRECATED_MACRO_WARN(msg) BOOST_SPIRIT_X3_DEPRECATED_MACRO_WARN_I(message(msg))
#define BOOST_SPIRIT_DECLARE(...) BOOST_PP_SEQ_FOR_EACH( \
BOOST_SPIRIT_DECLARE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
/***/
#define BOOST_SPIRIT_X3_DECLARE_(r, constexpr_, rule_type) \
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context> \
[[nodiscard]] constexpr_ bool \
parse_rule( \
::boost::spirit::x3::detail::rule_id<typename std::remove_cvref_t<rule_type>::id>, \
It& first, Se const& last, \
Context const& context, typename std::remove_cvref_t<rule_type>::attribute_type& attr \
);
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
#define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \
using BOOST_PP_CAT(rule_name, _synonym) = decltype(rule_name); \
template <typename Iterator, typename Context> \
inline bool parse_rule( \
::boost::spirit::x3::detail::rule_id<BOOST_PP_CAT(rule_name, _synonym)::id> \
, Iterator& first, Iterator const& last \
, Context const& context, BOOST_PP_CAT(rule_name, _synonym)::attribute_type& attr) \
{ \
using rule_t = BOOST_JOIN(rule_name, _synonym); \
return ::boost::spirit::x3::detail \
::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \
::call_rule_definition( \
BOOST_JOIN(rule_name, _def), rule_name.name \
, first, last, context, attr \
, ::boost::mpl::bool_<rule_t::force_attribute>()); \
} \
/***/
#else
#define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \
template <typename Iterator, typename Context> \
inline bool parse_rule( \
::boost::spirit::x3::detail::rule_id<decltype(rule_name)::id> \
, Iterator& first, Iterator const& last \
, Context const& context, decltype(rule_name)::attribute_type& attr) \
{ \
using rule_t = decltype(rule_name); \
return ::boost::spirit::x3::detail \
::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \
::call_rule_definition( \
BOOST_JOIN(rule_name, _def), rule_name.name \
, first, last, context, attr \
, ::boost::mpl::bool_<rule_t::force_attribute>()); \
} \
/***/
#endif
#define BOOST_SPIRIT_X3_DECLARE(rule_type) BOOST_SPIRIT_X3_DECLARE_(,, rule_type)
#define BOOST_SPIRIT_X3_DECLARE_CONSTEXPR(rule_type) BOOST_SPIRIT_X3_DECLARE_(, constexpr, rule_type)
#define BOOST_SPIRIT_DEFINE(...) BOOST_PP_SEQ_FOR_EACH( \
BOOST_SPIRIT_DEFINE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
/***/
// NB: This can't be `constexpr`, because a constexpr declaration
// cannot be used with explicit template instantiation. We simply
// can't drop (legit) use cases of `BOOST_SPIRIT_INSTANTIATE`, so
// this is a pure technical limitation. If you need `constexpr`
// support in your rule, use `BOOST_SPIRIT_X3_DECLARE_CONSTEXPR`.
#define BOOST_SPIRIT_DECLARE(...) \
BOOST_SPIRIT_X3_DEPRECATED_MACRO_WARN( \
"Use of variadic arguments with `BOOST_SPIRIT_DECLARE` is deprecated due to the heavy compile-time cost of " \
"`BOOST_PP_SEQ_*`. Just apply `BOOST_SPIRIT_X3_DECLARE` for each of your rules." \
) \
BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_X3_DECLARE_,, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define BOOST_SPIRIT_INSTANTIATE(rule_type, Iterator, Context) \
template bool parse_rule<Iterator, Context>( \
::boost::spirit::x3::detail::rule_id<rule_type::id> \
, Iterator& first, Iterator const& last \
, Context const& context, rule_type::attribute_type&); \
/***/
#define BOOST_SPIRIT_X3_DEFINE_(r, constexpr_, rule_name) \
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Context> \
[[nodiscard]] constexpr_ bool \
parse_rule( \
::boost::spirit::x3::detail::rule_id<std::remove_cvref_t<decltype(rule_name)>::id>, \
It& first, Se const& last, \
Context const& context, \
std::remove_cvref_t<decltype(rule_name)>::attribute_type& attr \
) { \
using rule_t = std::remove_cvref_t<decltype(rule_name)>; \
return ::boost::spirit::x3::detail::rule_parser< \
typename rule_t::attribute_type, typename rule_t::id, true \
>::call_rule_definition<rule_t::force_attribute>( \
BOOST_JOIN(rule_name, _def), rule_name.name, \
first, last, context, attr \
); \
}
#define BOOST_SPIRIT_X3_DEFINE(rule_type) BOOST_SPIRIT_X3_DEFINE_(,, rule_type)
#define BOOST_SPIRIT_X3_DEFINE_CONSTEXPR(rule_type) BOOST_SPIRIT_X3_DEFINE_(, constexpr, rule_type)
// NB: This can't be `constexpr`, because a constexpr declaration
// cannot be used with explicit template instantiation. We simply
// can't drop (legit) use cases of `BOOST_SPIRIT_INSTANTIATE`, so
// this is a pure technical limitation. If you need `constexpr`
// support in your rule, use `BOOST_SPIRIT_X3_DEFINE_CONSTEXPR`.
#define BOOST_SPIRIT_DEFINE(...) \
BOOST_SPIRIT_X3_DEPRECATED_MACRO_WARN( \
"Use of variadic arguments with `BOOST_SPIRIT_DEFINE` is deprecated due to the heavy compile-time cost of " \
"`BOOST_PP_SEQ_*`. Just apply `BOOST_SPIRIT_X3_DEFINE` for each of your rules." \
) \
BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_X3_DEFINE_,, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
namespace detail
{
template <typename RuleT, std::forward_iterator It, typename A, typename B = void>
struct instantiate_macro_helper
{
using rule_type = RuleT;
using iterator_type = It;
// Old API:
// A => Context
// B => void
// New API:
// A => Se
// B => Context
using sentinel_type = std::conditional_t<std::is_void_v<B>, It, A>;
static_assert(std::sentinel_for<sentinel_type, It>);
using context_type = std::conditional_t<std::is_void_v<B>, A, B>;
};
} // detail
#define BOOST_SPIRIT_X3_INSTANTIATE_(rule_type, It, Se, Context) \
template bool parse_rule<It, Se, Context>( \
::boost::spirit::x3::detail::rule_id<typename std::remove_cvref_t<rule_type>::id>, \
It&, Se const&, Context const&, \
typename std::remove_cvref_t<rule_type>::attribute_type& \
);
#define BOOST_SPIRIT_X3_INSTANTIATE_WRAP(...) __VA_ARGS__
// NB: This can't be `constexpr`, because a constexpr declaration
// cannot be used with explicit template instantiation.
#define BOOST_SPIRIT_X3_INSTANTIATE(...) \
BOOST_SPIRIT_X3_INSTANTIATE_( \
BOOST_SPIRIT_X3_INSTANTIATE_WRAP(typename ::boost::spirit::x3::detail::instantiate_macro_helper<__VA_ARGS__>::rule_type), \
BOOST_SPIRIT_X3_INSTANTIATE_WRAP(typename ::boost::spirit::x3::detail::instantiate_macro_helper<__VA_ARGS__>::iterator_type), \
BOOST_SPIRIT_X3_INSTANTIATE_WRAP(typename ::boost::spirit::x3::detail::instantiate_macro_helper<__VA_ARGS__>::sentinel_type), \
BOOST_SPIRIT_X3_INSTANTIATE_WRAP(typename ::boost::spirit::x3::detail::instantiate_macro_helper<__VA_ARGS__>::context_type) \
)
#define BOOST_SPIRIT_INSTANTIATE(...) \
BOOST_SPIRIT_X3_DEPRECATED_MACRO_WARN( \
"Use `BOOST_SPIRIT_X3_INSTANTIATE`. `BOOST_SPIRIT_INSTANTIATE` is deprecated because " \
"the name was not correctly prefixed with `X3`." \
) \
BOOST_SPIRIT_X3_INSTANTIATE(__VA_ARGS__)
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
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)
@@ -55,7 +54,7 @@ namespace boost { namespace spirit { namespace x3
};
template <typename T, typename Encoding, typename BoolPolicies = bool_policies<T>>
struct literal_bool_parser : parser<literal_bool_parser<T, Encoding, BoolPolicies>>
struct literal_bool_parser : parser<bool_parser<T, Encoding, BoolPolicies>>
{
typedef Encoding encoding;
typedef T attribute_type;
@@ -115,7 +114,7 @@ namespace boost { namespace spirit { namespace x3
constexpr false_type false_ = { false };
}
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
namespace standard_wide
{
typedef bool_parser<bool, char_encoding::standard_wide> bool_type;

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
Copyright (c) 2009 Hartmut Kaiser
Copyright (c) 2014 Joel de Guzman
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)
@@ -12,22 +11,19 @@
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <string_view>
#include <iterator>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
///////////////////////////////////////////////////////////////////////////
// Default boolean policies
///////////////////////////////////////////////////////////////////////////
template <typename T = bool>
struct bool_policies
{
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompare>
[[nodiscard]] static constexpr bool
parse_true(It& first, Se const& last, Attribute& attr_, CaseCompare const& case_compare)
noexcept(std::is_nothrow_constructible_v<Attribute, T>)
template <typename Iterator, typename Attribute, typename CaseCompare>
static bool
parse_true(Iterator& first, Iterator const& last, Attribute& attr_, CaseCompare const& case_compare)
{
using namespace std::string_view_literals;
if (detail::string_parse("true"sv, first, last, unused, case_compare))
if (detail::string_parse("true", first, last, unused, case_compare))
{
traits::move_to(T(true), attr_); // result is true
return true;
@@ -35,13 +31,11 @@ namespace boost::spirit::x3
return false;
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompare>
[[nodiscard]] static constexpr bool
parse_false(It& first, Se const& last, Attribute& attr_, CaseCompare const& case_compare)
noexcept(std::is_nothrow_constructible_v<Attribute, T>)
template <typename Iterator, typename Attribute, typename CaseCompare>
static bool
parse_false(Iterator& first, Iterator const& last, Attribute& attr_, CaseCompare const& case_compare)
{
using namespace std::string_view_literals;
if (detail::string_parse("false"sv, first, last, unused, case_compare))
if (detail::string_parse("false", first, last, unused, case_compare))
{
traits::move_to(T(false), attr_); // result is false
return true;
@@ -49,6 +43,6 @@ namespace boost::spirit::x3
return false;
}
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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)
@@ -12,11 +11,11 @@
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/support/numeric_utils/extract_int.hpp>
#include <string_view>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
// Default (unsigned) real number policies
///////////////////////////////////////////////////////////////////////////
// Default (unsigned) real number policies
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct ureal_policies
{
@@ -73,24 +72,24 @@ namespace boost::spirit::x3
return extract_int<int, 10, 1, -1>::call(first, last, attr_);
}
// The parse_nan() and parse_inf() functions get called whenever
// a number to parse does not start with a digit (after having
// successfully parsed an optional sign).
///////////////////////////////////////////////////////////////////////
// The parse_nan() and parse_inf() functions get called whenever
// a number to parse does not start with a digit (after having
// successfully parsed an optional sign).
//
// The functions should return true if a Nan or Inf has been found. In
// this case the attr should be set to the matched value (NaN or
// Inf). The optional sign will be automatically applied afterwards.
// The functions should return true if a Nan or Inf has been found. In
// this case the attr should be set to the matched value (NaN or
// Inf). The optional sign will be automatically applied afterwards.
//
// The default implementation below recognizes representations of NaN
// and Inf as mandated by the C99 Standard and as proposed for
// inclusion into the C++0x Standard: nan, nan(...), inf and infinity
// (the matching is performed case-insensitively).
// The default implementation below recognizes representations of NaN
// and Inf as mandated by the C99 Standard and as proposed for
// inclusion into the C++0x Standard: nan, nan(...), inf and infinity
// (the matching is performed case-insensitively).
///////////////////////////////////////////////////////////////////////
template <typename Iterator, typename Attribute>
static bool
parse_nan(Iterator& first, Iterator const& last, Attribute& attr_)
{
using namespace std::string_view_literals;
if (first == last)
return false; // end of input reached
@@ -98,7 +97,7 @@ namespace boost::spirit::x3
return false; // not "nan"
// nan[(...)] ?
if (detail::string_parse("nan"sv, "NAN"sv, first, last, unused))
if (detail::string_parse("nan", "NAN", first, last, unused))
{
if (first != last && *first == '(')
{
@@ -122,8 +121,6 @@ namespace boost::spirit::x3
static bool
parse_inf(Iterator& first, Iterator const& last, Attribute& attr_)
{
using namespace std::string_view_literals;
if (first == last)
return false; // end of input reached
@@ -131,10 +128,10 @@ namespace boost::spirit::x3
return false; // not "inf"
// inf or infinity ?
if (detail::string_parse("inf"sv, "INF"sv, first, last, unused))
if (detail::string_parse("inf", "INF", first, last, unused))
{
// skip allowed 'inity' part of infinity
(void)detail::string_parse("inity"sv, "INITY"sv, first, last, unused);
detail::string_parse("inity", "INITY", first, last, unused);
attr_ = std::numeric_limits<T>::infinity();
return true;
}
@@ -142,7 +139,9 @@ namespace boost::spirit::x3
}
};
// Default (signed) real number policies
///////////////////////////////////////////////////////////////////////////
// Default (signed) real number policies
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct real_policies : ureal_policies<T>
{
@@ -165,6 +164,6 @@ namespace boost::spirit::x3
{
static bool const expect_dot = true;
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -15,42 +14,42 @@
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/traits/variant_has_substitute.hpp>
#include <boost/spirit/home/x3/support/traits/variant_find_substitute.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
#include <boost/mpl/if.hpp>
#include <boost/fusion/include/front.hpp>
#include <iterator>
#include <boost/type_traits/is_same.hpp>
#include <type_traits>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Left, typename Right>
struct alternative;
} // boost::spirit::x3
}}}
namespace boost::spirit::x3::detail
namespace boost { namespace spirit { namespace x3 { namespace detail
{
struct pass_variant_unused
{
using type = unused_type;
typedef unused_type type;
template <typename T>
[[nodiscard]] static constexpr unused_type
call(T&) noexcept
static unused_type
call(T&)
{
return unused_type{};
return unused_type();
}
};
template <typename Attribute>
struct pass_variant_used
{
using type = Attribute&;
typedef Attribute& type;
[[nodiscard]] static constexpr Attribute&
call(Attribute& v) noexcept
static Attribute&
call(Attribute& v)
{
return v;
}
@@ -59,44 +58,56 @@ namespace boost::spirit::x3::detail
template <>
struct pass_variant_used<unused_type> : pass_variant_unused {};
template <typename Parser, typename Attribute, typename Context, typename Enable = void>
template <typename Parser, typename Attribute, typename Context
, typename Enable = void>
struct pass_parser_attribute
{
using attribute_type = traits::attribute_of_t<Parser, Context>;
using substitute_type = traits::variant_find_substitute_t<Attribute, attribute_type>;
typedef typename
traits::attribute_of<Parser, Context>::type
attribute_type;
typedef typename
traits::variant_find_substitute<Attribute, attribute_type>::type
substitute_type;
using type = std::conditional_t<
std::is_same_v<Attribute, substitute_type>,
Attribute&,
substitute_type
>;
typedef typename
mpl::if_<
is_same<Attribute, substitute_type>
, Attribute&
, substitute_type
>::type
type;
template <typename Attribute_>
requires std::is_same_v<Attribute_, std::remove_reference_t<type>>
[[nodiscard]] static constexpr Attribute_&
call(Attribute_& attribute) noexcept
static Attribute_&
call(Attribute_& attribute, mpl::true_)
{
return attribute;
}
template <typename Attribute_>
requires (!std::is_same_v<Attribute_, std::remove_reference_t<type>>)
[[nodiscard]] static type
call(Attribute_&)
noexcept(std::is_nothrow_default_constructible_v<type>)
static type
call(Attribute_&, mpl::false_)
{
return type{};
return type();
}
template <typename Attribute_>
static type
call(Attribute_& attribute)
{
return call(attribute, is_same<Attribute_, typename remove_reference<type>::type>());
}
};
// Pass non-variant attributes as-is
template <typename Parser, typename Attribute, typename Context, typename Enable = void>
template <typename Parser, typename Attribute, typename Context
, typename Enable = void>
struct pass_non_variant_attribute
{
using type = Attribute&;
typedef Attribute& type;
[[nodiscard]] constexpr static Attribute&
call(Attribute& attribute) noexcept
static Attribute&
call(Attribute& attribute)
{
return attribute;
}
@@ -104,110 +115,80 @@ namespace boost::spirit::x3::detail
// Unwrap single element sequences
template <typename Parser, typename Attribute, typename Context>
requires traits::is_size_one_sequence_v<Attribute>
struct pass_non_variant_attribute<Parser, Attribute, Context>
struct pass_non_variant_attribute<Parser, Attribute, Context,
typename enable_if<traits::is_size_one_sequence<Attribute>>::type>
{
using attr_type = typename std::remove_reference_t<
typename fusion::result_of::front<Attribute>::type
>;
using pass = pass_parser_attribute<Parser, attr_type, Context>;
using type = typename pass::type;
typedef typename remove_reference<
typename fusion::result_of::front<Attribute>::type>::type
attr_type;
typedef pass_parser_attribute<Parser, attr_type, Context> pass;
typedef typename pass::type type;
template <typename Attribute_>
[[nodiscard]] static constexpr type
static type
call(Attribute_& attr)
noexcept(noexcept(pass::call(fusion::front(attr))))
{
return pass::call(fusion::front(attr));
}
};
template <typename Parser, typename Attribute, typename Context>
requires (!traits::is_variant_v<Attribute>)
struct pass_parser_attribute<Parser, Attribute, Context>
struct pass_parser_attribute<Parser, Attribute, Context,
typename enable_if_c<(!traits::is_variant<Attribute>::value)>::type>
: pass_non_variant_attribute<Parser, Attribute, Context>
{};
template <typename Parser, typename Context>
struct pass_parser_attribute<Parser, unused_type, Context>
: pass_variant_unused
{};
: pass_variant_unused {};
template <typename Parser, typename Attribute, typename Context>
struct pass_variant_attribute
: std::conditional_t<
traits::has_attribute_v<Parser, Context>,
pass_parser_attribute<Parser, Attribute, Context>,
pass_variant_unused
>
{};
struct pass_variant_attribute :
mpl::if_c<traits::has_attribute<Parser, Context>::value
, pass_parser_attribute<Parser, Attribute, Context>
, pass_variant_unused>::type
{
};
template <typename L, typename R, typename Attribute, typename Context>
struct pass_variant_attribute<alternative<L, R>, Attribute, Context>
: std::conditional_t<
traits::has_attribute_v<alternative<L, R>, Context>,
pass_variant_used<Attribute>,
pass_variant_unused
>
{};
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
using parse_alternative_pseudo_t = traits::pseudo_attribute<
Context, typename pass_variant_attribute<Parser, Attribute, Context>::type, It, Se
>;
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename Attribute>
constexpr bool is_reference_pseudo_type = std::is_reference_v<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type>;
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires is_reference_pseudo_type<Parser, It, Se, Context, Attribute>
[[nodiscard]] constexpr bool
parse_alternative(
Parser const& p, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attribute
) noexcept(
noexcept(parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::call(
first, last, pass_variant_attribute<Parser, Attribute, Context>::call(attribute)
)) &&
is_nothrow_parsable_v<
Parser, It, Se, Context, RContext,
std::remove_reference_t<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type>
>
)
struct pass_variant_attribute<alternative<L, R>, Attribute, Context> :
mpl::if_c<traits::has_attribute<alternative<L, R>, Context>::value
, pass_variant_used<Attribute>
, pass_variant_unused>::type
{
using pass = pass_variant_attribute<Parser, Attribute, Context>;
using pseudo = traits::pseudo_attribute<Context, typename pass::type, It, Se>;
typename pseudo::type attr_ = pseudo::call(first, last, pass::call(attribute));
return p.parse(first, last, context, rcontext, attr_);
}
};
template <typename Parser, std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext, typename Attribute>
requires (!is_reference_pseudo_type<Parser, It, Se, Context, Attribute>)
[[nodiscard]] constexpr bool
parse_alternative(
Parser const& p, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attribute
) noexcept(
noexcept(parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::call(
first, last, pass_variant_attribute<Parser, Attribute, Context>::call(attribute)
)) &&
is_nothrow_parsable_v<
Parser, It, Se, Context, RContext,
std::remove_reference_t<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type>
> &&
noexcept(traits::move_to(
std::declval<typename parse_alternative_pseudo_t<Parser, It, Se, Context, Attribute>::type&&>(),
attribute
))
)
template <bool Condition>
struct move_if
{
using pass = pass_variant_attribute<Parser, Attribute, Context>;
using pseudo = traits::pseudo_attribute<Context, typename pass::type, It, Se>;
template<typename T1, typename T2>
static void call(T1& /* attr_ */, T2& /* attr */) {}
};
template <>
struct move_if<true>
{
template<typename T1, typename T2>
static void call(T1& attr_, T2& attribute)
{
traits::move_to(attr_, attribute);
}
};
template <typename Parser, typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attribute)
{
using pass = detail::pass_variant_attribute<Parser, Attribute, Context>;
using pseudo = traits::pseudo_attribute<Context, typename pass::type, Iterator>;
typename pseudo::type attr_ = pseudo::call(first, last, pass::call(attribute));
if (p.parse(first, last, context, rcontext, attr_))
{
traits::move_to(std::move(attr_), attribute);
move_if<!std::is_reference<decltype(attr_)>::value>::call(attr_, attribute);
return true;
}
return false;
@@ -216,14 +197,14 @@ namespace boost::spirit::x3::detail
template <typename Subject>
struct alternative_helper : unary_parser<Subject, alternative_helper<Subject>>
{
static constexpr bool is_pass_through_unary = true;
static bool const is_pass_through_unary = true;
using unary_parser<Subject, alternative_helper<Subject>>::unary_parser;
template <typename Iterator, typename Context, typename RContext, typename Attribute>
[[nodiscard]] constexpr bool parse(
Iterator& first, Iterator const& last, Context const& context, RContext& rcontext, Attribute& attr
) const noexcept(noexcept(detail::parse_alternative(this->subject, first, last, context, rcontext, attr)))
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
return detail::parse_alternative(this->subject, first, last, context, rcontext, attr);
}
@@ -232,34 +213,39 @@ namespace boost::spirit::x3::detail
template <typename Left, typename Right, typename Context, typename RContext>
struct parse_into_container_impl<alternative<Left, Right>, Context, RContext>
{
using parser_type = alternative<Left, Right>;
typedef alternative<Left, Right> parser_type;
template <typename Iterator, typename Attribute>
requires traits::is_variant_v<traits::container_value_t<Attribute>>
[[nodiscard]] static constexpr bool
call(
parser_type const& parser,
Iterator& first, Iterator const& last, Context const& context, RContext& rcontext, Attribute& attribute
)
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attribute, mpl::false_)
{
return detail::parse_into_container(parser.left, first, last, context, rcontext, attribute)
|| detail::parse_into_container(parser.right, first, last, context, rcontext, attribute);
}
template <typename Iterator, typename Attribute>
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attribute, mpl::true_)
{
return detail::parse_into_container(alternative_helper<Left>{parser.left}, first, last, context, rcontext, attribute)
|| detail::parse_into_container(alternative_helper<Right>{parser.right}, first, last, context, rcontext, attribute);
}
template <typename Iterator, typename Attribute>
requires (!traits::is_variant_v<traits::container_value_t<Attribute>>)
[[nodiscard]] static constexpr bool
call(
parser_type const& parser,
Iterator& first, Iterator const& last,
Context const& context, RContext& rcontext, Attribute& attribute
)
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attribute)
{
return detail::parse_into_container(parser.left, first, last, context, rcontext, attribute)
|| detail::parse_into_container(parser.right, first, last, context, rcontext, attribute);
return call(parser, first, last, context, rcontext, attribute,
typename traits::is_variant<typename traits::container_value<Attribute>::type>::type{});
}
};
} // boost::spirit::x3::detail
}}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -26,15 +25,18 @@
#include <boost/mpl/if.hpp>
#include <iterator>
#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/is_same.hpp>
namespace boost::spirit::x3
#include <iterator> // for std::make_move_iterator
namespace boost { namespace spirit { namespace x3
{
template <typename Left, typename Right>
struct sequence;
} // boost::spirit::x3
}}}
namespace boost::spirit::x3::detail
namespace boost { namespace spirit { namespace x3 { namespace detail
{
template <typename Parser, typename Context, typename Enable = void>
struct sequence_size
@@ -356,62 +358,62 @@ namespace boost::spirit::x3::detail
template <typename Left, typename Right, typename Context, typename RContext>
struct parse_into_container_impl<sequence<Left, Right>, Context, RContext>
{
using parser_type = sequence<Left, Right>;
typedef sequence<Left, Right> parser_type;
template <typename Attribute>
static constexpr bool is_container_substitute = traits::is_substitute_v<
traits::attribute_of_t<parser_type, Context>,
traits::container_value_t<Attribute>
>;
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
requires is_container_substitute<Attribute>
[[nodiscard]] static constexpr bool
call(
parser_type const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) noexcept(noexcept(parse_into_container_base_impl<parser_type>::call(
parser, first, last, context, rcontext, attr
)))
{
return parse_into_container_base_impl<parser_type>::call(
parser, first, last, context, rcontext, attr
);
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
requires (!is_container_substitute<Attribute>)
[[nodiscard]] static constexpr bool
call(
parser_type const& parser, It& first, Se const& last,
Context const& context, RContext& rcontext, Attribute& attr
) // never noexcept (requires container insertion)
template <typename Iterator, typename Attribute>
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
{
// inform user what went wrong if we jumped here in attempt to
// parse incompatible sequence into fusion::map
static_assert(
!std::is_same_v<traits::attribute_category_t<Attribute>, traits::associative_attribute>,
"To parse directly into fusion::map sequence must produce tuple attribute "
"where type of first element is existing key in fusion::map and second element "
"is value to be stored under that key"
);
static_assert(!is_same< typename traits::attribute_category<Attribute>::type,
traits::associative_attribute>::value,
"To parse directly into fusion::map sequence must produce tuple attribute "
"where type of first element is existing key in fusion::map and second element "
"is value to be stored under that key");
Attribute attr_{};
if (!detail::parse_sequence(
parser, first, last, context, rcontext, attr_, traits::container_attribute()
))
if (!parse_sequence(parser
, first, last, context, rcontext, attr_, traits::container_attribute()))
{
return false;
}
traits::append(
attr,
std::make_move_iterator(traits::begin(attr_)),
std::make_move_iterator(traits::end(attr_))
);
traits::append(attr, std::make_move_iterator(traits::begin(attr_)),
std::make_move_iterator(traits::end(attr_)));
return true;
}
template <typename Iterator, typename Attribute>
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
{
return parse_into_container_base_impl<parser_type>::call(
parser, first, last, context, rcontext, attr);
}
template <typename Iterator, typename Attribute>
static bool call(
parser_type const& parser
, Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr)
{
typedef typename
traits::attribute_of<parser_type, Context>::type
attribute_type;
typedef typename
traits::container_value<Attribute>::type
value_type;
return call(parser, first, last, context, rcontext, attr
, typename traits::is_substitute<attribute_type, value_type>::type());
}
};
} // boost::spirit::x3::detail
}}}}
#endif

View File

@@ -2,7 +2,7 @@
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2017 wanghan02
Copyright (c) 2024-2025 Nana Sakisaka
Copyright (c) 2024 Nana Sakisaka
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)
@@ -10,7 +10,7 @@
#if !defined(BOOST_SPIRIT_X3_OPTIONAL_MARCH_23_2007_1117PM)
#define BOOST_SPIRIT_X3_OPTIONAL_MARCH_23_2007_1117PM
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/proxy.hpp>
#include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
#include <boost/spirit/home/x3/support/expectation.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
@@ -18,101 +18,72 @@
#include <boost/spirit/home/x3/support/traits/optional_traits.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename Subject>
struct optional : unary_parser<Subject, optional<Subject>>
struct optional : proxy<Subject, optional<Subject>>
{
using base_type = unary_parser<Subject, optional<Subject>>;
static constexpr bool is_pass_through_unary = false;
static constexpr bool handles_container = true;
typedef proxy<Subject, optional<Subject>> base_type;
static bool const is_pass_through_unary = false;
static bool const handles_container = true;
template <typename SubjectT>
requires std::is_constructible_v<Subject, SubjectT>
constexpr optional(SubjectT&& subject)
noexcept(std::is_nothrow_constructible_v<Subject, SubjectT>)
: base_type(std::forward<SubjectT>(subject))
{}
constexpr optional(Subject const& subject)
: base_type(subject) {}
// catch-all overload
template <
std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext,
typename Attribute // unconstrained
>
[[nodiscard]] constexpr bool
parse(
It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr
) const
noexcept(is_nothrow_parsable_v<Subject, It, Se, Context, RContext, Attribute>)
using base_type::parse_subject;
// Attribute is a container
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse_subject(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr
, traits::container_attribute) const
{
static_assert(Parsable<Subject, It, Se, Context, RContext, Attribute>);
// discard [[nodiscard]]
(void)this->subject.parse(first, last, context, rcontext, attr);
return !x3::has_expectation_failure(context);
detail::parse_into_container(
this->subject, first, last, context, rcontext, attr);
return !has_expectation_failure(context);
}
// container attribute
template <
std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext,
traits::CategorizedAttr<traits::container_attribute> Attribute
>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
noexcept(noexcept(detail::parse_into_container(this->subject, first, last, context, rcontext, attr)))
// Attribute is an optional
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse_subject(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr
, traits::optional_attribute) const
{
// discard [[nodiscard]]
(void)detail::parse_into_container(this->subject, first, last, context, rcontext, attr);
return !x3::has_expectation_failure(context);
}
typedef typename
x3::traits::optional_value<Attribute>::type
value_type;
// optional attribute
template <
std::forward_iterator It, std::sentinel_for<It> Se, typename Context, typename RContext,
traits::CategorizedAttr<traits::optional_attribute> Attribute
>
[[nodiscard]] constexpr bool
parse(It& first, Se const& last, Context const& context, RContext& rcontext, Attribute& attr) const
noexcept(
std::is_nothrow_default_constructible_v<x3::traits::optional_value_t<Attribute>> &&
is_nothrow_parsable_v<Subject, It, Se, Context, RContext, x3::traits::optional_value_t<Attribute>> &&
noexcept(x3::traits::move_to(std::declval<x3::traits::optional_value_t<Attribute>&&>(), attr))
)
{
using value_type = x3::traits::optional_value_t<Attribute>;
value_type val; // default-initialize
// create a local value
value_type val{};
static_assert(Parsable<Subject, It, Se, Context, RContext, value_type>);
if (this->subject.parse(first, last, context, rcontext, val))
{
// assign the parsed value into our attribute
x3::traits::move_to(std::move(val), attr);
return true;
}
x3::traits::move_to(val, attr);
return !x3::has_expectation_failure(context);
} else {
return !has_expectation_failure(context);
}
return true;
}
};
template <X3Subject Subject>
[[nodiscard]] constexpr optional<as_parser_plain_t<Subject>>
operator-(Subject&& subject)
noexcept(is_parser_nothrow_constructible_v<optional<as_parser_plain_t<Subject>>, Subject>)
template <typename Subject>
constexpr optional<typename extension::as_parser<Subject>::value_type>
operator-(Subject const& subject)
{
return { as_parser(std::forward<Subject>(subject)) };
return { as_parser(subject) };
}
} // boost::spirit::x3
}}}
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename Subject, typename Context>
struct attribute_of<x3::optional<Subject>, Context>
: build_optional<attribute_of_t<Subject, Context>>
{};
} // boost::spirit::x3::traits
: build_optional<
typename attribute_of<Subject, Context>::type> {};
}}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,7 +8,6 @@
#define BOOST_SPIRIT_X3_STRING_FEBRUARY_03_2007_0355PM
#include <boost/spirit/home/x3/string/literal_string.hpp>
#include <boost/spirit/home/x3/string/string.hpp>
#include <boost/spirit/home/x3/string/symbols.hpp>
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,22 +9,36 @@
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <string_view>
#include <iterator>
namespace boost::spirit::x3::detail
namespace boost { namespace spirit { namespace x3 { namespace detail
{
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompareFunc>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string_view<CharT, CharTraitsT> const str,
It& first, Se const& last,
Attribute& attr, CaseCompareFunc const& compare
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
template <typename Char, typename Iterator, typename Attribute, typename CaseCompareFunc>
inline bool string_parse(
Char const* str
, Iterator& first, Iterator const& last, Attribute& attr, CaseCompareFunc const& compare)
{
It i = first;
auto stri = str.begin();
auto str_last = str.end();
Iterator i = first;
Char ch = *str;
for (; !!ch; ++i)
{
if (i == last || (compare(ch, *i) != 0))
return false;
ch = *++str;
}
x3::traits::move_to(first, i, attr);
first = i;
return true;
}
template <typename String, typename Iterator, typename Attribute, typename CaseCompareFunc>
inline bool string_parse(
String const& str
, Iterator& first, Iterator const& last, Attribute& attr, CaseCompareFunc const& compare)
{
Iterator i = first;
typename String::const_iterator stri = str.begin();
typename String::const_iterator str_last = str.end();
for (; stri != str_last; ++stri, ++i)
if (i == last || (compare(*stri, *i) != 0))
@@ -35,29 +48,30 @@ namespace boost::spirit::x3::detail
return true;
}
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute, typename CaseCompareFunc>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string<CharT, CharTraitsT> const& str,
It& first, Se const& last,
Attribute& attr, CaseCompareFunc const& compare
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
template <typename Char, typename Iterator, typename Attribute>
inline bool string_parse(
Char const* uc_i, Char const* lc_i
, Iterator& first, Iterator const& last, Attribute& attr)
{
return detail::string_parse(std::basic_string_view{str}, first, last, attr, compare);
Iterator i = first;
for (; *uc_i && *lc_i; ++uc_i, ++lc_i, ++i)
if (i == last || ((*uc_i != *i) && (*lc_i != *i)))
return false;
x3::traits::move_to(first, i, attr);
first = i;
return true;
}
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string_view<CharT, CharTraitsT> const ucstr,
std::basic_string_view<CharT, CharTraitsT> const lcstr,
It& first, Se const& last, Attribute& attr
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
template <typename String, typename Iterator, typename Attribute>
inline bool string_parse(
String const& ucstr, String const& lcstr
, Iterator& first, Iterator const& last, Attribute& attr)
{
auto uc_i = ucstr.begin();
auto uc_last = ucstr.end();
auto lc_i = lcstr.begin();
It i = first;
typename String::const_iterator uc_i = ucstr.begin();
typename String::const_iterator uc_last = ucstr.end();
typename String::const_iterator lc_i = lcstr.begin();
Iterator i = first;
for (; uc_i != uc_last; ++uc_i, ++lc_i, ++i)
if (i == last || ((*uc_i != *i) && (*lc_i != *i)))
@@ -66,17 +80,6 @@ namespace boost::spirit::x3::detail
first = i;
return true;
}
template <typename CharT, typename CharTraitsT, std::forward_iterator It, std::sentinel_for<It> Se, typename Attribute>
[[nodiscard]] constexpr bool
string_parse(
std::basic_string<CharT, CharTraitsT> const& ucstr,
std::basic_string<CharT, CharTraitsT> const& lcstr,
It& first, Se const& last, Attribute& attr
) noexcept(std::is_same_v<std::remove_const_t<Attribute>, unused_type>)
{
return detail::string_parse(std::basic_string_view{ucstr}, std::basic_string_view{lcstr}, first, last, attr);
}
} // boost::spirit::x3::detail
}}}}
#endif

View File

@@ -0,0 +1,202 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM)
#define BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM
#include <boost/call_traits.hpp>
#include <boost/assert.hpp>
#include <string>
namespace boost { namespace spirit { namespace x3 { namespace detail
{
// This file contains low level TST routines, not for
// public consumption.
template <typename Char, typename T>
struct tst_node
{
tst_node(Char id)
: id(id), data(0), lt(0), eq(0), gt(0)
{
}
template <typename Alloc>
static void
destruct_node(tst_node* p, Alloc* alloc)
{
if (p)
{
if (p->data)
alloc->delete_data(p->data);
destruct_node(p->lt, alloc);
destruct_node(p->eq, alloc);
destruct_node(p->gt, alloc);
alloc->delete_node(p);
}
}
template <typename Alloc>
static tst_node*
clone_node(tst_node* p, Alloc* alloc)
{
if (p)
{
tst_node* clone = alloc->new_node(p->id);
if (p->data)
clone->data = alloc->new_data(*p->data);
clone->lt = clone_node(p->lt, alloc);
clone->eq = clone_node(p->eq, alloc);
clone->gt = clone_node(p->gt, alloc);
return clone;
}
return 0;
}
template <typename Iterator, typename CaseCompare>
static T*
find(tst_node* start, Iterator& first, Iterator last, CaseCompare comp)
{
if (first == last)
return 0;
Iterator i = first;
Iterator latest = first;
tst_node* p = start;
T* found = 0;
while (p && i != last)
{
int32_t c = comp(*i,p->id);
if (c == 0)
{
if (p->data)
{
found = p->data;
latest = i;
}
p = p->eq;
i++;
}
else if (c < 0)
{
p = p->lt;
}
else
{
p = p->gt;
}
}
if (found)
first = ++latest; // one past the last matching char
return found;
}
template <typename Iterator, typename Alloc>
static T*
add(
tst_node*& start
, Iterator first
, Iterator last
, typename boost::call_traits<T>::param_type val
, Alloc* alloc)
{
if (first == last)
return 0;
tst_node** pp = &start;
for (;;)
{
auto c = *first;
if (*pp == 0)
*pp = alloc->new_node(c);
tst_node* p = *pp;
if (c == p->id)
{
if (++first == last)
{
if (p->data == 0)
p->data = alloc->new_data(val);
return p->data;
}
pp = &p->eq;
}
else if (c < p->id)
{
pp = &p->lt;
}
else
{
pp = &p->gt;
}
}
}
template <typename Iterator, typename Alloc>
static void
remove(tst_node*& p, Iterator first, Iterator last, Alloc* alloc)
{
if (p == 0 || first == last)
return;
auto c = *first;
if (c == p->id)
{
if (++first == last)
{
if (p->data)
{
alloc->delete_data(p->data);
p->data = 0;
}
}
remove(p->eq, first, last, alloc);
}
else if (c < p->id)
{
remove(p->lt, first, last, alloc);
}
else
{
remove(p->gt, first, last, alloc);
}
if (p->data == 0 && p->lt == 0 && p->eq == 0 && p->gt == 0)
{
alloc->delete_node(p);
p = 0;
}
}
template <typename F>
static void
for_each(tst_node* p, std::basic_string<Char> prefix, F f)
{
if (p)
{
for_each(p->lt, prefix, f);
std::basic_string<Char> s = prefix + p->id;
for_each(p->eq, s, f);
if (p->data)
f(s, *p->data);
for_each(p->gt, prefix, f);
}
}
Char id; // the node's identity character
T* data; // optional data
tst_node* lt; // left pointer
tst_node* eq; // middle pointer
tst_node* gt; // right pointer
};
}}}}
#endif

View File

@@ -1,175 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM)
#define BOOST_SPIRIT_X3_TST_MARCH_09_2007_0905AM
#include <boost/spirit/home/x3/core/config.hpp>
#include <boost/spirit/home/x3/support/allocator.hpp>
#include <boost/assert.hpp>
#include <iterator>
#include <memory>
#include <string_view>
#include <string>
#include <utility>
namespace boost::spirit::x3::detail
{
// This file contains low level TST routines, not for
// public consumption.
template <typename Char, typename T, typename Alloc = std::allocator<T>>
struct tst_node
{
using allocator_type = Alloc;
using node_allocator_type = std::allocator_traits<Alloc>::template rebind_alloc<tst_node>;
constexpr explicit tst_node(Char id, Alloc const& alloc = {}) noexcept
: alloc(alloc)
, node_alloc(this->alloc)
, id(id)
{
}
constexpr tst_node(tst_node const& rhs)
: alloc(std::allocator_traits<Alloc>::select_on_container_copy_construction(rhs.alloc))
, node_alloc(std::allocator_traits<node_allocator_type>::select_on_container_copy_construction(rhs.node_alloc))
, id(rhs.id)
, data(allocator_ops<tst_node>::template copy_construct<&tst_node::alloc, &tst_node::data>(*this, rhs))
, lt(allocator_ops<tst_node>::template copy_construct<&tst_node::node_alloc, &tst_node::lt>(*this, rhs))
, eq(allocator_ops<tst_node>::template copy_construct<&tst_node::node_alloc, &tst_node::eq>(*this, rhs))
, gt(allocator_ops<tst_node>::template copy_construct<&tst_node::node_alloc, &tst_node::gt>(*this, rhs))
{
}
constexpr tst_node(tst_node&& rhs) noexcept
: alloc(std::move(rhs.alloc))
, node_alloc(std::move(rhs.node_alloc))
, id(std::move(rhs.id))
, data(std::exchange(rhs.data, nullptr))
, lt(std::exchange(rhs.lt, nullptr))
, eq(std::exchange(rhs.eq, nullptr))
, gt(std::exchange(rhs.gt, nullptr))
{
}
constexpr ~tst_node() noexcept
{
allocator_ops<tst_node>::template destroy_deallocate<
&tst_node::alloc, &tst_node::data
>(*this);
allocator_ops<tst_node>::template destroy_deallocate<
&tst_node::node_alloc,
&tst_node::lt, &tst_node::eq, &tst_node::gt
>(*this);
}
constexpr tst_node& operator=(tst_node const& rhs)
{
if (std::addressof(rhs) == this) return *this;
id = rhs.id;
allocator_ops<tst_node>::template copy_assign<
&tst_node::alloc, &tst_node::data
>(*this, rhs);
allocator_ops<tst_node>::template copy_assign<
&tst_node::node_alloc,
&tst_node::lt, &tst_node::eq, &tst_node::gt
>(*this, rhs);
}
constexpr tst_node& operator=(tst_node&& rhs)
noexcept(allocator_ops<tst_node>::template move_assign_noexcept<allocator_type, node_allocator_type>)
{
if (std::addressof(rhs) == this) return *this;
id = std::move(rhs.id);
allocator_ops<tst_node>::template move_assign<
&tst_node::alloc, &tst_node::data
>(*this, std::move(rhs));
allocator_ops<tst_node>::template move_assign<
&tst_node::node_alloc,
&tst_node::lt, &tst_node::eq, &tst_node::gt
>(*this, std::move(rhs));
}
template <std::forward_iterator Iterator, typename CaseCompare>
[[nodiscard]] static constexpr T*
find(tst_node* start, Iterator& first, Iterator last, CaseCompare const& comp) noexcept
{
if (first == last) return nullptr;
Iterator i = first;
Iterator latest = first;
tst_node* p = start;
T* found = nullptr;
while (p && i != last)
{
auto c = comp(*i,p->id);
if (c == 0) {
if (p->data)
{
found = p->data;
latest = i;
}
p = p->eq;
++i;
}
else if (c < 0)
{
p = p->lt;
}
else
{
p = p->gt;
}
}
if (found)
{
first = ++latest; // one past the last matching char
}
return found;
}
template <typename F>
static void
for_each(tst_node* const p, std::basic_string_view<Char> const prefix, F&& f)
{
if (!p) return;
tst_node::for_each(p->lt, prefix, f);
std::basic_string<Char> s = std::basic_string<Char>(prefix) + p->id;
tst_node::for_each(p->eq, s, f);
if (p->data)
{
f(s, *p->data);
}
tst_node::for_each(p->gt, prefix, f);
}
friend struct allocator_ops<tst_node>;
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS Alloc alloc;
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS node_allocator_type node_alloc;
Char id; // the node's identity character
T* data = nullptr; // optional data
tst_node* lt = nullptr; // left pointer
tst_node* eq = nullptr; // middle pointer
tst_node* gt = nullptr; // right pointer
};
}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,66 +7,276 @@
#if !defined(BOOST_SPIRIT_X3_LITERAL_STRING_APR_18_2006_1125PM)
#define BOOST_SPIRIT_X3_LITERAL_STRING_APR_18_2006_1125PM
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/core/skip_over.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/string/detail/string_parse.hpp>
#include <boost/spirit/home/x3/support/no_case.hpp>
#include <boost/spirit/home/x3/support/utility/utf8.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
template <typename String, typename Encoding, typename Attribute = std::basic_string<typename Encoding::char_type>>
template <typename String, typename Encoding,
typename Attribute = std::basic_string<typename Encoding::char_type>>
struct literal_string : parser<literal_string<String, Encoding, Attribute>>
{
static_assert(
!std::is_pointer_v<std::decay_t<String>>,
"`literal_string` for raw character pointer/array is banned; it has an undetectable risk of holding a dangling pointer."
);
static_assert(std::is_convertible_v<String, std::basic_string_view<typename String::value_type>>);
typedef typename Encoding::char_type char_type;
typedef Encoding encoding;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<unused_type, attribute_type>::value;
static bool const handles_container = has_attribute;
using char_type = typename Encoding::char_type;
using encoding = Encoding;
using attribute_type = Attribute;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
static constexpr bool handles_container = has_attribute;
template<class... Args>
requires std::is_constructible_v<String, Args...>
constexpr literal_string(Args&&... args)
noexcept(std::is_nothrow_constructible_v<String, Args...>)
: str(std::forward<Args>(args)...)
constexpr literal_string(typename add_reference< typename add_const<String>::type >::type str)
: str(str)
{}
template <typename Iterator, typename Context, typename Attribute_>
[[nodiscard]] constexpr bool parse(
Iterator& first, Iterator const& last,
Context const& context, unused_type, Attribute_& attr
) const
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute_& attr) const
{
x3::skip_over(first, last, context);
return detail::string_parse(str, first, last, attr, x3::get_case_compare<encoding>(context));
return detail::string_parse(str, first, last, attr, get_case_compare<encoding>(context));
}
String str;
};
namespace standard
{
constexpr literal_string<char const*, char_encoding::standard>
string(char const* s)
{
return { s };
}
inline literal_string<std::basic_string<char>, char_encoding::standard>
string(std::basic_string<char> const& s)
{
return { s };
}
inline constexpr literal_string<char const*, char_encoding::standard, unused_type>
lit(char const* s)
{
return { s };
}
template <typename Char>
literal_string<std::basic_string<Char>, char_encoding::standard, unused_type>
lit(std::basic_string<Char> const& s)
{
return { s };
}
}
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
namespace standard_wide
{
constexpr literal_string<wchar_t const*, char_encoding::standard_wide>
string(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::standard_wide>
string(std::basic_string<wchar_t> const& s)
{
return { s };
}
constexpr literal_string<wchar_t const*, char_encoding::standard_wide, unused_type>
lit(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::standard_wide, unused_type>
lit(std::basic_string<wchar_t> const& s)
{
return { s };
}
}
#endif
#if defined(BOOST_SPIRIT_X3_UNICODE)
namespace unicode
{
constexpr literal_string<char32_t const*, char_encoding::unicode>
string(char32_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<char32_t>, char_encoding::unicode>
string(std::basic_string<char32_t> const& s)
{
return { s };
}
constexpr literal_string<char32_t const*, char_encoding::unicode, unused_type>
lit(char32_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<char32_t>, char_encoding::unicode, unused_type>
lit(std::basic_string<char32_t> const& s)
{
return { s };
}
}
#endif
namespace ascii
{
constexpr literal_string<wchar_t const*, char_encoding::ascii>
string(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::ascii>
string(std::basic_string<wchar_t> const& s)
{
return { s };
}
constexpr literal_string<char const*, char_encoding::ascii, unused_type>
lit(char const* s)
{
return { s };
}
template <typename Char>
literal_string<std::basic_string<Char>, char_encoding::ascii, unused_type>
lit(std::basic_string<Char> const& s)
{
return { s };
}
}
namespace iso8859_1
{
constexpr literal_string<wchar_t const*, char_encoding::iso8859_1>
string(wchar_t const* s)
{
return { s };
}
inline literal_string<std::basic_string<wchar_t>, char_encoding::iso8859_1>
string(std::basic_string<wchar_t> const& s)
{
return { s };
}
constexpr literal_string<char const*, char_encoding::iso8859_1, unused_type>
lit(char const* s)
{
return { s };
}
template <typename Char>
literal_string<std::basic_string<Char>, char_encoding::iso8859_1, unused_type>
lit(std::basic_string<Char> const& s)
{
return { s };
}
}
using standard::string;
using standard::lit;
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
using standard_wide::string;
using standard_wide::lit;
#endif
namespace extension
{
template <int N>
struct as_parser<char[N]>
{
typedef literal_string<
char const*, char_encoding::standard, unused_type>
type;
typedef type value_type;
static constexpr type call(char const* s)
{
return type(s);
}
};
template <int N>
struct as_parser<char const[N]> : as_parser<char[N]> {};
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
template <int N>
struct as_parser<wchar_t[N]>
{
typedef literal_string<
wchar_t const*, char_encoding::standard_wide, unused_type>
type;
typedef type value_type;
static constexpr type call(wchar_t const* s)
{
return type(s);
}
};
template <int N>
struct as_parser<wchar_t const[N]> : as_parser<wchar_t[N]> {};
#endif
template <>
struct as_parser<char const*>
{
typedef literal_string<
char const*, char_encoding::standard, unused_type>
type;
typedef type value_type;
static constexpr type call(char const* s)
{
return type(s);
}
};
template <typename Char>
struct as_parser< std::basic_string<Char> >
{
typedef literal_string<
Char const*, char_encoding::standard, unused_type>
type;
typedef type value_type;
static type call(std::basic_string<Char> const& s)
{
return type(s.c_str());
}
};
}
template <typename String, typename Encoding, typename Attribute>
struct get_info<literal_string<String, Encoding, Attribute>>
{
using result_type = std::string;
[[nodiscard]] constexpr std::string operator()(literal_string<String, Encoding, Attribute> const& p) const
typedef std::string result_type;
std::string operator()(literal_string<String, Encoding, Attribute> const& p) const
{
return '"' + x3::to_utf8(p.str) + '"';
return '"' + to_utf8(p.str) + '"';
}
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,298 +0,0 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_STRING_STRING_HPP
#define BOOST_SPIRIT_X3_STRING_STRING_HPP
#include <boost/spirit/home/x3/string/literal_string.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp> // required for "c" -> 'c' optimization
#include <boost/spirit/home/x3/support/traits/string_traits.hpp>
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3
{
namespace standard
{
inline namespace helpers
{
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard, std::basic_string<char>>
string(char ch) noexcept
{
return { ch };
}
// Optimize `literal_string{"c"}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard, std::basic_string<char>>
string(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
} // helpers
template <typename T>
requires traits::CharIncompatibleWith<T, char> || traits::StringLikeIncompatibleWith<T, char>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // standard
using standard::helpers::string;
using standard::helpers::lit;
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
namespace standard_wide
{
inline namespace helpers
{
template <traits::CppStringLike<wchar_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, std::basic_string<wchar_t>>
string(wchar_t ch) noexcept
{
return { ch };
}
// Optimize `literal_string{L"c"}` into `literal_char{L'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::standard_wide, std::basic_string<wchar_t>>
string(traits::X3VagueArrayOf2Chars<wchar_t> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<wchar_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::standard_wide, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
} // helpers
template <typename T>
requires traits::CharIncompatibleWith<T, wchar_t> || traits::StringLikeIncompatibleWith<T, wchar_t>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // standard_wide
using standard_wide::helpers::string;
using standard_wide::helpers::lit;
#endif
#ifdef BOOST_SPIRIT_X3_UNICODE
namespace unicode
{
inline namespace helpers
{
// TODO: add `char8_t` and `char16_t` overloads
template <traits::CppStringLike<char32_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::unicode>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::unicode>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::unicode, std::basic_string<char32_t>>
string(char32_t ch) noexcept
{
return { ch };
}
// Optimize `literal_string{U"c"}` into `literal_char{U'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::unicode, std::basic_string<char32_t>>
string(traits::X3VagueArrayOf2Chars<char32_t> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char32_t> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::unicode, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::unicode, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
} // helpers
template <typename T>
requires traits::CharIncompatibleWith<T, char32_t> || traits::StringLikeIncompatibleWith<T, char32_t>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
}
using unicode::helpers::string;
using unicode::helpers::lit;
#endif
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] ascii
{
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::ascii>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::ascii>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::ascii, std::basic_string<char>>
string(char ch) noexcept
{
return { ch };
}
// Optimize `literal_string{"c"}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::ascii, std::basic_string<char>>
string(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::ascii, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::ascii, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
template <typename T>
requires traits::CharIncompatibleWith<T, char> || traits::StringLikeIncompatibleWith<T, char>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // ascii
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] iso8859_1
{
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1>
string(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1>, T>)
{
return {std::forward<T>(string_like)};
}
// Optimize `literal_string{'c'}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::iso8859_1, std::basic_string<char>>
string(char ch) noexcept
{
return { ch };
}
// Optimize `literal_string{"c"}` into `literal_char{'c'}`
[[nodiscard]] constexpr literal_char<char_encoding::iso8859_1, std::basic_string<char>>
string(traits::X3VagueArrayOf2Chars<char> auto const& ch) noexcept
{
return { ch[0] };
}
template <traits::CppStringLike<char> T>
[[nodiscard]] constexpr literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1, unused_type>
lit(T&& string_like)
noexcept(std::is_nothrow_constructible_v<literal_string<traits::maybe_owning_string<T>, char_encoding::iso8859_1, unused_type>, T>)
{
return {std::forward<T>(string_like)};
}
template <typename T>
requires traits::CharIncompatibleWith<T, char> || traits::StringLikeIncompatibleWith<T, char>
constexpr void string(T&&) = delete; // Mixing incompatible character types is not allowed
} // iso8859_1
namespace extension
{
template <traits::CharLike CharT, std::size_t N>
struct as_parser<CharT[N]>
{
using type = literal_string<std::basic_string_view<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
[[nodiscard]] static constexpr type call(CharT const* s)
{
return type(s);
}
};
template <traits::CharLike CharT, std::size_t N>
struct as_parser<CharT const[N]> : as_parser<CharT[N]> {};
template <traits::CharLike CharT>
struct as_parser<CharT const*>
{
using type = literal_string<std::basic_string_view<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
[[nodiscard]] static constexpr type call(CharT const* s)
{
return type(std::basic_string_view<CharT>{s});
}
};
template <traits::CharLike CharT>
struct as_parser<std::basic_string<CharT>>
{
using type = literal_string<std::basic_string<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
template <typename T>
[[nodiscard]] static constexpr type call(T&& str)
noexcept(std::is_nothrow_constructible_v<type, T>)
{
return type(std::forward<T>(str));
}
};
template <traits::CharLike CharT>
struct as_parser<std::basic_string_view<CharT>>
{
using type = literal_string<std::basic_string_view<CharT>, traits::char_encoding_for<CharT>, unused_type>;
using value_type = type;
template <typename T>
[[nodiscard]] static constexpr type call(T&& str)
noexcept(std::is_nothrow_constructible_v<type, T>)
{
return type(std::forward<T>(str));
}
};
} // extension
} // boost::spirit::x3
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Carl Barron
Copyright (c) 2025 Nana Sakisaka
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)
@@ -17,161 +16,99 @@
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/no_case.hpp>
#include <boost/spirit/home/x3/char_encoding/detail/encoding_warning.hpp>
#include <boost/spirit/home/x3/char_encoding/ascii.hpp>
#include <boost/spirit/home/x3/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/x3/char_encoding/standard.hpp>
#include <boost/spirit/home/x3/char_encoding/standard_wide.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/spirit/home/support/char_encoding/iso8859_1.hpp>
#include <boost/spirit/home/support/char_encoding/standard.hpp>
#include <boost/spirit/home/support/char_encoding/standard_wide.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
#include <string>
#include <string_view>
#include <ranges>
#include <iterator>
#include <initializer_list>
#include <iterator> // std::begin
#include <memory> // std::shared_ptr
#include <type_traits>
#include <utility>
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
#endif
#define BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING(old_api) \
"Use `shared_" old_api "` instead. `" old_api "` has had a " \
"*implicit* trait where the underlying storage is shared via " \
"`std::shared_ptr`. This disallows `constexpr` usage in generic " \
"scenarios where the sharing is not actually needed at all. Even " \
"for non-`constexpr` usage, the old name `" old_api "` does not " \
"represent this trait, so the usage of the old API is strongly " \
"discouraged."
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
namespace detail
{
template <typename Derived, bool IsShared, typename Encoding, typename T, typename Lookup>
struct symbols_parser_impl : parser<Derived>
template <
typename Encoding
, typename T = unused_type
, typename Lookup = tst<typename Encoding::char_type, T> >
struct symbols_parser : parser<symbols_parser<Encoding, T, Lookup>>
{
using char_type = typename Encoding::char_type; // the character type
using encoding = Encoding;
using value_type = T; // the value associated with each entry
using attribute_type = value_type;
typedef typename Encoding::char_type char_type; // the character type
typedef Encoding encoding;
typedef T value_type; // the value associated with each entry
typedef value_type attribute_type;
static constexpr bool has_attribute = !std::is_same_v<unused_type, attribute_type>;
static constexpr bool handles_container = traits::is_container_v<attribute_type>;
static bool const has_attribute =
!std::is_same<unused_type, attribute_type>::value;
static bool const handles_container =
traits::is_container<attribute_type>::value;
constexpr symbols_parser_impl(std::string_view name = "symbols")
requires(IsShared)
: add{*this}
, remove{*this}
, lookup(std::make_shared<Lookup>())
, name_(name)
symbols_parser(std::string const& name = "symbols")
: add{*this}
, remove{*this}
, lookup(std::make_shared<Lookup>())
, name_(name)
{
}
constexpr symbols_parser_impl(std::string_view name = "symbols")
requires(!IsShared)
: add{*this}
, remove{*this}
, lookup(std::make_unique<Lookup>())
, name_(name)
symbols_parser(symbols_parser const& syms)
: add{*this}
, remove{*this}
, lookup(syms.lookup)
, name_(syms.name_)
{
}
constexpr symbols_parser_impl(symbols_parser_impl const& syms)
requires(IsShared)
: add{*this}
, remove{*this}
, lookup(syms.lookup)
, name_(syms.name_)
template <typename Symbols>
symbols_parser(Symbols const& syms, std::string const& name = "symbols")
: symbols_parser(name)
{
for (auto& sym : syms)
add(sym);
}
constexpr symbols_parser_impl(symbols_parser_impl const& syms)
requires(!IsShared)
: add{*this}
, remove{*this}
, lookup(std::make_unique<Lookup>(*syms.lookup))
, name_(syms.name_)
template <typename Symbols, typename Data>
symbols_parser(Symbols const& syms, Data const& data
, std::string const& name = "symbols")
: symbols_parser(name)
{
using std::begin;
auto di = begin(data);
for (auto& sym : syms)
add(sym, *di++);
}
constexpr symbols_parser_impl(symbols_parser_impl&&) noexcept = default;
template <std::ranges::forward_range Symbols>
requires std::convertible_to<std::ranges::range_value_t<Symbols>, std::basic_string_view<char_type>>
constexpr symbols_parser_impl(Symbols const& syms, std::string const& name = "symbols")
: symbols_parser_impl(name)
symbols_parser(std::initializer_list<std::pair<char_type const*, T>> syms
, std::string const & name="symbols")
: symbols_parser(name)
{
for (auto const& sym : syms)
{
this->add(sym);
}
}
template <std::ranges::forward_range Symbols, std::ranges::forward_range Data>
requires
std::convertible_to<std::ranges::range_value_t<Symbols>, std::basic_string_view<char_type>> &&
std::convertible_to<std::ranges::range_value_t<Data>, T>
constexpr symbols_parser_impl(
Symbols const& syms, Data const& data, std::string const& name = "symbols"
)
: symbols_parser_impl(name)
{
auto di = std::ranges::begin(data);
for (auto const& sym : syms)
{
this->add(sym, *di++);
}
}
constexpr symbols_parser_impl(
std::initializer_list<std::pair<char_type const*, T>> syms,
std::string const & name="symbols"
)
: symbols_parser_impl(name)
{
for (auto const& sym : syms)
{
for (auto& sym : syms)
add(sym.first, sym.second);
}
}
constexpr symbols_parser_impl(
std::initializer_list<char_type const*> syms,
std::string const &name="symbols"
)
: symbols_parser_impl(name)
symbols_parser(std::initializer_list<char_type const*> syms
, std::string const &name="symbols")
: symbols_parser(name)
{
for (auto const& str : syms)
{
for (auto str : syms)
add(str);
}
}
constexpr symbols_parser_impl& operator=(symbols_parser_impl const& rhs)
symbols_parser&
operator=(symbols_parser const& rhs)
{
name_ = rhs.name_;
if constexpr (IsShared)
{
lookup = rhs.lookup;
}
else
{
*lookup = *rhs.lookup;
}
lookup = rhs.lookup;
return *this;
}
constexpr symbols_parser_impl& operator=(symbols_parser_impl&&) = default;
constexpr void clear() noexcept
void clear()
{
lookup->clear();
}
@@ -179,87 +116,93 @@ namespace detail
struct adder;
struct remover;
constexpr symbols_parser_impl& operator=(std::initializer_list<char_type const*> const& syms)
template <typename Str>
adder const&
operator=(Str const& str)
{
lookup->clear();
for (auto const& sym : syms)
{
this->add(sym);
}
return *this;
return add(str);
}
constexpr adder const&
operator=(std::basic_string_view<char_type> const s)
template <typename Str>
friend adder const&
operator+=(symbols_parser& sym, Str const& str)
{
lookup->clear();
return this->add(s);
return sym.add(str);
}
friend constexpr adder const&
operator+=(symbols_parser_impl& sym, std::basic_string_view<char_type> const s)
template <typename Str>
friend remover const&
operator-=(symbols_parser& sym, Str const& str)
{
return sym.add(s);
}
friend constexpr remover const&
operator-=(symbols_parser_impl& sym, std::basic_string_view<char_type> const s)
{
return sym.remove(s);
return sym.remove(str);
}
template <typename F>
constexpr void for_each(F&& f) const
void for_each(F f) const
{
lookup->for_each(std::forward<F>(f));
lookup->for_each(f);
}
template <typename F>
constexpr void for_each(F&& f)
template <typename Str>
value_type& at(Str const& str)
{
lookup->for_each(std::forward<F>(f));
return *lookup->add(traits::get_string_begin<char_type>(str)
, traits::get_string_end<char_type>(str), T());
}
[[nodiscard]] constexpr value_type& at(std::basic_string_view<char_type> const s)
{
return *lookup->add(s.begin(), s.end(), T{});
}
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type* prefix_find(Iterator& first, Iterator const& last) noexcept
template <typename Iterator>
value_type* prefix_find(Iterator& first, Iterator const& last)
{
return lookup->find(first, last, case_compare<Encoding>());
}
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type const* prefix_find(Iterator& first, Iterator const& last) const noexcept
template <typename Iterator>
value_type const* prefix_find(Iterator& first, Iterator const& last) const
{
return lookup->find(first, last, case_compare<Encoding>());
}
[[nodiscard]] constexpr value_type* find(std::basic_string_view<char_type> const s) noexcept
template <typename Str>
value_type* find(Str const& str)
{
return this->find_impl(s.begin(), s.end());
return find_impl(traits::get_string_begin<char_type>(str)
, traits::get_string_end<char_type>(str));
}
[[nodiscard]] constexpr value_type const* find(std::basic_string_view<char_type> const s) const noexcept
template <typename Str>
value_type const* find(Str const& str) const
{
return this->find_impl(s.begin(), s.end());
return find_impl(traits::get_string_begin<char_type>(str)
, traits::get_string_end<char_type>(str));
}
template <std::forward_iterator Iterator, typename Context, typename Attribute>
[[nodiscard]] constexpr bool parse(
Iterator& first, Iterator const& last, Context const& context, unused_type, Attribute& attr
) const noexcept(
noexcept(x3::skip_over(first, last, context)) &&
noexcept(x3::traits::move_to(std::declval<value_type const&>(), attr))
)
private:
template <typename Iterator>
value_type* find_impl(Iterator begin, Iterator end)
{
value_type* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
template <typename Iterator>
value_type const* find_impl(Iterator begin, Iterator end) const
{
value_type const* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
public:
template <typename Iterator, typename Context, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute& attr) const
{
x3::skip_over(first, last, context);
if (value_type const* val_ptr = lookup->find(first, last, x3::get_case_compare<Encoding>(context)))
if (value_type const* val_ptr
= lookup->find(first, last, get_case_compare<Encoding>(context)))
{
x3::traits::move_to(*val_ptr, attr);
return true;
@@ -267,214 +210,124 @@ namespace detail
return false;
}
constexpr void name(std::string const &str)
void name(std::string const &str)
{
name_ = str;
}
[[nodiscard]] constexpr std::string const& name() const noexcept
std::string const &name() const
{
return name_;
}
struct [[maybe_unused]] adder
struct adder
{
template <std::forward_iterator Iterator>
[[maybe_unused]] constexpr adder const&
template <typename Iterator>
adder const&
operator()(Iterator first, Iterator last, T const& val) const
{
sym.lookup->add(first, last, val);
return *this;
}
[[maybe_unused]] constexpr adder const&
operator()(std::basic_string_view<char_type> const s, T const& val = T{}) const
template <typename Str>
adder const&
operator()(Str const& s, T const& val = T()) const
{
sym.lookup->add(s.begin(), s.end(), val);
sym.lookup->add(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s), val);
return *this;
}
[[maybe_unused, deprecated("Don't rely on overloaded comma operator. It's the leftover from the black magic in the 2000s.")]]
constexpr adder const&
operator,(std::basic_string_view<char_type> const s) const
template <typename Str>
adder const&
operator,(Str const& s) const
{
sym.lookup->add(s.begin(), s.end(), T{});
sym.lookup->add(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s), T());
return *this;
}
symbols_parser_impl& sym;
symbols_parser& sym;
};
struct [[maybe_unused]] remover
struct remover
{
template <std::forward_iterator Iterator>
[[maybe_unused]] constexpr remover const&
template <typename Iterator>
remover const&
operator()(Iterator const& first, Iterator const& last) const
{
sym.lookup->remove(first, last);
return *this;
}
[[maybe_unused]] constexpr remover const&
operator()(std::basic_string_view<char_type> const s) const
template <typename Str>
remover const&
operator()(Str const& s) const
{
sym.lookup->remove(s.begin(), s.end());
sym.lookup->remove(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s));
return *this;
}
[[maybe_unused, deprecated("Don't rely on overloaded comma operator. It's the leftover from the black magic in the 2000s.")]]
constexpr remover const&
operator,(std::basic_string_view<char_type> const s) const
template <typename Str>
remover const&
operator,(Str const& s) const
{
sym.lookup->remove(s.begin(), s.end());
sym.lookup->remove(traits::get_string_begin<char_type>(s)
, traits::get_string_end<char_type>(s));
return *this;
}
symbols_parser_impl& sym;
symbols_parser& sym;
};
[[maybe_unused]] adder add;
[[maybe_unused]] remover remove;
private:
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type* find_impl(Iterator begin, Iterator end) noexcept
{
value_type* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
template <std::forward_iterator Iterator>
[[nodiscard]] constexpr value_type const* find_impl(Iterator begin, Iterator end) const noexcept
{
value_type const* r = lookup->find(begin, end, case_compare<Encoding>());
return begin == end ? r : 0;
}
std::conditional_t<IsShared, std::shared_ptr<Lookup>, std::unique_ptr<Lookup>> lookup;
adder add;
remover remove;
std::shared_ptr<Lookup> lookup;
std::string name_;
};
} // detail
template <typename Encoding, typename T = unused_type, typename Lookup = tst<typename Encoding::char_type, T>>
struct shared_symbols_parser
: detail::symbols_parser_impl<shared_symbols_parser<Encoding, T, Lookup>, true, Encoding, T, Lookup>
{
using base_type = detail::symbols_parser_impl<shared_symbols_parser<Encoding, T, Lookup>, true, Encoding, T, Lookup>;
using base_type::base_type;
using base_type::operator=;
};
template <typename Encoding, typename T = unused_type, typename Lookup = tst<typename Encoding::char_type, T>>
struct [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols_parser"))]]
symbols_parser : shared_symbols_parser<Encoding, T, Lookup>
{
using base_type = shared_symbols_parser<Encoding, T, Lookup>;
using base_type::base_type;
using base_type::operator=;
};
template <typename Encoding, typename T = unused_type, typename Lookup = tst<typename Encoding::char_type, T>>
struct unique_symbols_parser
: detail::symbols_parser_impl<unique_symbols_parser<Encoding, T, Lookup>, false, Encoding, T, Lookup>
{
using base_type = detail::symbols_parser_impl<unique_symbols_parser<Encoding, T, Lookup>, false, Encoding, T, Lookup>;
using base_type::base_type;
using base_type::operator=;
};
template <typename Encoding, typename T, typename Lookup>
struct get_info<shared_symbols_parser<Encoding, T, Lookup>>
struct get_info<symbols_parser<Encoding, T, Lookup>>
{
using result_type = std::string const&;
[[nodiscard]] constexpr result_type operator()(shared_symbols_parser<Encoding, T, Lookup> const& symbols) const noexcept
{
return symbols.name();
}
};
template <typename Encoding, typename T, typename Lookup>
struct get_info<unique_symbols_parser<Encoding, T, Lookup>>
{
using result_type = std::string const&;
[[nodiscard]] constexpr result_type operator()(unique_symbols_parser<Encoding, T, Lookup> const& symbols) const noexcept
{
return symbols.name();
}
typedef std::string result_type;
result_type operator()(symbols_parser< Encoding, T
, Lookup
> const& symbols) const
{
return symbols.name();
}
};
namespace standard
{
template <typename T = unused_type>
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::standard, T>;
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::standard, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::standard, T>;
} // standard
using symbols = symbols_parser<char_encoding::standard, T>;
}
using standard::symbols;
using standard::shared_symbols;
using standard::unique_symbols;
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
#ifndef BOOST_SPIRIT_NO_STANDARD_WIDE
namespace standard_wide
{
template <typename T = unused_type>
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::standard_wide, T>;
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::standard_wide, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::standard_wide, T>;
} // standard_wide
using symbols = symbols_parser<char_encoding::standard_wide, T>;
}
#endif
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] ascii
namespace ascii
{
template <typename T = unused_type>
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::ascii, T>;
using symbols = symbols_parser<char_encoding::ascii, T>;
}
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::ascii, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::ascii, T>;
} // ascii
namespace [[deprecated(BOOST_SPIRIT_X3_WRONG_ENCODING_ASSUMPTION_WARNING)]] iso8859_1
namespace iso8859_1
{
template <typename T = unused_type>
using symbols [[deprecated(BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING("symbols"))]]
= x3::shared_symbols_parser<char_encoding::iso8859_1, T>;
using symbols = symbols_parser<char_encoding::iso8859_1, T>;
}
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::iso8859_1, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::iso8859_1, T>;
} // iso8859_1
#ifdef BOOST_SPIRIT_X3_UNICODE
namespace unicode {
template <typename T = unused_type>
using shared_symbols = x3::shared_symbols_parser<char_encoding::unicode, T>;
template <typename T = unused_type>
using unique_symbols = x3::unique_symbols_parser<char_encoding::unicode, T>;
} // unicode
#endif
} // boost::spirit::x3
#undef BOOST_SPIRIT_X3_IMPLICIT_SHARED_SYMBOLS_WARNING
}}}
#if defined(BOOST_MSVC)
# pragma warning(pop)

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,208 +7,129 @@
#if !defined(BOOST_SPIRIT_X3_TST_JUNE_03_2007_1031AM)
#define BOOST_SPIRIT_X3_TST_JUNE_03_2007_1031AM
#include <boost/spirit/home/x3/core/config.hpp>
#include <boost/spirit/home/x3/string/detail/tst_node.hpp>
#include <boost/spirit/home/x3/support/allocator.hpp>
#include <boost/assert.hpp>
#include <boost/spirit/home/x3/string/detail/tst.hpp>
#include <iterator>
#include <memory>
#include <string>
#include <type_traits>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
struct tst_pass_through
{
template <typename Char>
[[nodiscard]] constexpr Char operator()(Char ch) const noexcept
Char operator()(Char ch) const
{
return ch;
}
};
template <typename Char, typename T, typename Alloc = std::allocator<T>>
template <typename Char, typename T>
struct tst
{
using char_type = Char; // the character type
using value_type = T; // the value associated with each entry
using allocator_type = Alloc;
using node = detail::tst_node<Char, T>;
using node_allocator_type = std::allocator_traits<Alloc>::template rebind_alloc<node>;
typedef Char char_type; // the character type
typedef T value_type; // the value associated with each entry
typedef detail::tst_node<Char, T> node;
constexpr tst() noexcept(std::is_nothrow_default_constructible_v<Alloc>) = default;
constexpr explicit tst(Alloc const& alloc) noexcept
: alloc_(alloc)
, node_alloc_(alloc_)
{}
constexpr ~tst() noexcept
{
detail::allocator_ops<tst>::template destroy_deallocate<&tst::node_alloc_, &tst::root_>(*this);
}
constexpr tst(tst const& other)
: alloc_(std::allocator_traits<Alloc>::select_on_container_copy_construction(other.alloc_))
, node_alloc_(std::allocator_traits<node_allocator_type>::select_on_container_copy_construction(other.node_alloc_))
, root_(detail::allocator_ops<tst>::template copy_construct<&tst::node_alloc_, &tst::root_>(*this, other))
tst()
: root(0)
{
}
constexpr tst(tst&& other) noexcept
: alloc_(std::move(other.alloc_))
, node_alloc_(std::move(other.node_alloc_))
, root_(std::exchange(other.root_, nullptr))
~tst()
{
clear();
}
constexpr tst& operator=(tst const& other)
tst(tst const& rhs)
: root(0)
{
if (this == std::addressof(other)) return *this;
detail::allocator_ops<tst>::template copy_assign<&tst::node_alloc_, &tst::root_>(*this, other);
detail::allocator_ops<tst>::template copy_assign<&tst::alloc_>(*this, other);
return *this;
copy(rhs);
}
constexpr tst& operator=(tst&& other)
noexcept(detail::allocator_ops<tst>::template move_assign_noexcept<allocator_type, node_allocator_type>)
tst& operator=(tst const& rhs)
{
if (this == std::addressof(other)) return *this;
detail::allocator_ops<tst>::template move_assign<&tst::node_alloc_, &tst::root_>(*this, std::move(other));
detail::allocator_ops<tst>::template move_assign<&tst::alloc_>(*this, std::move(other));
return *this;
return assign(rhs);
}
template <std::forward_iterator Iterator, typename CaseCompare>
[[nodiscard]] constexpr T* find(Iterator& first, Iterator last, CaseCompare caseCompare) const noexcept
template <typename Iterator, typename CaseCompare>
T* find(Iterator& first, Iterator last, CaseCompare caseCompare) const
{
return node::find(root_, first, last, caseCompare);
return node::find(root, first, last, caseCompare);
}
template <std::forward_iterator Iterator, typename Val>
constexpr T* add(Iterator first, Iterator last, Val&& val)
/*template <typename Iterator>
T* find(Iterator& first, Iterator last) const
{
if (first == last) return nullptr;
if (!root_)
{
root_ = std::allocator_traits<node_allocator_type>::allocate(node_alloc_, 1);
std::allocator_traits<node_allocator_type>::construct(node_alloc_, root_, *first, alloc_);
}
return find(first, last, case_compare<tst_pass_through());
}*/
return this->add(root_, first, last, std::forward<Val>(val));
template <typename Iterator>
T* add(
Iterator first
, Iterator last
, typename boost::call_traits<T>::param_type val)
{
return node::add(root, first, last, val, this);
}
template <std::forward_iterator Iterator>
constexpr void remove(Iterator first, Iterator last) noexcept
template <typename Iterator>
void remove(Iterator first, Iterator last)
{
this->remove(root_, first, last);
node::remove(root, first, last, this);
}
constexpr void clear() noexcept
void clear()
{
if (!root_) return;
std::allocator_traits<node_allocator_type>::destroy(node_alloc_, root_);
std::allocator_traits<node_allocator_type>::deallocate(node_alloc_, root_, 1);
root_ = nullptr;
node::destruct_node(root, this);
root = 0;
}
template <typename F>
constexpr void for_each(F&& f) const
void for_each(F f) const
{
node::for_each(root_, {}, std::forward<F>(f));
node::for_each(root, std::basic_string<Char>(), f);
}
friend struct detail::allocator_ops<tst>;
private:
template <std::forward_iterator Iterator, typename Val>
[[nodiscard]] constexpr T*
add(node* root, Iterator first, Iterator last, Val&& val)
friend struct detail::tst_node<Char, T>;
void copy(tst const& rhs)
{
BOOST_ASSERT(root != nullptr);
BOOST_ASSERT(first != last);
node** pp = &root;
auto c = *first;
while (true)
{
node* const p = *pp;
if (c == p->id)
{
if (++first == last)
{
if (!p->data)
{
p->data = std::allocator_traits<Alloc>::allocate(alloc_, 1);
std::allocator_traits<Alloc>::construct(alloc_, p->data, std::forward<Val>(val));
}
return p->data;
}
pp = &p->eq;
c = *first;
}
else if (c < p->id)
{
pp = &p->lt;
}
else
{
pp = &p->gt;
}
if (!*pp)
{
*pp = std::allocator_traits<node_allocator_type>::allocate(node_alloc_, 1);
std::allocator_traits<node_allocator_type>::construct(node_alloc_, *pp, c);
}
}
root = node::clone_node(rhs.root, this);
}
template <std::forward_iterator Iterator>
constexpr void
remove(node*& p, Iterator first, Iterator last) noexcept
tst& assign(tst const& rhs)
{
if (!p || first == last) return;
auto c = *first;
if (c == p->id)
if (this != &rhs)
{
if (++first == last)
{
if (p->data)
{
std::allocator_traits<Alloc>::destroy(alloc_, p->data);
std::allocator_traits<Alloc>::deallocate(alloc_, p->data, 1);
p->data = nullptr;
}
}
this->remove(p->eq, first, last);
}
else if (c < p->id)
{
this->remove(p->lt, first, last);
}
else
{
this->remove(p->gt, first, last);
}
if (!p->data && !p->lt && !p->eq && !p->gt)
{
std::allocator_traits<node_allocator_type>::destroy(node_alloc_, p);
std::allocator_traits<node_allocator_type>::deallocate(node_alloc_, p, 1);
p = nullptr;
clear();
copy(rhs);
}
return *this;
}
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS Alloc alloc_;
BOOST_SPIRIT_X3_NO_UNIQUE_ADDRESS node_allocator_type node_alloc_;
node* root_ = nullptr;
node* root;
node* new_node(Char id)
{
return new node(id);
}
T* new_data(typename boost::call_traits<T>::param_type val)
{
return new T(val);
}
void delete_node(node* p)
{
delete p;
}
void delete_data(T* p)
{
delete p;
}
};
}
}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,10 +7,9 @@
#if !defined(BOOST_SPIRIT_X3_TST_MAP_JUNE_03_2007_1143AM)
#define BOOST_SPIRIT_X3_TST_MAP_JUNE_03_2007_1143AM
#include <boost/spirit/home/x3/string/tst.hpp>
#include <boost/spirit/home/x3/string/detail/tst.hpp>
#include <unordered_map>
#include <boost/pool/object_pool.hpp>
#include <boost/call_traits.hpp>
namespace boost { namespace spirit { namespace x3
{

View File

@@ -1,252 +0,0 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_X3_SUPPORT_ALLOCATOR_HPP)
#define BOOST_SPIRIT_X3_SUPPORT_ALLOCATOR_HPP
#include <boost/assert.hpp>
#include <memory>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3::detail {
template <typename Klass>
struct allocator_ops
{
template <typename... Allocs>
static constexpr bool move_assign_noexcept = std::conjunction_v<
std::disjunction<
typename std::allocator_traits<Allocs>::propagate_on_container_move_assignment,
typename std::allocator_traits<Allocs>::is_always_equal
>...
>;
template <auto AllocMem, auto Mem>
[[nodiscard]] static constexpr auto copy_construct(Klass& self, Klass const& other)
-> std::remove_reference_t<decltype(self.*Mem)>
{
if (!(other.*Mem)) return nullptr;
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
auto& alloc = self.*AllocMem;
auto* data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *(other.*Mem));
return data;
}
template <auto AllocMem, auto... Mems>
static constexpr void destroy_deallocate(Klass& self) noexcept
{
static_assert(sizeof...(Mems) > 0);
(allocator_ops::destroy_deallocate_impl<AllocMem, Mems>(self), ...);
}
template <auto AllocMem, auto... Mems>
static constexpr void copy_assign(Klass& self, Klass const& other)
{
BOOST_ASSERT(std::addressof(self) != std::addressof(other));
(allocator_ops::copy_assign_impl<AllocMem, Mems>(self, other), ...);
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocca = std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value;
if constexpr (pocca)
{
self.*AllocMem = other.*AllocMem;
}
}
template <auto AllocMem, auto... Mems>
static constexpr void move_assign(Klass& self, Klass&& other)
noexcept(move_assign_noexcept<decltype(self.*AllocMem)>)
{
BOOST_ASSERT(std::addressof(self) != std::addressof(other));
(allocator_ops::move_assign_impl<AllocMem, Mems>(self, std::move(other)), ...);
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocca = std::allocator_traits<Alloc>::propagate_on_container_move_assignment::value;
if constexpr (pocca)
{
self.*AllocMem = std::move(other.*AllocMem);
}
}
private:
template <auto AllocMem, auto Mem>
static constexpr void destroy_deallocate_impl(Klass& self) noexcept
{
auto& data = self.*Mem;
if (!data) return;
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
auto& alloc = self.*AllocMem;
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
template <auto AllocMem, auto Mem>
static constexpr void copy_assign_impl(Klass& self, Klass const& other)
{
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocca = std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value;
auto& data = self.*Mem;
auto& alloc = self.*AllocMem;
auto const& other_data = other.*Mem;
auto const& other_alloc = other.*AllocMem;
if (other_data)
{
if constexpr (std::allocator_traits<Alloc>::is_always_equal::value)
{
if (data)
{
*data = *other_data;
return;
}
if constexpr (pocca)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, *other_data);
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *other_data);
}
return;
}
else if (alloc == other_alloc)
{
if (data)
{
*data = *other_data;
return;
}
if constexpr (pocca)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, *other_data);
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *other_data);
}
return;
}
else
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
data = nullptr;
}
if constexpr (pocca)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, *other_data);
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, *other_data);
}
return;
}
}
else // !other_data
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
data = nullptr;
}
return;
}
}
template <auto AllocMem, auto Mem>
static constexpr void move_assign_impl(Klass& self, Klass&& other)
noexcept(move_assign_noexcept<std::remove_reference_t<decltype(self.*AllocMem)>>)
{
using Alloc = std::remove_reference_t<decltype(self.*AllocMem)>;
constexpr bool pocma = std::allocator_traits<Alloc>::propagate_on_container_move_assignment::value;
auto& data = self.*Mem;
auto& alloc = self.*AllocMem;
auto& other_data = other.*Mem;
auto& other_alloc = other.*AllocMem;
if (other_data)
{
if constexpr (std::allocator_traits<Alloc>::is_always_equal::value)
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
data = std::exchange(other_data, nullptr);
return;
}
else if (alloc == other_alloc)
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
data = std::exchange(other_data, nullptr);
return;
}
else
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
}
if constexpr (pocma)
{
data = std::allocator_traits<Alloc>::allocate(other_alloc, 1);
std::allocator_traits<Alloc>::construct(other_alloc, data, std::move(*other_data));
}
else
{
data = std::allocator_traits<Alloc>::allocate(alloc, 1);
std::allocator_traits<Alloc>::construct(alloc, data, std::move(*other_data));
}
std::allocator_traits<Alloc>::destroy(other_alloc, other_data);
std::allocator_traits<Alloc>::deallocate(other_alloc, other_data, 1);
return;
}
}
else // !other_data
{
if (data)
{
std::allocator_traits<Alloc>::destroy(alloc, data);
std::allocator_traits<Alloc>::deallocate(alloc, data, 1);
data = nullptr;
}
return;
}
}
};
} // boost::spirit::x3::detail
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -12,9 +11,7 @@
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/char/char_class_tags.hpp>
#include <cstdint>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
struct no_case_tag {};
@@ -22,20 +19,19 @@ namespace boost::spirit::x3
struct case_compare
{
template <typename Char, typename CharSet>
[[nodiscard]] constexpr bool in_set(Char ch, CharSet const& set) noexcept
bool in_set(Char ch, CharSet const& set)
{
static_assert(noexcept(set.test(ch)));
return set.test(ch);
}
template <typename Char>
[[nodiscard]] constexpr std::int32_t operator()(Char lc, Char rc) const noexcept
int32_t operator()(Char lc, Char rc) const
{
return lc - rc;
}
template <typename CharClassTag>
[[nodiscard]] constexpr CharClassTag get_char_class_tag(CharClassTag tag) const noexcept
CharClassTag get_char_class_tag(CharClassTag tag) const
{
return tag;
}
@@ -45,18 +41,17 @@ namespace boost::spirit::x3
struct no_case_compare
{
template <typename Char, typename CharSet>
[[nodiscard]] bool in_set(Char ch_, CharSet const& set) noexcept // TODO: constexpr
bool in_set(Char ch_, CharSet const& set)
{
using char_type = typename Encoding::classify_type;
auto ch = char_type(ch_);
static_assert(noexcept(set.test(ch)));
return set.test(ch)
|| set.test(Encoding::islower(ch)
? Encoding::toupper(ch) : Encoding::tolower(ch));
}
template <typename Char>
[[nodiscard]] std::int32_t operator()(Char lc_, Char const rc_) const noexcept // TODO: constexpr
int32_t operator()(Char lc_, Char const rc_) const
{
using char_type = typename Encoding::classify_type;
auto lc = char_type(lc_);
@@ -66,45 +61,43 @@ namespace boost::spirit::x3
}
template <typename CharClassTag>
[[nodiscard]] constexpr CharClassTag get_char_class_tag(CharClassTag tag) const noexcept
CharClassTag get_char_class_tag(CharClassTag tag) const
{
return tag;
}
[[nodiscard]] constexpr alpha_tag get_char_class_tag(lower_tag) const noexcept
alpha_tag get_char_class_tag(lower_tag ) const
{
return {};
}
[[nodiscard]] constexpr alpha_tag get_char_class_tag(upper_tag) const noexcept
alpha_tag get_char_class_tag(upper_tag ) const
{
return {};
}
};
namespace detail
template <typename Encoding>
case_compare<Encoding> get_case_compare_impl(unused_type const&)
{
template <typename Encoding>
[[nodiscard]] constexpr case_compare<Encoding> get_case_compare_impl(unused_type const&) noexcept
{
return {};
}
template <typename Encoding>
[[nodiscard]] constexpr no_case_compare<Encoding> get_case_compare_impl(no_case_tag const&) noexcept
{
return {};
}
} // detail
template <typename Encoding, typename Context>
[[nodiscard]] constexpr decltype(auto) get_case_compare(Context const& context) noexcept
{
return detail::get_case_compare_impl<Encoding>(x3::get<no_case_tag>(context));
return {};
}
auto const no_case_compare_ = no_case_tag{}; // TODO: this should be private
template <typename Encoding>
no_case_compare<Encoding> get_case_compare_impl(no_case_tag const&)
{
return {};
}
} // boost::spirit::x3
template <typename Encoding, typename Context>
inline decltype(auto) get_case_compare(Context const& context)
{
return get_case_compare_impl<Encoding>(x3::get<no_case_tag>(context));
}
auto const no_case_compare_ = no_case_tag{};
}}}
#endif

View File

@@ -4,7 +4,6 @@
Copyright (c) 2011 Jan Frederick Eick
Copyright (c) 2011 Christopher Jefferson
Copyright (c) 2006 Stephen Nutt
Copyright (c) 2025 Nana Sakisaka
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)
@@ -16,7 +15,7 @@
#include <boost/spirit/home/x3/support/traits/attribute_type.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/traits/numeric_traits.hpp>
#include <boost/spirit/home/x3/support/traits/char_encoding_traits.hpp>
#include <boost/spirit/home/support/char_encoding/ascii.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/iteration/local.hpp>
@@ -123,7 +122,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
{
return (Radix <= 10 || (ch >= '0' && ch <= '9'))
? ch - '0'
: traits::char_encoding_traits<Char>::encoding_type::tolower(ch) - 'a' + 10;
: char_encoding::ascii::tolower(ch) - 'a' + 10;
}
};
@@ -343,7 +342,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
if (count + leading_zeros >= MinDigits)
{
traits::move_to(std::move(val), attr);
traits::move_to(val, attr);
first = it;
return true;
}
@@ -445,7 +444,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
{
if (count == 0) // must have at least one digit
return false;
traits::move_to(std::move(val), attr);
traits::move_to(val, attr);
first = it;
return true;
}
@@ -459,7 +458,7 @@ namespace boost { namespace spirit { namespace x3 { namespace detail
, SPIRIT_NUMERIC_INNER_LOOP, _)
}
traits::move_to(std::move(val), attr);
traits::move_to(val, attr);
first = it;
return true;
}

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2011 Jan Frederick Eick
Copyright (c) 2025 Nana Sakisaka
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)
@@ -78,7 +77,7 @@ namespace boost { namespace spirit { namespace x3
T attr;
if (call(first, last, attr))
{
traits::move_to(std::move(attr), attr_);
traits::move_to(attr, attr_);
return true;
}
return false;
@@ -132,7 +131,7 @@ namespace boost { namespace spirit { namespace x3
T attr;
if (call(first, last, attr))
{
traits::move_to(std::move(attr), attr_);
traits::move_to(attr, attr_);
return true;
}
return false;

View File

@@ -0,0 +1,78 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Agustin Berge
http://spirit.sourceforge.net/
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)
=============================================================================*/
#if !defined(BOOST_SPIRIT_X3_SUBCONTEXT_APR_15_2013_0840AM)
#define BOOST_SPIRIT_X3_SUBCONTEXT_APR_15_2013_0840AM
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
namespace boost { namespace spirit { namespace x3
{
template <typename... T>
struct subcontext;
template <>
struct subcontext<>
{
template <typename Context>
subcontext(Context const& /*context*/)
{}
template <typename ID_>
unused_type
get(ID_) const
{
return unused;
}
};
template <typename T>
struct subcontext<T>
: context<typename T::first_type, typename T::second_type>
{
typedef context<
typename T::first_type, typename T::second_type
> context_type;
template <typename Context>
subcontext(Context const& context)
: context_type(x3::get<typename T::first_type>(context))
{}
using context_type::get;
};
template <typename T, typename... Tail>
struct subcontext<T, Tail...>
: subcontext<Tail...>
, context<
typename T::first_type, typename T::second_type
, subcontext<Tail...>
>
{
typedef subcontext<Tail...> base_type;
typedef context<
typename T::first_type, typename T::second_type
, base_type
> context_type;
template <typename Context>
subcontext(Context const& context)
: base_type(context)
, context_type(
x3::get<typename T::first_type>(context)
, *static_cast<base_type*>(this))
{}
using context_type::get;
};
}}}
#endif

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -8,22 +8,22 @@
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_CATEGORY_JAN_4_2012_1150AM)
#define BOOST_SPIRIT_X3_ATTRIBUTE_CATEGORY_JAN_4_2012_1150AM
#include <boost/mpl/identity.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/support/category_of.hpp>
#include <boost/spirit/home/x3/support/traits/is_variant.hpp>
#include <boost/spirit/home/x3/support/traits/is_range.hpp>
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <boost/spirit/home/x3/support/traits/optional_traits.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/support/category_of.hpp>
#include <type_traits>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
struct unused_type;
} // boost::spirit::x3
}}}
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
struct unused_attribute {};
struct plain_attribute {};
@@ -36,89 +36,60 @@ namespace boost::spirit::x3::traits
template <typename T, typename Enable = void>
struct attribute_category
{
using type = plain_attribute;
};
template <typename T>
struct attribute_category<T const> : attribute_category<T> {};
template <typename T>
struct attribute_category<T&> : attribute_category<T> {};
template <typename T>
struct attribute_category<T const&> : attribute_category<T> {};
template <typename T>
struct attribute_category<T&&> : attribute_category<T> {};
template <typename T>
struct attribute_category<T const&&> : attribute_category<T> {};
template <typename T>
using attribute_category_t = typename attribute_category<T>::type;
: mpl::identity<plain_attribute> {};
template <>
struct attribute_category<unused_type>
{
using type = unused_attribute;
};
: mpl::identity<unused_attribute> {};
template <typename T, typename AttributeCategoryTag>
concept CategorizedAttr = std::is_same_v<typename attribute_category<T>::type, AttributeCategoryTag>;
template <>
struct attribute_category<unused_type const>
: mpl::identity<unused_attribute> {};
template <typename T>
concept NonUnusedAttr = !CategorizedAttr<T, unused_attribute>;
struct attribute_category< T
, typename enable_if<
typename mpl::eval_if<
fusion::traits::is_sequence<T>
, fusion::traits::is_associative<T>
, mpl::false_
>::type >::type >
: mpl::identity<associative_attribute> {};
template <typename T>
requires
fusion::traits::is_sequence<T>::value &&
fusion::traits::is_associative<T>::value
struct attribute_category<T>
{
using type = associative_attribute;
};
struct attribute_category< T
, typename enable_if<
mpl::and_<
fusion::traits::is_sequence<T>
, mpl::not_<fusion::traits::is_associative<T> >
> >::type >
: mpl::identity<tuple_attribute> {};
template <typename T>
requires
fusion::traits::is_sequence<T>::value &&
(!fusion::traits::is_associative<T>::value)
struct attribute_category<T>
{
using type = tuple_attribute;
};
struct attribute_category<T,
typename enable_if<traits::is_variant<T>>::type>
: mpl::identity<variant_attribute> {};
template <typename T>
requires is_variant_v<T>
struct attribute_category<T>
{
using type = variant_attribute;
};
struct attribute_category<T,
typename enable_if<traits::is_optional<T>>::type>
: mpl::identity<optional_attribute> {};
template <typename T>
requires is_optional_v<T>
struct attribute_category<T>
{
using type = optional_attribute;
};
struct attribute_category<T,
typename enable_if<traits::is_range<T>>::type>
: mpl::identity<range_attribute> {};
template <typename T>
requires is_range_v<T>
struct attribute_category<T>
{
using type = range_attribute;
};
struct attribute_category< T
, typename enable_if<
mpl::and_<
traits::is_container<T>
, mpl::not_<fusion::traits::is_sequence<T> >
, mpl::not_<traits::is_range<T> >
> >::type >
: mpl::identity<container_attribute> {};
template <typename T>
requires
(!traits::is_range_v<T>) &&
traits::is_container_v<T> &&
(!fusion::traits::is_sequence<T>::value)
struct attribute_category<T>
{
using type = container_attribute;
};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Agustin Berge
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -9,9 +9,11 @@
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_OF_JAN_7_2012_0914AM)
#define BOOST_SPIRIT_X3_ATTRIBUTE_OF_JAN_7_2012_0914AM
#include <type_traits>
#include <boost/spirit/home/x3/support/utility/sfinae.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/utility/enable_if.hpp>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// Get the attribute type of a component. By default, this gets the
@@ -22,37 +24,31 @@ namespace boost::spirit::x3::traits
template <typename Component, typename Context, typename Enable = void>
struct attribute_of;
template <typename Component, typename Context, typename Enable = void>
using attribute_of_t = typename attribute_of<Component, Context>::type;
template <typename Component, typename Context>
requires requires {
typename Component::attribute_type;
}
struct attribute_of<Component, Context>
namespace detail
{
using type = typename Component::attribute_type;
};
template <typename Component, typename Context, typename Enable = void>
struct default_attribute_of;
template <typename Component, typename Context>
requires requires {
typename Component::template attribute<Context>::type;
}
struct attribute_of<Component, Context>
{
using type = typename Component::template attribute<Context>::type;
};
template <typename Component, typename Context>
struct default_attribute_of<Component, Context,
typename disable_if_substitution_failure<
typename Component::attribute_type>::type>
: mpl::identity<typename Component::attribute_type> {};
template <typename Component, typename Context>
requires Component::is_pass_through_unary
struct attribute_of<Component, Context>
{
static_assert(requires {
typename Component::subject_type;
});
using type = typename attribute_of<typename Component::subject_type, Context>::type;
};
template <typename Component, typename Context>
struct default_attribute_of<Component, Context,
typename disable_if_substitution_failure<
typename Component::template attribute<Context>::type>::type>
: Component::template attribute<Context> {};
} // boost::spirit::x3::traits
template <typename Component, typename Context>
struct default_attribute_of<Component, Context,
typename enable_if_c<Component::is_pass_through_unary>::type>
: attribute_of<typename Component::subject_type, Context>{};
}
template <typename Component, typename Context, typename Enable>
struct attribute_of : detail::default_attribute_of<Component, Context> {};
}}}}
#endif

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -8,20 +8,19 @@
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_TYPE_JAN_5_2012_0358PM)
#define BOOST_SPIRIT_X3_ATTRIBUTE_TYPE_JAN_5_2012_0358PM
namespace boost::spirit::x3::traits
#include <boost/mpl/identity.hpp>
namespace boost { namespace spirit { namespace x3 { namespace traits
{
// Retrieve the attribute type to use from the given type.
///////////////////////////////////////////////////////////////////////////
// Retrieve the attribute type to use from the given type
//
// This is needed to extract the correct attribute type from proxy classes
// as utilized in `FUSION_ADAPT_ADT` et. al.
// as utilized in FUSION_ADAPT_ADT et. al.
///////////////////////////////////////////////////////////////////////////
template <typename Attribute, typename Enable = void>
struct attribute_type
{
using type = Attribute;
};
struct attribute_type : mpl::identity<Attribute> {};
template <typename Attribute>
using attribute_type_t = typename attribute_type<Attribute>::type;
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,62 +0,0 @@
/*=============================================================================
Copyright (c) 2025 Nana Sakisaka
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_SPIRIT_X3_SUPPORT_TRAITS_CHAR_ENCODING_TRAITS_HPP
#define BOOST_SPIRIT_X3_SUPPORT_TRAITS_CHAR_ENCODING_TRAITS_HPP
#include <boost/spirit/home/x3/char/char.hpp>
#include <boost/spirit/home/x3/char/literal_char.hpp>
#include <boost/spirit/home/x3/string/literal_string.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
#endif
namespace boost::spirit::x3::traits
{
namespace detail
{
template <typename Encoding>
struct char_encoding_traits_impl
{
using encoding_type = Encoding;
template <class... Args>
[[nodiscard]] static constexpr auto lit(Args&&... args)
noexcept(noexcept(Encoding::lit(std::forward<Args>(args)...)))
{
return Encoding::lit(std::forward<Args>(args)...);
}
template <class... Args>
[[nodiscard]] static constexpr auto string(Args&&... args)
noexcept(noexcept(Encoding::string(std::forward<Args>(args)...)))
{
return Encoding::string(std::forward<Args>(args)...);
}
};
} // detail
template <traits::CharLike CharT>
struct char_encoding_traits;
template <>
struct char_encoding_traits<char> : detail::char_encoding_traits_impl<char_encoding::standard> {};
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
template <>
struct char_encoding_traits<wchar_t> : detail::char_encoding_traits_impl<char_encoding::standard_wide> {};
#endif
#ifdef BOOST_SPIRIT_X3_UNICODE
template <>
struct char_encoding_traits<char32_t> : detail::char_encoding_traits_impl<char_encoding::unicode> {};
#endif
} // boost::spirit::x3::traits
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -12,55 +12,49 @@
#include <boost/fusion/support/category_of.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/fusion/include/deque.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/make_void.hpp>
#include <ranges>
#include <iterator>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename T>
struct is_container : std::false_type {};
// TODO: fully replace this trait using std::ranges
template <typename T>
requires
//std::ranges::range<T> && // TODO: this breaks `fusion::vector<>`; test case in omit.cpp.
requires {
typename T::value_type;
typename T::iterator;
typename T::size_type;
typename T::reference;
}
struct is_container<T> : std::true_type {};
template <typename T>
constexpr bool is_container_v = is_container<T>::value;
template <typename T>
concept ContainerAttr = is_container_v<std::remove_cvref_t<T>>;
template <typename T>
struct is_associative : std::false_type {};
template <typename T>
requires requires {
typename T::key_type;
}
struct is_associative<T> : std::true_type {};
template <typename T>
constexpr bool is_associative_v = is_associative<T>::value;
///////////////////////////////////////////////////////////////////////////
// This file contains some container utils for stl containers.
///////////////////////////////////////////////////////////////////////////
namespace detail
{
template <typename T, typename Enabler = void>
struct is_container_impl : mpl::false_ {};
template <typename T>
struct remove_value_const : std::type_identity<T> {};
struct is_container_impl<T, void_t<
typename T::value_type, typename T::iterator,
typename T::size_type, typename T::reference> > : mpl::true_ {};
template <typename T, typename Enabler = void>
struct is_associative_impl : mpl::false_ {};
template <typename T>
struct is_associative_impl<T, void_t<typename T::key_type>>
: mpl::true_ {};
}
template <typename T>
using is_container = typename detail::is_container_impl<T>::type;
template <typename T>
using is_associative = typename detail::is_associative_impl<T>::type;
///////////////////////////////////////////////////////////////////////////
namespace detail
{
template <typename T>
struct remove_value_const : mpl::identity<T> {};
template <typename T>
struct remove_value_const<T const> : remove_value_const<T> {};
@@ -68,21 +62,18 @@ namespace boost::spirit::x3::traits
template <typename F, typename S>
struct remove_value_const<std::pair<F, S>>
{
using first_type = typename remove_value_const<F>::type;
using second_type = typename remove_value_const<S>::type;
using type = std::pair<first_type, second_type>;
typedef typename remove_value_const<F>::type first_type;
typedef typename remove_value_const<S>::type second_type;
typedef std::pair<first_type, second_type> type;
};
}
///////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct container_value
: detail::remove_value_const<typename Container::value_type>
: detail::remove_value_const<typename Container::value_type>
{};
template <typename Container>
using container_value_t = typename container_value<Container>::type;
template <typename Container>
struct container_value<Container const> : container_value<Container> {};
@@ -91,36 +82,32 @@ namespace boost::spirit::x3::traits
// saved to container, we simply return whole fusion::map as is
// so that check can be done in traits::is_substitute specialisation
template <typename T>
struct container_value<
T,
std::enable_if_t<
std::conditional_t<
fusion::traits::is_sequence<T>::value,
fusion::traits::is_associative<T>,
std::false_type
>::type::value
>
> : std::type_identity<T> {};
struct container_value<T
, typename enable_if<typename mpl::eval_if <
fusion::traits::is_sequence<T>
, fusion::traits::is_associative<T>
, mpl::false_ >::type >::type>
: mpl::identity<T> {};
template <>
struct container_value<unused_type> : std::type_identity<unused_type> {};
struct container_value<unused_type> : mpl::identity<unused_type> {};
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct container_iterator
: std::type_identity<typename Container::iterator> {};
: mpl::identity<typename Container::iterator> {};
template <typename Container>
struct container_iterator<Container const>
: std::type_identity<typename Container::const_iterator> {};
: mpl::identity<typename Container::const_iterator> {};
template <>
struct container_iterator<unused_type>
: std::type_identity<unused_type const*> {};
: mpl::identity<unused_type const*> {};
template <>
struct container_iterator<unused_type const>
: std::type_identity<unused_type const*> {};
: mpl::identity<unused_type const*> {};
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename T>
@@ -169,13 +156,13 @@ namespace boost::spirit::x3::traits
{
private:
template <typename Iterator>
static void insert(Container& c, Iterator first, Iterator last, std::false_type)
static void insert(Container& c, Iterator first, Iterator last, mpl::false_)
{
c.insert(c.end(), first, last);
}
template <typename Iterator>
static void insert(Container& c, Iterator first, Iterator last, std::true_type)
static void insert(Container& c, Iterator first, Iterator last, mpl::true_)
{
c.insert(first, last);
}
@@ -203,26 +190,23 @@ namespace boost::spirit::x3::traits
///////////////////////////////////////////////////////////////////////////
template <typename Container, typename Enable = void>
struct is_empty_container;
[[nodiscard]] constexpr bool is_empty(unused_type) noexcept
struct is_empty_container
{
return true;
}
static bool call(Container const& c)
{
return c.empty();
}
};
template <ContainerAttr Container>
[[nodiscard]] constexpr bool is_empty(Container const& c) noexcept
template <typename Container>
inline bool is_empty(Container const& c)
{
return is_empty_container<Container>::call(c);
}
template <ContainerAttr Container>
requires requires {
std::ranges::empty(std::declval<Container const&>());
}
[[nodiscard]] constexpr bool is_empty(Container const& c) noexcept
inline bool is_empty(unused_type)
{
return std::ranges::empty(c);
return true;
}
///////////////////////////////////////////////////////////////////////////
@@ -340,17 +324,17 @@ namespace boost::spirit::x3::traits
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct build_container : std::type_identity<std::vector<T>> {};
struct build_container : mpl::identity<std::vector<T>> {};
template <typename T>
struct build_container<boost::fusion::deque<T> > : build_container<T> {};
template <>
struct build_container<unused_type> : std::type_identity<unused_type> {};
struct build_container<unused_type> : mpl::identity<unused_type> {};
template <>
struct build_container<char> : std::type_identity<std::string> {};
struct build_container<char> : mpl::identity<std::string> {};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2013 Agustin Berge
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,21 +8,20 @@
#if !defined(BOOST_SPIRIT_X3_HANDLES_CONTAINER_DEC_18_2010_0920AM)
#define BOOST_SPIRIT_X3_HANDLES_CONTAINER_DEC_18_2010_0920AM
#include <type_traits>
#include <boost/mpl/bool.hpp>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// Whether a component handles container attributes intrinsically
// (or whether container attributes need to be split up separately).
// By default, this gets the Component's handles_container nested value.
// Components may specialize this if such a handles_container is not
// Components may specialize this if such a handles_container is not
// readily available (e.g. expensive to compute at compile time).
///////////////////////////////////////////////////////////////////////////
template <typename Component, typename Context, typename Enable = void>
struct handles_container : std::bool_constant<Component::handles_container> {};
struct handles_container : mpl::bool_<Component::handles_container> {};
template <typename Component, typename Context>
constexpr bool handles_container_v = handles_container<Component, Context>::value;
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Agustin Berge
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -10,54 +10,50 @@
#define BOOST_SPIRIT_X3_HAS_ATTRIBUTE_JUN_6_2012_1714PM
#include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
#include <boost/spirit/home/x3/support/utility/sfinae.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
#include <concepts>
#include <type_traits>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
struct unused_type;
} // boost::spirit::x3
}}}
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
// TODO: make these 'Component' depend on the concept.
// It is currently hard to implement due to circular dependency.
// Whether a component has an attribute. By default, this compares the
///////////////////////////////////////////////////////////////////////////
// Whether a component has an attribute. By default, this compares the
// component attribute against unused_type. If the component provides a
// nested constant expression has_attribute as a hint, that value is used
// instead. Components may specialize this.
///////////////////////////////////////////////////////////////////////////
template <typename Component, typename Context, typename Enable = void>
struct has_attribute
struct has_attribute;
namespace detail
{
static_assert(requires {
typename attribute_of<Component, Context>::type;
});
static constexpr bool value = !std::is_same_v<attribute_of_t<Component, Context>, unused_type>;
};
template <typename Component, typename Context, typename Enable = void>
struct default_has_attribute
: mpl::not_<is_same<unused_type,
typename attribute_of<Component, Context>::type>> {};
template <typename Component, typename Context>
constexpr bool has_attribute_v = has_attribute<Component, Context>::value;
template <typename Component, typename Context>
struct default_has_attribute<Component, Context,
typename disable_if_substitution_failure<
mpl::bool_<Component::has_attribute>>::type>
: mpl::bool_<Component::has_attribute> {};
template <typename Component, typename Context>
struct default_has_attribute<Component, Context,
typename enable_if_c<Component::is_pass_through_unary>::type>
: has_attribute<typename Component::subject_type, Context> {};
}
template <typename Component, typename Context, typename Enable>
struct has_attribute : detail::default_has_attribute<Component, Context> {};
template <typename Component, typename Context>
requires requires {
{ Component::has_attribute } -> std::same_as<bool>;
}
struct has_attribute<Component, Context>
: std::bool_constant<Component::has_attribute>
{};
template <typename Component, typename Context>
requires Component::is_pass_through_unary
struct has_attribute<Component, Context>
{
static_assert(requires {
typename Component::subject_type;
});
static constexpr bool value = has_attribute_v<typename Component::subject_type, Context>;
};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2014 Agustin Berge
Copyright (c) 2025 Nana Sakisaka
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)
@@ -9,19 +8,26 @@
#if !defined(BOOST_SPIRIT_X3_IS_PARSER_MAY_20_2013_0235PM)
#define BOOST_SPIRIT_X3_IS_PARSER_MAY_20_2013_0235PM
#include <boost/mpl/bool.hpp>
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/support/utility/sfinae.hpp>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
// is_parser<T>: metafunction that evaluates to `std::true_type` if `T`
// models `X3Subject`, `std::false_type` otherwise
///////////////////////////////////////////////////////////////////////////
// is_parser<T>: metafunction that evaluates to mpl::true_ if a type T
// can be used as a parser, mpl::false_ otherwise
///////////////////////////////////////////////////////////////////////////
template <typename T, typename Enable = void>
struct [[deprecated("Use the concept `x3::X3Subject`")]]
is_parser : std::bool_constant<X3Subject<T>>
struct is_parser
: mpl::false_
{};
} // boost::spirit::x3::traits
template <typename T>
struct is_parser<T, typename disable_if_substitution_failure<
typename extension::as_parser<T>::type>::type>
: mpl::true_
{};
}}}}
#endif

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -8,27 +8,20 @@
#if !defined(BOOST_SPIRIT_X3_IS_RANGE_DEC_06_2017_1900PM)
#define BOOST_SPIRIT_X3_IS_RANGE_DEC_06_2017_1900PM
#include <boost/range/range_fwd.hpp> // TODO: remove this
#include <boost/range/range_fwd.hpp>
#include <boost/mpl/bool.hpp>
#include <iterator>
#include <ranges>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename T, typename Enable = void>
struct is_range : std::false_type {};
struct is_range
: mpl::false_
{};
template <typename T>
constexpr bool is_range_v = is_range<T>::value;
template <typename T>
struct [[deprecated("Use std::ranges::subrange")]]
is_range<boost::iterator_range<T>> : std::true_type {};
template <std::input_or_output_iterator It, std::sentinel_for<It> Se, std::ranges::subrange_kind Kind>
struct is_range<std::ranges::subrange<It, Se, Kind>> : std::true_type {};
} // boost::spirit::x3::traits
struct is_range<boost::iterator_range<T>>
: mpl::true_
{};
}}}}
#endif

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -9,8 +9,6 @@
#define BOOST_SPIRIT_X3_IS_SUBSTITUTE_JAN_9_2012_1049PM
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <boost/spirit/home/x3/support/traits/tuple_traits.hpp>
#include <boost/spirit/home/x3/support/traits/optional_traits.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/include/value_at_key.hpp>
@@ -22,148 +20,140 @@
#include <boost/mpl/size.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/count_if.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/optional/optional.hpp>
#include <boost/type_traits/is_same.hpp>
#include <optional>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// Find out if T can be a (strong) substitute for Attribute
///////////////////////////////////////////////////////////////////////////
template <typename T, typename Attribute, typename Enable = void>
struct is_substitute;
template <typename T, typename Attribute>
constexpr bool is_substitute_v = is_substitute<T, Attribute>::value;
template <typename Variant, typename Attribute>
struct variant_has_substitute;
// TODO: reduce MPL usage
namespace detail
{
template <typename T, typename Attribute>
struct value_type_is_substitute
: is_substitute<container_value_t<T>, container_value_t<Attribute>>
: is_substitute<
typename container_value<T>::type
, typename container_value<Attribute>::type>
{};
template <typename T, typename Attribute, typename Enable = void>
struct is_substitute_impl : std::false_type {};
struct is_substitute_impl : mpl::false_ {};
template <typename T, typename Attribute>
requires std::conjunction_v<
fusion::traits::is_sequence<T>,
fusion::traits::is_sequence<Attribute>
>
struct is_substitute_impl<T, Attribute>
: mpl::equal<T, Attribute, is_substitute<mpl::_1, mpl::_2>>
{};
struct is_substitute_impl<T, Attribute,
typename enable_if<
mpl::and_<
fusion::traits::is_sequence<T>,
fusion::traits::is_sequence<Attribute>,
mpl::equal<T, Attribute, is_substitute<mpl::_1, mpl::_2>>
>
>::type>
: mpl::true_ {};
template <typename T, typename Attribute>
requires
is_container_v<T> &&
is_container_v<Attribute>
struct is_substitute_impl<T, Attribute>
: value_type_is_substitute<T, Attribute>
{};
struct is_substitute_impl<T, Attribute,
typename enable_if<
mpl::and_<
is_container<T>,
is_container<Attribute>,
value_type_is_substitute<T, Attribute>
>
>::type>
: mpl::true_ {};
template <typename T, typename Attribute>
requires is_variant_v<Attribute>
struct is_substitute_impl<T, Attribute>
: variant_has_substitute<Attribute, T>
struct is_substitute_impl<T, Attribute,
typename enable_if<
is_variant<Attribute>
>::type>
: variant_has_substitute<Attribute, T>
{};
}
template <typename T, typename Attribute, typename Enable>
template <typename T, typename Attribute, typename Enable /*= void*/>
struct is_substitute
: std::disjunction<
std::is_same<T, Attribute>,
detail::is_substitute_impl<T, Attribute>
>
{};
: mpl::or_<
is_same<T, Attribute>,
detail::is_substitute_impl<T, Attribute>> {};
// for reference T
template <typename T, typename Attribute>
struct is_substitute<T&, Attribute>
: is_substitute<T, Attribute>
{};
template <typename T, typename Attribute, typename Enable>
struct is_substitute<T&, Attribute, Enable>
: is_substitute<T, Attribute, Enable> {};
// for reference Attribute
template <typename T, typename Attribute>
struct is_substitute<T, Attribute&>
: is_substitute<T, Attribute>
{};
namespace detail
{
template <typename Key, typename Value, typename Map>
struct has_fusion_kv_in_map : std::false_type {};
template <typename Key, typename Value, typename Map>
requires fusion::result_of::has_key<Map, Key>::value
struct has_fusion_kv_in_map<Key, Value, Map> : is_substitute<
typename fusion::result_of::value_at_key<Map, Key>::type,
Value
> {};
} // detail
template <typename T, typename Attribute, typename Enable>
struct is_substitute<T, Attribute&, Enable>
: is_substitute<T, Attribute, Enable> {};
// 2 element mpl tuple is compatible with fusion::map if:
// - it's first element type is existing key in map
// - it second element type is compatible to type stored at the key in map
template <typename T, typename Attribute>
requires std::conjunction_v<
fusion::traits::is_sequence<T>,
fusion::traits::is_sequence<Attribute>,
traits::has_size<T, 2>,
fusion::traits::is_associative<Attribute>
>
struct is_substitute<T, Attribute>
struct is_substitute<T, Attribute
, typename enable_if<
typename mpl::eval_if<
mpl::and_<fusion::traits::is_sequence<T>
, fusion::traits::is_sequence<Attribute>>
, mpl::and_<traits::has_size<T, 2>
, fusion::traits::is_associative<Attribute>>
, mpl::false_>::type>::type>
{
// Checking that "p_key >> p_value" parser can
// checking that "p_key >> p_value" parser can
// store it's result in fusion::map attribute
using p_key = typename mpl::at_c<T, 0>::type;
using p_value = typename mpl::at_c<T, 1>::type;
typedef typename mpl::at_c<T, 0>::type p_key;
typedef typename mpl::at_c<T, 1>::type p_value;
// For simple `p_key` type we just check that
// for simple p_key type we just check that
// such key can be found in attr and that value under that key
// matches `p_value`.
// matches p_value
template <typename Key, typename Value, typename Map>
struct has_kv_in_map
: mpl::eval_if<
fusion::result_of::has_key<Map, Key>
, mpl::apply<
is_substitute<
fusion::result_of::value_at_key<mpl::_1, Key>
, Value>
, Map>
, mpl::false_>
{};
// Otherwise, if p_key is variant over multiple types (as a result of
// "(key1|key2|key3) >> p_value" parser), check that all
// keys are found in `fusion::map` attribute and that values
// under these keys match `p_value`.
// if p_key is variant over multiple types (as a result of
// "(key1|key2|key3) >> p_value" parser) check that all
// keys are found in fusion::map attribute and that values
// under these keys match p_value
template <typename Variant>
struct variant_kv
: mpl::equal_to<
mpl::size<typename Variant::types>,
mpl::size<
mpl::filter_view<
typename Variant::types,
detail::has_fusion_kv_in_map<mpl::_1, p_value, Attribute>
>
>
mpl::size< typename Variant::types>
, mpl::size< mpl::filter_view<typename Variant::types
, has_kv_in_map<mpl::_1, p_value, Attribute>>>
>
{};
static constexpr bool value = std::conditional_t<
is_variant_v<p_key>,
variant_kv<p_key>,
detail::has_fusion_kv_in_map<p_key, p_value, Attribute>
>::value;
typedef typename
mpl::eval_if<
is_variant<p_key>
, variant_kv<p_key>
, has_kv_in_map<p_key, p_value, Attribute>
>::type
type;
};
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
template <typename T, typename Attribute>
struct [[deprecated("Use std::optional")]] is_substitute<boost::optional<T>, boost::optional<Attribute>>
: is_substitute<T, Attribute>
{};
#endif
template <typename T, typename Attribute>
struct is_substitute<std::optional<T>, std::optional<Attribute>>
: is_substitute<T, Attribute>
{};
} // boost::spirit::x3::traits
struct is_substitute<optional<T>, optional<Attribute>>
: is_substitute<T, Attribute> {};
}}}}
#endif

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -8,40 +8,34 @@
#if !defined(BOOST_SPIRIT_X3_IS_VARIANT_JAN_10_2012_0823AM)
#define BOOST_SPIRIT_X3_IS_VARIANT_JAN_10_2012_0823AM
#include <boost/variant/variant_fwd.hpp> // TODO: remove this
#include <boost/variant.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/bool.hpp>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
// TODO: define a legit concept for determining variant-like types
namespace detail
{
// By declaring a nested struct in your class/struct, you tell
// spirit that it is regarded as a variant type. The minimum
// required interface for such a variant is that it has constructors
// for various types supported by your variant and a typedef 'types'
// which is an mpl sequence of the contained types.
//
// This is an intrusive interface. For a non-intrusive interface,
// use the is_variant trait.
BOOST_MPL_HAS_XXX_TRAIT_DEF(adapted_variant_tag)
}
template <typename T, typename Enabled = void>
struct is_variant : std::false_type {};
template <typename T>
constexpr bool is_variant_v = is_variant<T>::value;
// By declaring a nested struct named `adapted_variant_tag` in
// your class, you tell spirit that it is regarded as a variant type.
// The minimum required interface for such a variant is that it has
// constructors for various types supported by your variant and a
// typedef 'types' which is an mpl sequence of the contained types.
// Note (2025): The above spec is obsolete and will change in the near future.
//
// This is an intrusive interface. For a non-intrusive interface,
// specialize the is_variant trait.
template <typename T>
requires requires {
typename T::adapted_variant_tag;
}
struct is_variant<T> : std::true_type
template <typename T, typename Enable = void>
struct is_variant
: detail::has_adapted_variant_tag<T>
{};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct is_variant<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
: std::true_type
: mpl::true_
{};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2013 Agustin Berge
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -17,259 +17,212 @@
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/include/front.hpp>
#include <boost/fusion/include/move.hpp>
#include <boost/fusion/include/copy.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#ifndef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
# include <boost/range/iterator_range_core.hpp> // deprecated
#endif
#include <memory>
#include <iterator>
#include <ranges>
#include <type_traits>
#include <utility>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
// Identical types ---------------------------------------
//
// Note that these overloads must be strictly "more constrained"
// than any of the other overloads.
//
// Such resolution should be possible even without an extra
// constraint that checks `std::is_same_v<Source, Dest>`, thanks to
// the ordinary overload resolution rules of C++.
template <typename Source, typename Dest>
inline void move_to(Source&& src, Dest& dest);
template <typename T>
requires (!CategorizedAttr<T, unused_attribute>)
constexpr void move_to(T const&& src, T& dest)
noexcept(std::is_nothrow_assignable_v<T&, T const&&>)
inline void move_to(T& src, T& dest);
template <typename T>
inline void move_to(T const& src, T& dest);
template <typename T>
inline void move_to(T&& src, T& dest);
template <typename Iterator, typename Dest>
inline void move_to(Iterator first, Iterator last, Dest& dest);
template <typename Dest>
inline void move_to(unused_type, Dest&) {}
template <typename Source>
inline void move_to(Source&, unused_type) {}
inline void move_to(unused_type, unused_type) {}
template <typename Iterator>
inline void
move_to(Iterator, Iterator, unused_type) {}
namespace detail
{
template <typename Source, typename Dest>
inline void
move_to(Source&, Dest&, unused_attribute) {}
template <typename Source, typename Dest>
inline void
move_to_plain(Source& src, Dest& dest, mpl::false_) // src is not a single-element tuple
{
dest = std::move(src);
}
template <typename Source, typename Dest>
inline void
move_to_plain(Source& src, Dest& dest, mpl::true_) // src is a single-element tuple
{
dest = std::move(fusion::front(src));
}
template <typename Source, typename Dest>
inline void
move_to(Source& src, Dest& dest, plain_attribute)
{
typename mpl::and_<
fusion::traits::is_sequence<Source>,
is_size_one_sequence<Source> >
is_single_element_sequence;
move_to_plain(src, dest, is_single_element_sequence);
}
template <typename Source, typename Dest>
inline typename enable_if<is_container<Source>>::type
move_to(Source& src, Dest& dest, container_attribute)
{
traits::move_to(src.begin(), src.end(), dest);
}
template <typename Source, typename Dest>
inline typename enable_if<
mpl::and_<
is_same_size_sequence<Dest, Source>,
mpl::not_<is_size_one_sequence<Dest> > >
>::type
move_to(Source& src, Dest& dest, tuple_attribute)
{
fusion::move(std::move(src), dest);
}
template <typename Source, typename Dest>
inline typename enable_if<
is_size_one_sequence<Dest>
>::type
move_to(Source& src, Dest& dest, tuple_attribute)
{
traits::move_to(src, fusion::front(dest));
}
template <typename Source, typename Dest>
inline void
move_to(Source& src, Dest& dest, variant_attribute, mpl::false_)
{
dest = std::move(src);
}
template <typename Source, typename Dest>
inline void
move_to_variant_from_single_element_sequence(Source& src, Dest& dest, mpl::false_)
{
// dest is a variant, src is a single element fusion sequence that the variant
// cannot directly hold. We'll try to unwrap the single element fusion sequence.
// Make sure that the Dest variant can really hold Source
static_assert(variant_has_substitute<Dest, typename fusion::result_of::front<Source>::type>::value,
"Error! The destination variant (Dest) cannot hold the source type (Source)");
dest = std::move(fusion::front(src));
}
template <typename Source, typename Dest>
inline void
move_to_variant_from_single_element_sequence(Source& src, Dest& dest, mpl::true_)
{
// dest is a variant, src is a single element fusion sequence that the variant
// *can* directly hold.
dest = std::move(src);
}
template <typename Source, typename Dest>
inline void
move_to(Source& src, Dest& dest, variant_attribute, mpl::true_)
{
move_to_variant_from_single_element_sequence(src, dest, variant_has_substitute<Dest, Source>());
}
template <typename Source, typename Dest>
inline void
move_to(Source& src, Dest& dest, variant_attribute tag)
{
move_to(src, dest, tag, is_size_one_sequence<Source>());
}
template <typename Source, typename Dest>
inline void
move_to(Source& src, Dest& dest, optional_attribute)
{
dest = std::move(src);
}
template <typename Iterator>
inline void
move_to(Iterator, Iterator, unused_type, unused_attribute) {}
template <typename Iterator, typename Dest>
inline void
move_to(Iterator first, Iterator last, Dest& dest, container_attribute)
{
if (is_empty(dest))
dest = Dest(first, last);
else
append(dest, first, last);
}
template <typename Iterator, typename Dest>
inline typename enable_if<
is_size_one_sequence<Dest>
>::type
move_to(Iterator first, Iterator last, Dest& dest, tuple_attribute)
{
traits::move_to(first, last, fusion::front(dest));
}
template <typename Iterator>
inline void
move_to(Iterator first, Iterator last, boost::iterator_range<Iterator>& rng, range_attribute)
{
rng = {first, last};
}
}
template <typename Source, typename Dest>
inline void move_to(Source&& src, Dest& dest)
{
detail::move_to(src, dest, typename attribute_category<Dest>::type());
}
template <typename T>
inline void move_to(T& src, T& dest)
{
BOOST_ASSERT(boost::addressof(src) != boost::addressof(dest));
dest = std::move(src);
}
template <typename T>
requires (!CategorizedAttr<T, unused_attribute>)
constexpr void move_to(T&& src, T& dest)
noexcept(std::is_nothrow_assignable_v<T&, T&&>)
{
dest = std::move(src);
}
template <typename T>
requires (!CategorizedAttr<T, unused_attribute>)
constexpr void move_to(T const& src, T& dest)
noexcept(std::is_nothrow_copy_assignable_v<T>)
inline void move_to(T const& src, T& dest)
{
BOOST_ASSERT(boost::addressof(src) != boost::addressof(dest));
dest = src;
}
template <typename T>
requires (!CategorizedAttr<T, unused_attribute>)
constexpr void move_to(T&, T&) noexcept
inline void move_to(T&& src, T& dest)
{
static_assert(
!std::is_const_v<T>,
"`x3::move_to(T const&, T const&)` is not allowed"
);
static_assert(
false,
"lvalue reference detected on the `src` argument of `x3::move_to`. "
"The caller is definitely lacking `std::move` or `std::forward`. If you "
"intend to *copy* the mutable value, apply `x3::move_to(std::as_const(attr_), attr)`."
);
// Banned: possible, but bug-prone.
// dest = std::move(src);
BOOST_ASSERT(boost::addressof(src) != boost::addressof(dest));
dest = std::move(src);
}
// unused_type -------------------------------------------
template <typename Source, typename Dest>
requires
CategorizedAttr<Source, unused_attribute> ||
CategorizedAttr<Dest, unused_attribute>
constexpr void move_to(Source&&, Dest&) noexcept
template <typename Iterator, typename Dest>
inline void move_to(Iterator first, Iterator last, Dest& dest)
{
// $$$ Use std::move_iterator when iterator is not a const-iterator $$$
detail::move_to(first, last, dest, typename attribute_category<Dest>::type());
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename Dest>
requires
std::is_same_v<std::remove_const_t<Dest>, unused_type>
constexpr void
move_to(It, Se, Dest&) noexcept
{
}
// Category specific --------------------------------------
template <NonUnusedAttr Source, CategorizedAttr<plain_attribute> Dest>
requires is_size_one_sequence_v<Source>
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(noexcept(dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)))))
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)));
}
template <NonUnusedAttr Source, CategorizedAttr<plain_attribute> Dest>
requires (!is_size_one_sequence_v<Source>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
static_assert(std::is_assignable_v<Dest&, Source&&>);
dest = std::forward<Source>(src);
}
template <NonUnusedAttr Source, CategorizedAttr<tuple_attribute> Dest>
requires
is_same_size_sequence_v<Dest, Source> &&
(!is_size_one_sequence_v<Dest>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(
std::is_rvalue_reference_v<Source&&> ?
noexcept(fusion::move(std::move(src), dest)) :
noexcept(fusion::copy(src, dest))
)
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
if constexpr (std::is_rvalue_reference_v<Source&&>)
{
fusion::move(std::move(src), dest);
}
else
{
fusion::copy(src, dest);
}
}
template <NonUnusedAttr Source, CategorizedAttr<variant_attribute> Dest>
requires is_size_one_sequence_v<Source> && variant_has_substitute_v<Dest, Source>
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
// dest is a variant, src is a single element fusion sequence that the variant
// *can* directly hold.
dest = std::forward<Source>(src);
}
template <NonUnusedAttr Source, CategorizedAttr<variant_attribute> Dest>
requires is_size_one_sequence_v<Source> && (!variant_has_substitute_v<Dest, Source>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(noexcept(dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)))))
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
// dest is a variant, src is a single element fusion sequence that the variant
// cannot directly hold. We'll try to unwrap the single element fusion sequence.
// Make sure that the Dest variant can really hold Source
static_assert(
variant_has_substitute_v<Dest, typename fusion::result_of::front<Source>::type>,
"Error! The destination variant (Dest) cannot hold the source type (Source)"
);
dest = std::forward_like<Source>(fusion::front(std::forward<Source>(src)));
}
template <NonUnusedAttr Source, CategorizedAttr<variant_attribute> Dest>
requires (!is_size_one_sequence_v<Source>)
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
dest = std::forward<Source>(src);
}
template <NonUnusedAttr Source, CategorizedAttr<optional_attribute> Dest>
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(std::is_nothrow_assignable_v<Dest&, Source&&>)
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
dest = std::forward<Source>(src);
}
// Containers -------------------------------------------------
template <std::forward_iterator It, std::sentinel_for<It> Se, CategorizedAttr<container_attribute> Dest>
constexpr void
move_to(It first, Se last, Dest& dest)
// never noexcept, requires container insertion
{
if (traits::is_empty(dest))
{
dest = Dest(first, last);
}
else
{
traits::append(dest, first, last);
}
}
#ifndef BOOST_SPIRIT_X3_NO_BOOST_ITERATOR_RANGE
template <std::forward_iterator It>
constexpr void
move_to(It first, It last, boost::iterator_range<It>& rng)
{
rng = {first, last};
}
#endif
template <std::forward_iterator It, std::sentinel_for<It> Se, std::ranges::subrange_kind Kind>
constexpr void
move_to(It first, Se last, std::ranges::subrange<It, Se, Kind>& rng)
{
rng = std::ranges::subrange<It, Se, Kind>(std::move(first), std::move(last));
}
template <std::forward_iterator It, std::sentinel_for<It> Se, CategorizedAttr<tuple_attribute> Dest>
requires is_size_one_sequence_v<Dest>
constexpr void
move_to(It first, Se last, Dest& dest)
noexcept(noexcept(traits::move_to(first, last, fusion::front(dest))))
{
traits::move_to(first, last, fusion::front(dest));
}
template <ContainerAttr Source, CategorizedAttr<container_attribute> Dest>
constexpr void
move_to(Source&& src, Dest& dest)
// TODO: noexcept
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
if constexpr (std::is_rvalue_reference_v<Source&&>)
{
traits::move_to(std::make_move_iterator(std::ranges::begin(src)), std::make_move_iterator(std::ranges::end(src)), dest);
}
else
{
traits::move_to(std::ranges::begin(src), std::ranges::end(src), dest);
}
}
// Size-one fusion tuple forwarding
template <NonUnusedAttr Source, CategorizedAttr<tuple_attribute> Dest>
requires is_size_one_sequence_v<Dest>
constexpr void
move_to(Source&& src, Dest& dest)
noexcept(noexcept(traits::move_to(std::forward<Source>(src), fusion::front(dest))))
{
static_assert(!std::same_as<std::remove_cvref_t<Source>, Dest>, "[BUG] This call should instead resolve to the overload handling identical types");
traits::move_to(std::forward<Source>(src), fusion::front(dest));
}
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -10,87 +10,65 @@
#define BOOST_SPIRIT_X3_OPTIONAL_TRAITS_FEBRUARY_06_2007_1001AM
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/optional/optional.hpp>
#include <boost/mpl/identity.hpp>
#ifndef BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
# define BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL 1
#endif
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
# include <boost/optional/optional.hpp>
#endif
#include <optional>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
template <typename T, typename Enable = void>
struct is_optional : std::false_type {};
struct is_optional
: mpl::false_
{};
template <typename T>
constexpr bool is_optional_v = is_optional<T>::value;
struct is_optional<boost::optional<T>>
: mpl::true_
{};
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
template <typename T>
struct [[deprecated("Use std::optional")]] is_optional<boost::optional<T>> : std::true_type {};
#endif
template <typename T>
struct is_optional<std::optional<T>> : std::true_type {};
// Build a optional type from T. Return unused_type if T is unused_type.
///////////////////////////////////////////////////////////////////////////
// build_optional
//
// Build a boost::optional from T. Return unused_type if T is unused_type.
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct build_optional
{
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
using type [[deprecated("Use std::optional")]] = boost::optional<T>;
#else
using type = std::optional<T>;
#endif
typedef boost::optional<T> type;
};
template <typename T>
using build_optional_t = typename build_optional<T>::type;
#if BOOST_SPIRIT_X3_USE_BOOST_OPTIONAL
template <typename T>
struct [[deprecated("Use std::optional")]] build_optional<boost::optional<T>>
struct build_optional<boost::optional<T> >
{
using type = boost::optional<T>;
};
#endif
template <typename T>
struct build_optional<std::optional<T>>
{
using type = std::optional<T>;
typedef boost::optional<T> type;
};
template <>
struct build_optional<unused_type>
{
using type = unused_type;
typedef unused_type type;
};
///////////////////////////////////////////////////////////////////////////
// optional_value
//
// Get the optional's value_type. Handles unused_type as well.
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct optional_value { using type = typename T::value_type; };
struct optional_value : mpl::identity<T> {};
template <typename T>
using optional_value_t = typename optional_value<T>::type;
struct optional_value<boost::optional<T> >
: mpl::identity<T> {};
template <>
struct optional_value<unused_type>
{
using type = unused_type;
};
: mpl::identity<unused_type> {};
template <>
struct optional_value<unused_type const>
{
using type = unused_type;
};
: mpl::identity<unused_type> {};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,16 +9,16 @@
#define BOOST_SPIRIT_X3_PRINT_ATTRIBUTE_JANUARY_20_2013_0814AM
#include <boost/variant.hpp>
#include <boost/optional/optional.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
#include <boost/spirit/home/x3/support/traits/is_variant.hpp>
#ifdef BOOST_SPIRIT_X3_UNICODE
# include <boost/spirit/home/x3/char_encoding/unicode.hpp>
# include <boost/spirit/home/support/char_encoding/unicode.hpp>
#endif
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename Out, typename T>
void print_attribute(Out& out, T const& val);
@@ -166,6 +165,6 @@ namespace boost::spirit::x3::traits
{
print_attribute_debug<Out, T>::call(out, val);
}
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2019 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,29 +7,28 @@
#if !defined(BOOST_SPIRIT_X3_PSEUDO_ATTRIBUTE_OF_MAY_15_2019_1012PM)
#define BOOST_SPIRIT_X3_PSEUDO_ATTRIBUTE_OF_MAY_15_2019_1012PM
#include <iterator>
#include <utility>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// Pseudo attributes are placeholders for parsers that can only know
// its actual attribute at parse time. This trait customization point
// provides a mechanism to convert the trait to the actual trait at
// parse time.
template <typename Context, typename Attribute, std::forward_iterator It, std::sentinel_for<It> Se = It, typename Enable = void>
///////////////////////////////////////////////////////////////////////////
template <typename Context, typename Attribute, typename Iterator
, typename Enable = void>
struct pseudo_attribute
{
using attribute_type = Attribute;
using type = Attribute;
[[nodiscard]] static constexpr type&& call(It&, Se const&, Attribute&& attribute) noexcept
static type&& call(Iterator&, Iterator const&, attribute_type&& attribute)
{
return static_cast<type&&>(attribute);
return std::forward<type>(attribute);
}
};
template <typename Context, typename Attribute, std::forward_iterator It, std::sentinel_for<It> Se>
using pseudo_attribute_t = typename pseudo_attribute<Context, Attribute, It, Se>::type;
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,8 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2010 Bryce Lelbach
Copyright (c) 2025 Nana Sakisaka
Copyright (c) 2010 Bryce Lelbach
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)
@@ -10,113 +9,146 @@
#if !defined(BOOST_SPIRIT_X3_STRING_TRAITS_OCTOBER_2008_1252PM)
#define BOOST_SPIRIT_X3_STRING_TRAITS_OCTOBER_2008_1252PM
#if defined(BOOST_SPIRIT_UNICODE) && !defined(BOOST_SPIRIT_X3_UNICODE)
# error "`BOOST_SPIRIT_UNICODE` has no effect on X3. #define `BOOST_SPIRIT_X3_UNICODE`"
#endif
#if defined(BOOST_SPIRIT_X3_NO_STANDARD_WIDE) && !defined(BOOST_SPIRIT_X3_NO_STANDARD_WIDE)
# error "`BOOST_SPIRIT_X3_NO_STANDARD_WIDE` has no effect on X3. #define `BOOST_SPIRIT_X3_NO_STANDARD_WIDE`"
#endif
#include <string>
#include <string_view>
#include <type_traits>
#include <concepts>
#include <boost/mpl/bool.hpp>
namespace boost::spirit::x3::char_encoding
namespace boost { namespace spirit { namespace x3 { namespace traits
{
struct standard;
///////////////////////////////////////////////////////////////////////////
// Get the C string from a string
///////////////////////////////////////////////////////////////////////////
template <typename String>
struct extract_c_string;
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
struct standard_wide;
#endif
template <typename String>
struct extract_c_string
{
template <typename T>
static T const* call (T* str)
{
return (T const*)str;
}
#ifdef BOOST_SPIRIT_X3_UNICODE
struct unicode;
#endif
} // boost::spirit::x3::char_encoding
template <typename T>
static T const* call (T const* str)
{
return str;
}
};
namespace boost::spirit::x3::traits
{
// Forwarder that strips const
template <typename T>
concept CharLike =
std::same_as<std::remove_cvref_t<T>, char> ||
std::same_as<std::remove_cvref_t<T>, wchar_t> ||
std::same_as<std::remove_cvref_t<T>, char8_t> ||
std::same_as<std::remove_cvref_t<T>, char16_t> ||
std::same_as<std::remove_cvref_t<T>, char32_t>;
struct extract_c_string<T const>
{
static decltype(auto) call(T const str)
{
return extract_c_string<T>::call(str);
}
};
// Spirit has historically converted "c" to 'c'.
//
// While we think it's still useful to retain the conversion,
// we need to avoid further conversion to `std::basic_string_view`,
// which leads to performance overhead. This trait enables
// detection of such arrays.
//
// Note that the status quo introduces ambiguity in determining
// {'c', '\0'} and {'c', 'd'}, but we're not aware of any practical
// usage of non-null-terminated character array in the context of
// DSL on parser combinator.
//
// However, if compelling use cases emerge, we may revise these
// semantics. Versioned as `X3` for forward compatibility.
template <typename T, typename CharT>
concept X3VagueArrayOf2Chars =
std::same_as<std::remove_all_extents_t<std::remove_cvref_t<T>>, CharT> &&
std::is_bounded_array_v<std::remove_cvref_t<T>> &&
std::extent_v<std::remove_cvref_t<T>> == 2;
// Forwarder that strips references
template <typename T>
struct extract_c_string<T&>
{
static decltype(auto) call(T& str)
{
return extract_c_string<T>::call(str);
}
};
// Main utility to guide `char_`, `lit` and `string` to be
// resolved into either `x3::literal_char` or `x3::literal_string`.
//
// This may also be used in other codes which require the same
// semantics.
template <typename T, typename CharT>
concept CppStringLike =
// This avoids converting `CharT[2]` to `std::basic_string_view`.
(!X3VagueArrayOf2Chars<T, CharT>) &&
// All other types that are *naturally* convertible to `std::basic_string_view`.
std::convertible_to<std::decay_t<T>, std::basic_string_view<CharT>>;
// Forwarder that strips const references
template <typename T>
struct extract_c_string<T const&>
{
static decltype(auto) call(T const& str)
{
return extract_c_string<T>::call(str);
}
};
// Mixing incompatible character types is semantically wrong.
// Don't do that. It may even lead to security vulnerabilities.
template <typename T, typename ExpectedCharT>
concept CharIncompatibleWith =
CharLike<T> &&
!std::same_as<std::remove_cvref_t<T>, ExpectedCharT>;
template <typename T, typename Traits, typename Allocator>
struct extract_c_string<std::basic_string<T, Traits, Allocator> >
{
typedef std::basic_string<T, Traits, Allocator> string;
// Mixing incompatible character types is semantically wrong.
// Don't do that. It may even lead to security vulnerabilities.
template <typename T, typename ExpectedCharT>
concept StringLikeIncompatibleWith =
CharLike<std::remove_const_t<std::remove_pointer_t<std::decay_t<T>>>> &&
!std::convertible_to<T, std::basic_string_view<ExpectedCharT>>;
static T const* call (string const& str)
{
return str.c_str();
}
};
namespace detail {
template <CharLike CharT> struct char_encoding_for_impl;
template <> struct char_encoding_for_impl<char> { using type = char_encoding::standard; };
template <typename T>
decltype(auto) get_c_string(T* str)
{
return extract_c_string<T*>::call(str);
}
#ifndef BOOST_SPIRIT_X3_NO_STANDARD_WIDE
template <> struct char_encoding_for_impl<wchar_t> { using type = char_encoding::standard_wide; };
#endif
template <typename T>
decltype(auto) get_c_string(T const* str)
{
return extract_c_string<T const*>::call(str);
}
#ifdef BOOST_SPIRIT_X3_UNICODE
template <> struct char_encoding_for_impl<char8_t> { using type = char_encoding::unicode; };
template <> struct char_encoding_for_impl<char16_t> { using type = char_encoding::unicode; };
template <> struct char_encoding_for_impl<char32_t> { using type = char_encoding::unicode; };
#endif
} // detail
template <typename String>
decltype(auto) get_c_string(String& str)
{
return extract_c_string<String>::call(str);
}
template <class T>
using maybe_owning_string = std::conditional_t<
std::is_pointer_v<std::decay_t<T>>,
std::basic_string_view<std::remove_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
std::remove_cvref_t<T>
>;
template <typename String>
decltype(auto) get_c_string(String const& str)
{
return extract_c_string<String>::call(str);
}
template <CharLike CharT>
using char_encoding_for = typename detail::char_encoding_for_impl<CharT>::type;
///////////////////////////////////////////////////////////////////////////
// Get the begin/end iterators from a string
///////////////////////////////////////////////////////////////////////////
} // boost::spirit::x3::traits
// Implementation for C-style strings.
template <typename T>
inline T const* get_string_begin(T const* str) { return str; }
template <typename T>
inline T* get_string_begin(T* str) { return str; }
template <typename T>
inline T const* get_string_end(T const* str)
{
T const* last = str;
while (*last)
last++;
return last;
}
template <typename T>
inline T* get_string_end(T* str)
{
T* last = str;
while (*last)
last++;
return last;
}
// Implementation for containers (includes basic_string).
template <typename T, typename Str>
inline typename Str::const_iterator get_string_begin(Str const& str)
{ return str.begin(); }
template <typename T, typename Str>
inline typename Str::iterator
get_string_begin(Str& str)
{ return str.begin(); }
template <typename T, typename Str>
inline typename Str::const_iterator get_string_end(Str const& str)
{ return str.end(); }
template <typename T, typename Str>
inline typename Str::iterator
get_string_end(Str& str)
{ return str.end(); }
}}}}
#endif

View File

@@ -1,7 +1,7 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2001-2012 Hartmut Kaiser
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -9,7 +9,9 @@
#if !defined(BOOST_SPIRIT_X3_ATTRIBUTE_TRANSFORM_JAN_8_2012_0721PM)
#define BOOST_SPIRIT_X3_ATTRIBUTE_TRANSFORM_JAN_8_2012_0721PM
namespace boost::spirit::x3::traits
#include <boost/mpl/identity.hpp>
namespace boost { namespace spirit { namespace x3 { namespace traits
{
///////////////////////////////////////////////////////////////////////////
// transform_attribute
@@ -22,12 +24,6 @@ namespace boost::spirit::x3::traits
template <typename Exposed, typename Transformed, typename Tag
, typename Enable = void>
struct transform_attribute;
template <typename Exposed, typename Transformed, typename Tag>
concept Transformable = requires {
typename transform_attribute<Exposed, Transformed, Tag>::type;
};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -11,69 +10,48 @@
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/include/is_view.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/and.hpp>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
// Note that these metafunctions MUST be explicitly derived from `std::bool_constant`,
// because they are used for tag dispatch in some locations.
// Beware that `std::conjunction` / `std::disjunction` is not guaranteed to derive
// from `std::bool_constant`.
template <typename A, typename B>
struct has_same_size
: std::bool_constant<
fusion::result_of::size<std::remove_cvref_t<A>>::value ==
fusion::result_of::size<std::remove_cvref_t<B>>::value
>
: mpl::bool_<(
fusion::result_of::size<A>::value ==
fusion::result_of::size<B>::value
)>
{};
template <typename A, typename B>
constexpr bool has_same_size_v = has_same_size<A, B>::value;
template <typename T, std::size_t N>
struct has_size
: std::bool_constant<fusion::result_of::size<std::remove_cvref_t<T>>::value == N>
: mpl::bool_<(fusion::result_of::size<T>::value == N)>
{};
template <typename T, std::size_t N>
constexpr bool has_size_v = has_size<T, N>::value;
template <typename A, typename B>
struct is_same_size_sequence
: std::bool_constant<std::conjunction_v<
fusion::traits::is_sequence<std::remove_cvref_t<A>>,
fusion::traits::is_sequence<std::remove_cvref_t<B>>,
has_same_size<A, B>
>>
: mpl::and_<
fusion::traits::is_sequence<A>
, fusion::traits::is_sequence<B>
, has_same_size<A, B>
>
{};
template <typename A, typename B>
constexpr bool is_same_size_sequence_v = is_same_size_sequence<A, B>::value;
template <typename Seq>
struct is_size_one_sequence
: std::bool_constant<std::conjunction_v<
fusion::traits::is_sequence<std::remove_cvref_t<Seq>>,
has_size<Seq, 1>
>>
: mpl::and_<
fusion::traits::is_sequence<Seq>
, has_size<Seq, 1>
>
{};
template <typename Seq>
constexpr bool is_size_one_sequence_v = is_size_one_sequence<Seq>::value;
template <typename View>
struct is_size_one_view
: std::bool_constant<std::conjunction_v<
fusion::traits::is_view<std::remove_cvref_t<View>>,
has_size<View, 1>
>>
: mpl::and_<
fusion::traits::is_view<View>
, has_size<View, 1>
>
{};
template <typename View>
constexpr bool is_size_one_view_v = is_size_one_view<View>::value;
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -9,9 +9,9 @@
#define BOOST_SPIRIT_X3_VARIANT_FIND_SUBSTITUTE_APR_18_2014_930AM
#include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
#include <boost/mpl/find.hpp> // TODO: remove this
#include <boost/mpl/find.hpp>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
template <typename Variant, typename T>
struct variant_find_substitute
@@ -19,34 +19,33 @@ namespace boost::spirit::x3::traits
// Get the type from the Variant that can be a substitute for T.
// If none is found, just return T
using variant_type = Variant;
using types = typename variant_type::types;
using end = typename mpl::end<types>::type;
typedef Variant variant_type;
typedef typename variant_type::types types;
typedef typename mpl::end<types>::type end;
using iter_1 = typename mpl::find<types, T>::type;
typedef typename mpl::find<types, T>::type iter_1;
using iter = typename mpl::eval_if<
std::is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<T, mpl::_1> >,
std::type_identity<iter_1>
>::type;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<T, mpl::_1> >,
mpl::identity<iter_1>
>::type
iter;
using type = typename mpl::eval_if<
std::is_same<iter, end>,
std::type_identity<T>,
mpl::deref<iter>
>::type;
typedef typename
mpl::eval_if<
is_same<iter, end>,
mpl::identity<T>,
mpl::deref<iter>
>::type
type;
};
template <typename Variant, typename T>
using variant_find_substitute_t = typename variant_find_substitute<Variant, T>::type;
template <typename Variant>
struct variant_find_substitute<Variant, Variant>
{
using type = Variant;
};
: mpl::identity<Variant> {};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,6 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
http://spirit.sourceforge.net/
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)
@@ -9,49 +9,43 @@
#define BOOST_SPIRIT_X3_VARIANT_HAS_SUBSTITUTE_APR_18_2014_925AM
#include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
#include <boost/mpl/find.hpp> // TODO: remove this
#include <boost/mpl/find.hpp>
#include <type_traits>
namespace boost::spirit::x3::traits
namespace boost { namespace spirit { namespace x3 { namespace traits
{
namespace detail
template <typename Variant, typename T>
struct variant_has_substitute_impl
{
template <typename Variant, typename T>
struct variant_has_substitute_impl
{
// Find a type from the Variant that can be a substitute for T.
// return true_ if one is found, else false_
// Find a type from the Variant that can be a substitute for T.
// return true_ if one is found, else false_
using variant_type = Variant;
using types = typename variant_type::types;
using end = typename mpl::end<types>::type;
using iter_1 = typename mpl::find<types, T>::type;
typedef Variant variant_type;
typedef typename variant_type::types types;
typedef typename mpl::end<types>::type end;
using iter = typename mpl::eval_if<
std::is_same<iter_1, end>,
typedef typename mpl::find<types, T>::type iter_1;
typedef typename
mpl::eval_if<
is_same<iter_1, end>,
mpl::find_if<types, traits::is_substitute<T, mpl::_1>>,
std::type_identity<iter_1>
>::type;
mpl::identity<iter_1>
>::type
iter;
using type = std::bool_constant<!std::is_same_v<iter, end>>;
};
} // detail
typedef mpl::not_<is_same<iter, end>> type;
};
template <typename Variant, typename T>
struct variant_has_substitute
: detail::variant_has_substitute_impl<Variant, T>::type
{};
template <typename Variant, typename T>
constexpr bool variant_has_substitute_v = variant_has_substitute<Variant, T>::value;
: variant_has_substitute_impl<Variant, T>::type {};
template <typename T>
struct variant_has_substitute<unused_type, T> : std::true_type {};
struct variant_has_substitute<unused_type, T> : mpl::true_ {};
template <typename T>
struct variant_has_substitute<unused_type const, T> : std::true_type {};
struct variant_has_substitute<unused_type const, T> : mpl::true_ {};
} // boost::spirit::x3::traits
}}}}
#endif

View File

@@ -1,6 +1,5 @@
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Copyright (c) 2025 Nana Sakisaka
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)
@@ -8,18 +7,15 @@
#if !defined(BOOST_SPIRIT_X3__ANNOTATE_ON_SUCCESS_HPP)
#define BOOST_SPIRIT_X3__ANNOTATE_ON_SUCCESS_HPP
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/spirit/home/x3/support/context.hpp>
#include <boost/spirit/home/x3/support/utility/error_reporting.hpp>
#include <boost/spirit/home/x3/support/utility/lambda_visitor.hpp>
#include <boost/spirit/home/x3/support/traits/is_variant.hpp>
#include <iterator>
#include <type_traits>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
struct error_handler_tag;
///////////////////////////////////////////////////////////////////////////
// The on_success handler tags the AST with the iterator position
// for error handling.
//
@@ -29,37 +25,13 @@ namespace boost::spirit::x3
// x3/support/ast.
//
// We'll ask the X3's error_handler utility to do these.
///////////////////////////////////////////////////////////////////////////
struct annotate_on_success
{
// Catch-all default overload
template <std::forward_iterator It, std::sentinel_for<It> Se, typename T, typename Context>
constexpr void
on_success(It const& first, Se const& last, T& ast, Context const& context)
{
auto&& error_handler_ref = x3::get<error_handler_tag>(context);
static_assert(
!std::is_same_v<std::remove_cvref_t<decltype(error_handler_ref)>, unused_type>,
"This rule is derived from `x3::annotate_on_success`, but no reference was bound to "
"`x3::error_handler_tag`. You must provide a viable error handler via `x3::with`."
);
// unwrap `reference_wrapper` if neccessary
if constexpr (requires {
error_handler_ref.get().tag(ast, first, last);
})
{
error_handler_ref.get().tag(ast, first, last);
}
else
{
error_handler_ref.tag(ast, first, last);
}
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename... Types, typename Context>
constexpr void
on_success(It const& first, Se const& last, x3::variant<Types...>& ast, Context const& context)
template <typename Iterator, typename Context, typename... Types>
inline void on_success(Iterator const& first, Iterator const& last
, variant<Types...>& ast, Context const& context)
{
ast.apply_visitor(x3::make_lambda_visitor<void>([&](auto& node)
{
@@ -67,13 +39,21 @@ namespace boost::spirit::x3
}));
}
template <std::forward_iterator It, std::sentinel_for<It> Se, typename T, typename Context>
constexpr void
on_success(It const& first, Se const& last, forward_ast<T>& ast, Context const& context)
template <typename T, typename Iterator, typename Context>
inline void on_success(Iterator const& first, Iterator const& last
, forward_ast<T>& ast, Context const& context)
{
this->on_success(first, last, ast.get(), context);
}
template <typename T, typename Iterator, typename Context>
inline typename disable_if<traits::is_variant<T>>::type on_success(Iterator const& first, Iterator const& last
, T& ast, Context const& context)
{
auto& error_handler = x3::get<error_handler_tag>(context).get();
error_handler.tag(ast, first, last);
}
};
} // boost::spirit::x3
}}}
#endif

View File

@@ -1,7 +1,6 @@
/*=============================================================================
Copyright (c) 2001-2014 Joel de Guzman
Copyright (c) 2023 Nikita Kniazev
Copyright (c) 2025 Nana Sakisaka
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)
@@ -10,165 +9,121 @@
#define BOOST_SPIRIT_X3_UC_TYPES_NOVEMBER_23_2008_0840PM
#include <boost/config.hpp>
#include <ranges>
#include <type_traits>
#include <string>
#include <string_view>
#include <cassert>
namespace boost::spirit::x3
namespace boost { namespace spirit { namespace x3
{
using ucs4_char = char32_t;
using utf8_char = char;
using ucs4_string = std::basic_string<ucs4_char>;
using utf8_string = std::basic_string<utf8_char>;
typedef char32_t ucs4_char;
typedef char utf8_char;
typedef std::basic_string<ucs4_char> ucs4_string;
typedef std::basic_string<utf8_char> utf8_string;
namespace detail {
constexpr void utf8_put_encode(utf8_string& out, ucs4_char x) noexcept
{
// https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf D90
if (x > 0x10FFFFul || (0xD7FFul < x && x < 0xE000ul)) [[unlikely]]
x = 0xFFFDul;
namespace detail {
inline void utf8_put_encode(utf8_string& out, ucs4_char x)
{
// https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf D90
if (BOOST_UNLIKELY(x > 0x10FFFFul || (0xD7FFul < x && x < 0xE000ul)))
x = 0xFFFDul;
// Table 3-6. UTF-8 Bit Distribution
if (x < 0x80ul) {
out.push_back(static_cast<unsigned char>(x));
}
else if (x < 0x800ul) {
out.push_back(static_cast<unsigned char>(0xC0ul + (x >> 6)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else if (x < 0x10000ul) {
out.push_back(static_cast<unsigned char>(0xE0ul + (x >> 12)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else {
out.push_back(static_cast<unsigned char>(0xF0ul + (x >> 18)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 12) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
// Table 3-6. UTF-8 Bit Distribution
if (x < 0x80ul) {
out.push_back(static_cast<unsigned char>(x));
}
else if (x < 0x800ul) {
out.push_back(static_cast<unsigned char>(0xC0ul + (x >> 6)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else if (x < 0x10000ul) {
out.push_back(static_cast<unsigned char>(0xE0ul + (x >> 12)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
else {
out.push_back(static_cast<unsigned char>(0xF0ul + (x >> 18)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 12) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + ((x >> 6) & 0x3Ful)));
out.push_back(static_cast<unsigned char>(0x80ul + (x & 0x3Ful)));
}
}
}
template <typename Char>
[[nodiscard]] constexpr utf8_string to_utf8(Char value)
inline utf8_string to_utf8(Char value)
{
utf8_string result;
using UChar = std::make_unsigned_t<Char>;
typedef typename std::make_unsigned<Char>::type UChar;
detail::utf8_put_encode(result, static_cast<UChar>(value));
return result;
}
template <typename Char>
[[nodiscard]] constexpr utf8_string to_utf8(Char const* str)
inline utf8_string to_utf8(Char const* str)
{
utf8_string result;
using UChar = typename std::make_unsigned<Char>::type;
typedef typename std::make_unsigned<Char>::type UChar;
while (*str)
{
detail::utf8_put_encode(result, static_cast<UChar>(*str++));
}
return result;
}
template <typename Char, typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string_view<Char, Traits> const str)
template <typename Char, typename Traits, typename Allocator>
inline utf8_string
to_utf8(std::basic_string<Char, Traits, Allocator> const& str)
{
utf8_string result;
using UChar = typename std::make_unsigned<Char>::type;
typedef typename std::make_unsigned<Char>::type UChar;
for (Char ch : str)
{
detail::utf8_put_encode(result, static_cast<UChar>(ch));
}
return result;
}
template <typename Char, typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string<Char, Traits> const& str)
{
utf8_string result;
using UChar = typename std::make_unsigned<Char>::type;
for (Char ch : str)
{
detail::utf8_put_encode(result, static_cast<UChar>(ch));
}
return result;
}
// Assume wchar_t content is UTF-16 on MSVC, or mingw/wineg++ with -fshort-wchar
#if defined(_MSC_VER) || defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2
[[nodiscard]] constexpr utf8_string to_utf8(wchar_t value)
inline utf8_string to_utf8(wchar_t value)
{
utf8_string result;
detail::utf8_put_encode(result, static_cast<std::make_unsigned_t<wchar_t>>(value));
detail::utf8_put_encode(result, static_cast<std::make_unsigned<wchar_t>::type>(value));
return result;
}
namespace detail {
template <std::forward_iterator It>
requires std::is_same_v<std::remove_const_t<std::iter_value_t<It>>, wchar_t>
[[nodiscard]] constexpr ucs4_char decode_utf16(It& s) noexcept
inline ucs4_char decode_utf16(wchar_t const*& s)
{
using uwchar_t = std::make_unsigned<wchar_t>::type;
typedef std::make_unsigned<wchar_t>::type uwchar_t;
uwchar_t x(*s);
if (x < 0xD800ul || x > 0xDFFFul)
{
return x;
}
// expected high-surrogate
if ((x >> 10) != 0b110110ul) [[unlikely]]
{
if (BOOST_UNLIKELY((x >> 10) != 0b110110ul))
return 0xFFFDul;
}
uwchar_t y(*++s);
// expected low-surrogate
if ((y >> 10) != 0b110111ul) [[unlikely]]
{
if (BOOST_UNLIKELY((y >> 10) != 0b110111ul))
return 0xFFFDul;
}
return ((x & 0x3FFul) << 10) + (y & 0x3FFul) + 0x10000ul;
}
}
template <typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string_view<wchar_t, Traits> const str)
inline utf8_string to_utf8(wchar_t const* str)
{
utf8_string result;
for (auto it = str.begin(); it != str.end(); ++it)
{
detail::utf8_put_encode(result, detail::decode_utf16(it));
}
for (ucs4_char c; (c = detail::decode_utf16(str)) != ucs4_char(); ++str)
detail::utf8_put_encode(result, c);
return result;
}
[[nodiscard]] constexpr utf8_string to_utf8(wchar_t const* str)
template <typename Traits, typename Allocator>
inline utf8_string
to_utf8(std::basic_string<wchar_t, Traits, Allocator> const& str)
{
return x3::to_utf8(std::basic_string_view(str));
}
template <typename Traits>
[[nodiscard]] constexpr utf8_string
to_utf8(std::basic_string<wchar_t, Traits> const& str)
{
utf8_string result;
for (auto it = str.begin(); it != str.end(); ++it)
{
detail::utf8_put_encode(result, detail::decode_utf16(it));
}
return result;
return to_utf8(str.c_str());
}
#endif
} // boost::spirit::x3
}}}
#endif

Some files were not shown because too many files have changed in this diff Show More