Thanks for using Compiler Explorer
Sponsors
C with Coccinelle
C++ with Coccinelle
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Numba
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 12.4.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 13.3.0
ARM GCC 13.3.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 14.1.0 (unknown-eabi)
ARM GCC 14.2.0
ARM GCC 14.2.0 (unknown-eabi)
ARM GCC 15.1.0
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (WINE)
ARM msvc v19.10 (WINE)
ARM msvc v19.14 (WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 12.4.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 13.3.0
ARM64 gcc 14.1.0
ARM64 gcc 14.2.0
ARM64 gcc 15.1.0
ARM64 gcc 4.9.4
ARM64 gcc 5.4
ARM64 gcc 5.5.0
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 12.4.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 13.3.0
AVR gcc 14.1.0
AVR gcc 14.2.0
AVR gcc 15.1.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF clang 19.1.0
BPF clang 20.1.0
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
EDG 6.7
EDG 6.7 (GNU mode gcc 14)
FRC 2019
FRC 2020
FRC 2023
HPPA gcc 14.2.0
HPPA gcc 15.1.0
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
KVX ACB 5.0.0 (GCC 12.2.1)
KVX ACB 5.2.0 (GCC 13.2.1)
LoongArch64 clang (trunk)
LoongArch64 clang 17.0.1
LoongArch64 clang 18.1.0
LoongArch64 clang 19.1.0
LoongArch64 clang 20.1.0
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 13.3.0
M68K gcc 14.1.0
M68K gcc 14.2.0
M68K gcc 15.1.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 12.4.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 13.3.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 14.2.0
RISC-V (32-bits) gcc 15.1.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 12.4.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 13.3.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 14.2.0
RISC-V (64-bits) gcc 15.1.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 19.1.0
RISC-V rv32gc clang 20.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 19.1.0
RISC-V rv64gc clang 20.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 12.4.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC LEON gcc 13.3.0
SPARC LEON gcc 14.1.0
SPARC LEON gcc 14.2.0
SPARC LEON gcc 15.1.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 12.4.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 13.3.0
SPARC gcc 14.1.0
SPARC gcc 14.2.0
SPARC gcc 15.1.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 12.4.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 13.3.0
SPARC64 gcc 14.1.0
SPARC64 gcc 14.2.0
SPARC64 gcc 15.1.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 12.4.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 13.3.0
TI C6x gcc 14.1.0
TI C6x gcc 14.2.0
TI C6x gcc 15.1.0
TI CL430 21.6.1
Tricore gcc 11.3.0 (EEESlab)
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 14.2.0 (20241119)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 14.2.0 (20241119)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 14.2.0 (20241119)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.20 VS16.0
arm64 msvc v19.21 VS16.1
arm64 msvc v19.22 VS16.2
arm64 msvc v19.23 VS16.3
arm64 msvc v19.24 VS16.4
arm64 msvc v19.25 VS16.5
arm64 msvc v19.27 VS16.7
arm64 msvc v19.28 VS16.8
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30 VS17.0
arm64 msvc v19.31 VS17.1
arm64 msvc v19.32 VS17.2
arm64 msvc v19.33 VS17.3
arm64 msvc v19.34 VS17.4
arm64 msvc v19.35 VS17.5
arm64 msvc v19.36 VS17.6
arm64 msvc v19.37 VS17.7
arm64 msvc v19.38 VS17.8
arm64 msvc v19.39 VS17.9
arm64 msvc v19.40 VS17.10
arm64 msvc v19.41 VS17.11
arm64 msvc v19.42 VS17.12
arm64 msvc v19.43 VS17.13
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 19.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 19.1.0
armv8-a clang 20.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
clad trunk (clang 19.1.0)
clad v1.8 (clang 18.1.0)
clad v1.9 (clang 19.1.0)
clang-cl 18.1.0
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
ez80-clang 15.0.0
ez80-clang 15.0.7
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 12.4.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 13.3.0
loongarch64 gcc 14.1.0
loongarch64 gcc 14.2.0
loongarch64 gcc 15.1.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips clang 19.1.0
mips clang 20.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 12.4.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 13.3.0
mips gcc 14.1.0
mips gcc 14.2.0
mips gcc 15.1.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 12.4.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 13.3.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 14.2.0
mips64 (el) gcc 15.1.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 clang 19.1.0
mips64 clang 20.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 12.4.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 13.3.0
mips64 gcc 14.1.0
mips64 gcc 14.2.0
mips64 gcc 15.1.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mips64el clang 19.1.0
mips64el clang 20.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel clang 19.1.0
mipsel clang 20.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 12.4.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 13.3.0
mipsel gcc 14.1.0
mipsel gcc 14.2.0
mipsel gcc 15.1.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 12.4.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 13.3.0
power gcc 14.1.0
power gcc 14.2.0
power gcc 15.1.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 12.4.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc 13.3.0
power64 gcc 14.1.0
power64 gcc 14.2.0
power64 gcc 15.1.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 12.4.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 13.3.0
power64le gcc 14.1.0
power64le gcc 14.2.0
power64le gcc 15.1.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
qnx 8.0.0
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 12.4.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 13.3.0
s390x gcc 14.1.0
s390x gcc 14.2.0
s390x gcc 15.1.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 12.4.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 13.3.0
sh gcc 14.1.0
sh gcc 14.2.0
sh gcc 15.1.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (WINE)
x64 msvc v19.10 (WINE)
x64 msvc v19.14 (WINE)
x64 msvc v19.20 VS16.0
x64 msvc v19.21 VS16.1
x64 msvc v19.22 VS16.2
x64 msvc v19.23 VS16.3
x64 msvc v19.24 VS16.4
x64 msvc v19.25 VS16.5
x64 msvc v19.27 VS16.7
x64 msvc v19.28 VS16.8
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30 VS17.0
x64 msvc v19.31 VS17.1
x64 msvc v19.32 VS17.2
x64 msvc v19.33 VS17.3
x64 msvc v19.34 VS17.4
x64 msvc v19.35 VS17.5
x64 msvc v19.36 VS17.6
x64 msvc v19.37 VS17.7
x64 msvc v19.38 VS17.8
x64 msvc v19.39 VS17.9
x64 msvc v19.40 VS17.10
x64 msvc v19.41 VS17.11
x64 msvc v19.42 VS17.12
x64 msvc v19.43 VS17.13
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (WINE)
x86 msvc v19.10 (WINE)
x86 msvc v19.14 (WINE)
x86 msvc v19.20 VS16.0
x86 msvc v19.21 VS16.1
x86 msvc v19.22 VS16.2
x86 msvc v19.23 VS16.3
x86 msvc v19.24 VS16.4
x86 msvc v19.25 VS16.5
x86 msvc v19.27 VS16.7
x86 msvc v19.28 VS16.8
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30 VS17.0
x86 msvc v19.31 VS17.1
x86 msvc v19.32 VS17.2
x86 msvc v19.33 VS17.3
x86 msvc v19.34 VS17.4
x86 msvc v19.35 VS17.5
x86 msvc v19.36 VS17.6
x86 msvc v19.37 VS17.7
x86 msvc v19.38 VS17.8
x86 msvc v19.39 VS17.9
x86 msvc v19.40 VS17.10
x86 msvc v19.41 VS17.11
x86 msvc v19.42 VS17.12
x86 msvc v19.43 VS17.13
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.11
x86 nvc++ 24.3
x86 nvc++ 24.5
x86 nvc++ 24.7
x86 nvc++ 24.9
x86 nvc++ 25.1
x86 nvc++ 25.3
x86-64 Zapcc 190308
x86-64 clang (-fimplicit-constexpr)
x86-64 clang (Chris Bazley N3089)
x86-64 clang (EricWF contracts)
x86-64 clang (amd-staging)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2996)
x86-64 clang (experimental P2998)
x86-64 clang (experimental P3068)
x86-64 clang (experimental P3309)
x86-64 clang (experimental P3367)
x86-64 clang (experimental P3372)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (old concepts branch)
x86-64 clang (p1974)
x86-64 clang (pattern matching - P2688)
x86-64 clang (reflection)
x86-64 clang (resugar)
x86-64 clang (string interpolation - P3412)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 19.1.0
x86-64 clang 19.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 20.1.0
x86-64 clang 20.1.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 clang rocm-6.0.2
x86-64 clang rocm-6.1.2
x86-64 clang rocm-6.2.4
x86-64 clang rocm-6.3.3
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.3 (assertions)
x86-64 gcc 10.4
x86-64 gcc 10.4 (assertions)
x86-64 gcc 10.5
x86-64 gcc 10.5 (assertions)
x86-64 gcc 11.1
x86-64 gcc 11.1 (assertions)
x86-64 gcc 11.2
x86-64 gcc 11.2 (assertions)
x86-64 gcc 11.3
x86-64 gcc 11.3 (assertions)
x86-64 gcc 11.4
x86-64 gcc 11.4 (assertions)
x86-64 gcc 12.1
x86-64 gcc 12.1 (assertions)
x86-64 gcc 12.2
x86-64 gcc 12.2 (assertions)
x86-64 gcc 12.3
x86-64 gcc 12.3 (assertions)
x86-64 gcc 12.4
x86-64 gcc 12.4 (assertions)
x86-64 gcc 13.1
x86-64 gcc 13.1 (assertions)
x86-64 gcc 13.2
x86-64 gcc 13.2 (assertions)
x86-64 gcc 13.3
x86-64 gcc 13.3 (assertions)
x86-64 gcc 14.1
x86-64 gcc 14.1 (assertions)
x86-64 gcc 14.2
x86-64 gcc 14.2 (assertions)
x86-64 gcc 15.1
x86-64 gcc 15.1 (assertions)
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
x86-64 icx 2024.1.0
x86-64 icx 2024.2.0
x86-64 icx 2024.2.1
x86-64 icx 2025.0.0
x86-64 icx 2025.0.1
x86-64 icx 2025.0.3
x86-64 icx 2025.0.4
x86-64 icx 2025.1.0
x86-64 icx 2025.1.0
z180-clang 15.0.0
z180-clang 15.0.7
z80-clang 15.0.0
z80-clang 15.0.7
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.12.1
zig c++ 0.13.0
zig c++ 0.14.0
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
/* Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. */ #ifndef CTRE_V2__CTRE__HPP #define CTRE_V2__CTRE__HPP #ifndef CTRE_V2__CTRE__LITERALS__HPP #define CTRE_V2__CTRE__LITERALS__HPP #ifndef CTRE_V2__CTLL__HPP #define CTRE_V2__CTLL__HPP #ifndef CTLL__PARSER__HPP #define CTLL__PARSER__HPP #ifndef CTLL__FIXED_STRING__GPP #define CTLL__FIXED_STRING__GPP #include <utility> #include <cstddef> #include <string_view> #include <cstdint> namespace ctll { struct length_value_t { uint32_t value; uint8_t length; }; constexpr length_value_t length_and_value_of_utf8_code_point(uint8_t first_unit) noexcept { if ((first_unit & 0b1000'0000) == 0b0000'0000) return {static_cast<uint32_t>(first_unit), 1}; else if ((first_unit & 0b1110'0000) == 0b1100'0000) return {static_cast<uint32_t>(first_unit & 0b0001'1111), 2}; else if ((first_unit & 0b1111'0000) == 0b1110'0000) return {static_cast<uint32_t>(first_unit & 0b0000'1111), 3}; else if ((first_unit & 0b1111'1000) == 0b1111'0000) return {static_cast<uint32_t>(first_unit & 0b0000'0111), 4}; else if ((first_unit & 0b1111'1100) == 0b1111'1000) return {static_cast<uint32_t>(first_unit & 0b0000'0011), 5}; else if ((first_unit & 0b1111'1100) == 0b1111'1100) return {static_cast<uint32_t>(first_unit & 0b0000'0001), 6}; else return {0, 0}; } constexpr char32_t value_of_trailing_utf8_code_point(uint8_t unit, bool & correct) noexcept { if ((unit & 0b1100'0000) == 0b1000'0000) return unit & 0b0011'1111; else { correct = false; return 0; } } constexpr length_value_t length_and_value_of_utf16_code_point(uint16_t first_unit) noexcept { if ((first_unit & 0b1111110000000000) == 0b1101'1000'0000'0000) return {static_cast<uint32_t>(first_unit & 0b0000001111111111), 2}; else return {first_unit, 1}; } template <size_t N> struct fixed_string { char32_t content[N] = {}; size_t real_size{0}; bool correct_flag{true}; template <typename T> constexpr fixed_string(const T (&input)[N+1]) noexcept { if constexpr (std::is_same_v<T, char>) { #if CTRE_STRING_IS_UTF8 size_t out{0}; for (size_t i{0}; i < N; ++i) { if ((i == (N-1)) && (input[i] == 0)) break; length_value_t info = length_and_value_of_utf8_code_point(input[i]); switch (info.length) { case 6: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 5: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 4: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 3: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 2: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 1: content[out++] = static_cast<char32_t>(info.value); real_size++; break; default: correct_flag = false; return; } } #else for (size_t i{0}; i < N; ++i) { content[i] = static_cast<uint8_t>(input[i]); if ((i == (N-1)) && (input[i] == 0)) break; real_size++; } #endif #if __cpp_char8_t } else if constexpr (std::is_same_v<T, char8_t>) { size_t out{0}; for (size_t i{0}; i < N; ++i) { if ((i == (N-1)) && (input[i] == 0)) break; length_value_t info = length_and_value_of_utf8_code_point(input[i]); switch (info.length) { case 6: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 5: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 4: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 3: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 2: if (++i < N) info.value = (info.value << 6) | value_of_trailing_utf8_code_point(input[i], correct_flag); [[fallthrough]]; case 1: content[out++] = static_cast<char32_t>(info.value); real_size++; break; default: correct_flag = false; return; } } #endif } else if constexpr (std::is_same_v<T, char16_t>) { size_t out{0}; for (size_t i{0}; i < N; ++i) { length_value_t info = length_and_value_of_utf16_code_point(input[i]); if (info.length == 2) { if (++i < N) { if ((input[i] & 0b1111'1100'0000'0000) == 0b1101'1100'0000'0000) { content[out++] = (info.value << 10) | (input[i] & 0b0000'0011'1111'1111); } else { correct_flag = false; break; } } } else { if ((i == (N-1)) && (input[i] == 0)) break; content[out++] = info.value; } } real_size = out; } else if constexpr (std::is_same_v<T, wchar_t> || std::is_same_v<T, char32_t>) { for (size_t i{0}; i < N; ++i) { content[i] = input[i]; if ((i == (N-1)) && (input[i] == 0)) break; real_size++; } } } constexpr fixed_string(const fixed_string & other) noexcept { for (size_t i{0}; i < N; ++i) { content[i] = other.content[i]; } real_size = other.real_size; correct_flag = other.correct_flag; } constexpr bool correct() const noexcept { return correct_flag; } constexpr size_t size() const noexcept { return real_size; } constexpr const char32_t * begin() const noexcept { return content; } constexpr const char32_t * end() const noexcept { return content + size(); } constexpr char32_t operator[](size_t i) const noexcept { return content[i]; } template <size_t M> constexpr bool is_same_as(const fixed_string<M> & rhs) const noexcept { if (real_size != rhs.size()) return false; for (size_t i{0}; i != real_size; ++i) { if (content[i] != rhs[i]) return false; } return true; } constexpr operator std::basic_string_view<char32_t>() const noexcept { return std::basic_string_view<char32_t>{content, size()}; } }; template <> class fixed_string<0> { static constexpr char32_t empty[1] = {0}; public: template <typename T> constexpr fixed_string(const T *) noexcept { } constexpr fixed_string(std::initializer_list<char32_t>) noexcept { } constexpr fixed_string(const fixed_string &) noexcept { } constexpr bool correct() const noexcept { return true; } constexpr size_t size() const noexcept { return 0; } constexpr const char32_t * begin() const noexcept { return empty; } constexpr const char32_t * end() const noexcept { return empty + size(); } constexpr char32_t operator[](size_t) const noexcept { return 0; } constexpr operator std::basic_string_view<char32_t>() const noexcept { return std::basic_string_view<char32_t>{empty, 0}; } }; template <typename CharT, size_t N> fixed_string(const CharT (&)[N]) -> fixed_string<N-1>; template <size_t N> fixed_string(fixed_string<N>) -> fixed_string<N>; } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) #define CTLL_FIXED_STRING ctll::fixed_string #else #define CTLL_FIXED_STRING const auto & #endif #endif #ifndef CTLL__TYPE_STACK__HPP #define CTLL__TYPE_STACK__HPP #ifndef CTLL__UTILITIES__HPP #define CTLL__UTILITIES__HPP #include <type_traits> #ifdef _MSC_VER #define CTLL_FORCE_INLINE __forceinline #else #define CTLL_FORCE_INLINE __attribute__((always_inline)) #endif namespace ctll { template <bool> struct conditional_helper; template <> struct conditional_helper<true> { template <typename A, typename> using type = A; }; template <> struct conditional_helper<false> { template <typename, typename B> using type = B; }; template <bool V, typename A, typename B> using conditional = typename conditional_helper<V>::template type<A,B>; } #endif namespace ctll { template <typename... Ts> struct list { }; struct _nothing { }; using empty_list = list<>; // calculate size of list content template <typename... Ts> constexpr auto size(list<Ts...>) noexcept { return sizeof...(Ts); } // check if the list is empty template <typename... Ts> constexpr bool empty(list<Ts...>) noexcept { return false; } constexpr bool empty(empty_list) { return true; } // concat two lists together left to right template <typename... As, typename... Bs> constexpr auto concat(list<As...>, list<Bs...>) noexcept -> list<As..., Bs...> { return {}; } // push something to the front of a list template <typename T, typename... As> constexpr auto push_front(T, list<As...>) noexcept -> list<T, As...> { return {}; } // pop element from the front of a list template <typename T, typename... As> constexpr auto pop_front(list<T, As...>) noexcept -> list<As...> { return {}; } constexpr auto pop_front(empty_list) -> empty_list; // pop element from the front of a list and return new typelist too template <typename Front, typename List> struct list_pop_pair { Front front{}; List list{}; constexpr list_pop_pair() = default; }; template <typename Head, typename... As, typename T = _nothing> constexpr auto pop_and_get_front(list<Head, As...>, T = T()) noexcept -> list_pop_pair<Head, list<As...>> { return {}; } template <typename T = _nothing> constexpr auto pop_and_get_front(empty_list, T = T()) noexcept -> list_pop_pair<T, empty_list> { return {}; } // return front of the list template <typename Head, typename... As, typename T = _nothing> constexpr auto front(list<Head, As...>, T = T()) noexcept -> Head { return {}; } template <typename T = _nothing> constexpr auto front(empty_list, T = T()) noexcept -> T { return {}; } } #endif #ifndef CTLL__GRAMMARS__HPP #define CTLL__GRAMMARS__HPP namespace ctll { // terminal type representing symbol / character of any type template <auto v> struct term { static constexpr auto value = v; }; // epsilon = nothing on input tape // also used as an command for parsing means "do nothing" struct epsilon { static constexpr auto value = '-'; }; // empty_stack_symbol = nothing on stack struct empty_stack_symbol {}; // push<T...> is alias to list<T...> template <typename... Ts> using push = list<Ts...>; // accept/reject type for controlling output of LL1 machine struct accept { constexpr explicit operator bool() noexcept { return true; } }; struct reject { constexpr explicit operator bool() noexcept { return false; } }; // action type, every action item in grammar must inherit from struct action { struct action_tag { }; }; // move one character forward and pop it from stack command struct pop_input { struct pop_input_tag { }; }; // additional overloads for type list template <typename... Ts> constexpr auto push_front(pop_input, list<Ts...>) -> list<Ts...> { return {}; } template <typename... Ts> constexpr auto push_front(epsilon, list<Ts...>) -> list<Ts...> { return {}; } template <typename... As, typename... Bs> constexpr auto push_front(list<As...>, list<Bs...>) -> list<As..., Bs...> { return {}; } template <typename T, typename... As> constexpr auto pop_front_and_push_front(T item, list<As...> l) { return push_front(item, pop_front(l)); } // SPECIAL matching types for nicer grammars // match any term struct anything { constexpr inline anything() noexcept { } template <auto V> constexpr anything(term<V>) noexcept; }; // match range of term A-B template <auto A, decltype(A) B> struct range { constexpr inline range() noexcept { } //template <auto V> constexpr range(term<V>) noexcept requires (A <= V) && (V <= B); template <auto V, typename = std::enable_if_t<(A <= V) && (V <= B)>> constexpr inline range(term<V>) noexcept; }; #ifdef __EDG__ template <auto V, auto... Set> struct contains { static constexpr bool value = ((Set == V) || ... || false); }; #endif // match terms defined in set template <auto... Def> struct set { constexpr inline set() noexcept { } #ifdef __EDG__ template <auto V, typename = std::enable_if_t<contains<V, Def...>::value>> constexpr inline set(term<V>) noexcept; #else template <auto V, typename = std::enable_if_t<((Def == V) || ... || false)>> constexpr inline set(term<V>) noexcept; #endif }; // match terms not defined in set template <auto... Def> struct neg_set { constexpr inline neg_set() noexcept { } #ifdef __EDG__ template <auto V, typename = std::enable_if_t<!contains<V, Def...>::value>> constexpr inline neg_set(term<V>) noexcept; #else template <auto V, typename = std::enable_if_t<!((Def == V) || ... || false)>> constexpr inline neg_set(term<V>) noexcept; #endif }; // AUGMENTED grammar which completes user-defined grammar for all other cases template <typename Grammar> struct augment_grammar: public Grammar { // start nonterminal is defined in parent type using typename Grammar::_start; // grammar rules are inherited from Grammar parent type using Grammar::rule; // term on stack and on input means pop_input; template <auto A> static constexpr auto rule(term<A>, term<A>) -> ctll::pop_input; // if the type on stack (range, set, neg_set, anything) is constructible from the terminal => pop_input template <typename Expected, auto V> static constexpr auto rule(Expected, term<V>) -> std::enable_if_t<std::is_constructible_v<Expected, term<V>>, ctll::pop_input>; // empty stack and empty input means we are accepting static constexpr auto rule(empty_stack_symbol, epsilon) -> ctll::accept; // not matching anything else => reject static constexpr auto rule(...) -> ctll::reject; // start stack is just a list<Grammar::_start>; using start_stack = list<typename Grammar::_start>; }; } #endif #ifndef CTLL__ACTIONS__HPP #define CTLL__ACTIONS__HPP namespace ctll { struct empty_subject { }; struct empty_actions { // dummy operator so using Actions::operator() later will not give error template <typename Action, typename InputSymbol, typename Subject> static constexpr auto apply(Action, InputSymbol, Subject subject) { return subject; } }; template <typename Actions> struct identity: public Actions { using Actions::apply; // allow empty_subject to exists template <typename Action, auto V> constexpr static auto apply(Action, term<V>, empty_subject) -> empty_subject { return {}; } template <typename Action> constexpr static auto apply(Action, epsilon, empty_subject) -> empty_subject { return {}; } }; template <typename Actions> struct ignore_unknown: public Actions { using Actions::apply; // allow flow thru unknown actions template <typename Action, auto V, typename Subject> constexpr static auto apply(Action, term<V>, Subject) -> Subject { return {}; } template <typename Action, typename Subject> constexpr static auto apply(Action, epsilon, Subject) -> Subject { return {}; } }; } #endif #include <limits> namespace ctll { enum class decision { reject, accept, undecided }; struct placeholder { }; template <size_t> using index_placeholder = placeholder; #if ((__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) || (__cpp_nontype_template_args >= 201911L)) template <typename Grammar, ctll::fixed_string input, typename ActionSelector = empty_actions, bool IgnoreUnknownActions = false> struct parser { // in c++20 #else template <typename Grammar, const auto & input, typename ActionSelector = empty_actions, bool IgnoreUnknownActions = false> struct parser { #endif #ifdef __GNUC__ // workaround to GCC bug #if ((__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) || (__cpp_nontype_template_args >= 201911L)) static constexpr auto _input = input; // c++20 mode #else static constexpr auto & _input = input; // c++17 mode #endif #else static constexpr auto _input = input; // everyone else #endif using Actions = ctll::conditional<IgnoreUnknownActions, ignore_unknown<ActionSelector>, identity<ActionSelector>>; using grammar = augment_grammar<Grammar>; template <size_t Pos, typename Stack, typename Subject, decision Decision> struct results { constexpr inline CTLL_FORCE_INLINE operator bool() const noexcept { return Decision == decision::accept; } #ifdef __GNUC__ // workaround to GCC bug #if ((__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) || (__cpp_nontype_template_args >= 201911L)) static constexpr auto _input = input; // c++20 mode #else static constexpr auto & _input = input; // c++17 mode #endif #else static constexpr auto _input = input; // everyone else #endif using output_type = Subject; constexpr auto operator+(placeholder) const noexcept { if constexpr (Decision == decision::undecided) { // parse for current char (RPos) with previous stack and subject :) return parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template decide<Pos, Stack, Subject>({}, {}); } else { // if there is decision already => just push it to the end of fold expression return *this; } } }; template <size_t Pos> static constexpr auto get_current_term() noexcept { if constexpr (Pos < input.size()) { constexpr auto value = input[Pos]; if constexpr (value <= static_cast<decltype(value)>(std::numeric_limits<char>::max())) { return term<static_cast<char>(value)>{}; } else { return term<value>{}; } } else { // return epsilon if we are past the input return epsilon{}; } } template <size_t Pos> static constexpr auto get_previous_term() noexcept { if constexpr (Pos == 0) { // there is no previous character on input if we are on start return epsilon{}; } else if constexpr ((Pos-1) < input.size()) { constexpr auto value = input[Pos-1]; if constexpr (value <= static_cast<decltype(value)>(std::numeric_limits<char>::max())) { return term<static_cast<char>(value)>{}; } else { return term<value>{}; } } else { return epsilon{}; } } // if rule is accept => return true and subject template <size_t Pos, typename Terminal, typename Stack, typename Subject> static constexpr auto move(ctll::accept, Terminal, Stack, Subject) noexcept { return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos, Stack, Subject, decision::accept>(); } // if rule is reject => return false and subject template <size_t Pos, typename Terminal, typename Stack, typename Subject> static constexpr auto move(ctll::reject, Terminal, Stack, Subject) noexcept { return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos, Stack, Subject, decision::reject>(); } // if rule is pop_input => move to next character template <size_t Pos, typename Terminal, typename Stack, typename Subject> static constexpr auto move(ctll::pop_input, Terminal, Stack, Subject) noexcept { return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos+1, Stack, Subject, decision::undecided>(); } // if rule is string => push it to the front of stack template <size_t Pos, typename... Content, typename Terminal, typename Stack, typename Subject> static constexpr auto move(push<Content...> string, Terminal, Stack stack, Subject subject) noexcept { return decide<Pos>(push_front(string, stack), subject); } // if rule is epsilon (empty string) => continue template <size_t Pos, typename Terminal, typename Stack, typename Subject> static constexpr auto move(epsilon, Terminal, Stack stack, Subject subject) noexcept { return decide<Pos>(stack, subject); } // if rule is string with current character at the beginning (term<V>) => move to next character // and push string without the character (quick LL(1)) template <size_t Pos, auto V, typename... Content, typename Stack, typename Subject> static constexpr auto move(push<term<V>, Content...>, term<V>, Stack stack, Subject) noexcept { constexpr auto _input = input; return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos+1, decltype(push_front(list<Content...>(), stack)), Subject, decision::undecided>(); } // if rule is string with any character at the beginning (compatible with current term<T>) => move to next character // and push string without the character (quick LL(1)) template <size_t Pos, auto V, typename... Content, auto T, typename Stack, typename Subject> static constexpr auto move(push<anything, Content...>, term<T>, Stack stack, Subject) noexcept { constexpr auto _input = input; return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos+1, decltype(push_front(list<Content...>(), stack)), Subject, decision::undecided>(); } // decide if we need to take action or move template <size_t Pos, typename Stack, typename Subject> static constexpr auto decide(Stack previous_stack, Subject previous_subject) noexcept { // each call means we pop something from stack auto top_symbol = decltype(ctll::front(previous_stack, empty_stack_symbol()))(); // gcc pedantic warning [[maybe_unused]] auto stack = decltype(ctll::pop_front(previous_stack))(); // in case top_symbol is action type (apply it on previous subject and get new one) if constexpr (std::is_base_of_v<ctll::action, decltype(top_symbol)>) { auto subject = Actions::apply(top_symbol, get_previous_term<Pos>(), previous_subject); // in case that semantic action is error => reject input if constexpr (std::is_same_v<ctll::reject, decltype(subject)>) { return typename parser<Grammar, _input, ActionSelector, IgnoreUnknownActions>::template results<Pos, Stack, Subject, decision::reject>(); } else { return decide<Pos>(stack, subject); } } else { // all other cases are ordinary for LL(1) parser auto current_term = get_current_term<Pos>(); auto rule = decltype(grammar::rule(top_symbol,current_term))(); return move<Pos>(rule, current_term, stack, previous_subject); } } // trampolines with folded expression template <typename Subject, size_t... Pos> static constexpr auto trampoline_decide(Subject, std::index_sequence<Pos...>) noexcept { // parse everything for first char and than for next and next ... // Pos+1 is needed as we want to finish calculation with epsilons on stack auto v = (decide<0, typename grammar::start_stack, Subject>({}, {}) + ... + index_placeholder<Pos+1>()); return v; } template <typename Subject = empty_subject> static constexpr auto trampoline_decide(Subject subject = {}) noexcept { // there will be no recursion, just sequence long as the input return trampoline_decide(subject, std::make_index_sequence<input.size()>()); } template <typename Subject = empty_subject> using output = decltype(trampoline_decide<Subject>()); template <typename Subject = empty_subject> static inline constexpr bool correct_with = trampoline_decide<Subject>(); }; } // end of ctll namespace #endif #endif #ifndef CTRE__PCRE_ACTIONS__HPP #define CTRE__PCRE_ACTIONS__HPP #ifndef CTRE__PCRE__HPP #define CTRE__PCRE__HPP // THIS FILE WAS GENERATED BY DESATOMAT TOOL, DO NOT MODIFY THIS FILE namespace ctre { struct pcre { // NONTERMINALS: struct a {}; struct b {}; struct backslash {}; struct backslash_range {}; struct block {}; struct block_name2 {}; struct block_name {}; struct c {}; struct class_named_name {}; struct content2 {}; struct content_in_capture {}; struct d {}; struct e {}; struct f {}; struct g {}; struct h {}; struct hexdec_repeat {}; struct i {}; struct j {}; struct k {}; struct l {}; struct m {}; struct mod {}; struct mod_opt {}; struct n {}; struct number2 {}; struct number {}; struct o {}; struct p {}; struct property_name2 {}; struct property_name {}; struct property_value2 {}; struct property_value {}; struct q {}; struct range {}; struct repeat {}; struct s {}; using _start = s; struct set2a {}; struct set2b {}; struct string2 {}; // 'action' types: struct class_digit: ctll::action {}; struct class_horizontal_space: ctll::action {}; struct class_named_alnum: ctll::action {}; struct class_named_alpha: ctll::action {}; struct class_named_ascii: ctll::action {}; struct class_named_blank: ctll::action {}; struct class_named_cntrl: ctll::action {}; struct class_named_digit: ctll::action {}; struct class_named_graph: ctll::action {}; struct class_named_lower: ctll::action {}; struct class_named_print: ctll::action {}; struct class_named_punct: ctll::action {}; struct class_named_space: ctll::action {}; struct class_named_upper: ctll::action {}; struct class_named_word: ctll::action {}; struct class_named_xdigit: ctll::action {}; struct class_non_horizontal_space: ctll::action {}; struct class_non_vertical_space: ctll::action {}; struct class_nondigit: ctll::action {}; struct class_nonnewline: ctll::action {}; struct class_nonspace: ctll::action {}; struct class_nonword: ctll::action {}; struct class_space: ctll::action {}; struct class_vertical_space: ctll::action {}; struct class_word: ctll::action {}; struct create_hexdec: ctll::action {}; struct create_number: ctll::action {}; struct finish_hexdec: ctll::action {}; struct look_finish: ctll::action {}; struct make_alternate: ctll::action {}; struct make_back_reference: ctll::action {}; struct make_capture: ctll::action {}; struct make_capture_with_name: ctll::action {}; struct make_lazy: ctll::action {}; struct make_optional: ctll::action {}; struct make_possessive: ctll::action {}; struct make_property: ctll::action {}; struct make_property_negative: ctll::action {}; struct make_range: ctll::action {}; struct make_relative_back_reference: ctll::action {}; struct make_sequence: ctll::action {}; struct negate_class_named: ctll::action {}; struct prepare_capture: ctll::action {}; struct push_assert_begin: ctll::action {}; struct push_assert_end: ctll::action {}; struct push_character: ctll::action {}; struct push_character_alarm: ctll::action {}; struct push_character_anything: ctll::action {}; struct push_character_escape: ctll::action {}; struct push_character_formfeed: ctll::action {}; struct push_character_newline: ctll::action {}; struct push_character_null: ctll::action {}; struct push_character_return_carriage: ctll::action {}; struct push_character_tab: ctll::action {}; struct push_empty: ctll::action {}; struct push_hexdec: ctll::action {}; struct push_name: ctll::action {}; struct push_number: ctll::action {}; struct push_property_name: ctll::action {}; struct push_property_value: ctll::action {}; struct repeat_ab: ctll::action {}; struct repeat_at_least: ctll::action {}; struct repeat_exactly: ctll::action {}; struct repeat_plus: ctll::action {}; struct repeat_star: ctll::action {}; struct reset_capture: ctll::action {}; struct set_combine: ctll::action {}; struct set_make: ctll::action {}; struct set_make_negative: ctll::action {}; struct set_start: ctll::action {}; struct start_lookahead_negative: ctll::action {}; struct start_lookahead_positive: ctll::action {}; // (q)LL1 function: using _others = ctll::neg_set<'!','$','\x28','\x29','*','+',',','-','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','0','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D','1','2','3','4','5','6','7','8','9'>; static constexpr auto rule(s, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>; static constexpr auto rule(s, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>; static constexpr auto rule(s, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>; static constexpr auto rule(s, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>; static constexpr auto rule(s, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>; static constexpr auto rule(s, ctll::set<'!',',','-',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',']','_','0','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>; static constexpr auto rule(s, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>; static constexpr auto rule(s, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>; static constexpr auto rule(s, ctll::epsilon) -> ctll::push<push_empty>; static constexpr auto rule(s, ctll::set<'\x29','*','+','?','\x7B','|','\x7D'>) -> ctll::reject; static constexpr auto rule(a, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, ctll::set<'!',',','-',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',']','_','0','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2, make_alternate>; static constexpr auto rule(a, ctll::term<'\x29'>) -> ctll::push<push_empty, make_alternate>; static constexpr auto rule(a, ctll::epsilon) -> ctll::push<push_empty, make_alternate>; static constexpr auto rule(a, ctll::set<'*','+','?','\x7B','|','\x7D'>) -> ctll::reject; static constexpr auto rule(b, ctll::term<','>) -> ctll::push<ctll::anything, n>; static constexpr auto rule(b, ctll::term<'\x7D'>) -> ctll::push<repeat_exactly, ctll::anything>; static constexpr auto rule(backslash, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>; static constexpr auto rule(backslash, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>; static constexpr auto rule(backslash, ctll::term<'H'>) -> ctll::push<ctll::anything, class_non_horizontal_space>; static constexpr auto rule(backslash, ctll::term<'V'>) -> ctll::push<ctll::anything, class_non_vertical_space>; static constexpr auto rule(backslash, ctll::term<'D'>) -> ctll::push<ctll::anything, class_nondigit>; static constexpr auto rule(backslash, ctll::term<'N'>) -> ctll::push<ctll::anything, class_nonnewline>; static constexpr auto rule(backslash, ctll::term<'S'>) -> ctll::push<ctll::anything, class_nonspace>; static constexpr auto rule(backslash, ctll::term<'W'>) -> ctll::push<ctll::anything, class_nonword>; static constexpr auto rule(backslash, ctll::term<'s'>) -> ctll::push<ctll::anything, class_space>; static constexpr auto rule(backslash, ctll::term<'v'>) -> ctll::push<ctll::anything, class_vertical_space>; static constexpr auto rule(backslash, ctll::term<'w'>) -> ctll::push<ctll::anything, class_word>; static constexpr auto rule(backslash, ctll::set<'1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, make_back_reference>; static constexpr auto rule(backslash, ctll::term<'g'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, m>; static constexpr auto rule(backslash, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property>; static constexpr auto rule(backslash, ctll::term<'P'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property_negative>; static constexpr auto rule(backslash, ctll::term<'u'>) -> ctll::push<ctll::anything, k>; static constexpr auto rule(backslash, ctll::term<'x'>) -> ctll::push<ctll::anything, l>; static constexpr auto rule(backslash, ctll::set<'$','\x28','\x29','*','+','-','.','?','[','\\',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character>; static constexpr auto rule(backslash, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm>; static constexpr auto rule(backslash, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape>; static constexpr auto rule(backslash, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed>; static constexpr auto rule(backslash, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline>; static constexpr auto rule(backslash, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null>; static constexpr auto rule(backslash, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage>; static constexpr auto rule(backslash, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab>; static constexpr auto rule(backslash_range, ctll::term<'u'>) -> ctll::push<ctll::anything, k>; static constexpr auto rule(backslash_range, ctll::term<'x'>) -> ctll::push<ctll::anything, l>; static constexpr auto rule(backslash_range, ctll::term<'-'>) -> ctll::push<ctll::anything, push_character>; static constexpr auto rule(backslash_range, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm>; static constexpr auto rule(backslash_range, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape>; static constexpr auto rule(backslash_range, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed>; static constexpr auto rule(backslash_range, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline>; static constexpr auto rule(backslash_range, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null>; static constexpr auto rule(backslash_range, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage>; static constexpr auto rule(backslash_range, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab>; static constexpr auto rule(block, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, ctll::term<'?'>) -> ctll::push<ctll::anything, d>; static constexpr auto rule(block, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, ctll::set<'!',',','-',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',']','_','0','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2, make_capture, ctll::term<'\x29'>>; static constexpr auto rule(block, ctll::term<'\x29'>) -> ctll::push<push_empty, make_capture, ctll::anything>; static constexpr auto rule(block, ctll::set<'*','+','\x7B','|','\x7D'>) -> ctll::reject; static constexpr auto rule(block_name2, ctll::set<'>','\x7D'>) -> ctll::epsilon; static constexpr auto rule(block_name2, ctll::set<'0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_name, block_name2>; static constexpr auto rule(block_name, ctll::set<'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_name, block_name2>; static constexpr auto rule(c, ctll::term<'['>) -> ctll::push<ctll::anything, ctll::term<':'>, i, range, set_start, set2b, set_make, ctll::term<']'>>; static constexpr auto rule(c, ctll::term<'\\'>) -> ctll::push<ctll::anything, e, set_start, set2b, set_make, ctll::term<']'>>; static constexpr auto rule(c, ctll::set<'!','$','\x28','\x29','*','+',',','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','0','s','t','u','v','w','x','y','z','\x7B','\x7D','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, range, set_start, set2b, set_make, ctll::term<']'>>; static constexpr auto rule(c, _others) -> ctll::push<ctll::anything, push_character, range, set_start, set2b, set_make, ctll::term<']'>>; static constexpr auto rule(c, ctll::term<'^'>) -> ctll::push<ctll::anything, set2a, set_make_negative, ctll::term<']'>>; static constexpr auto rule(c, ctll::set<'-',']','|'>) -> ctll::reject; static constexpr auto rule(class_named_name, ctll::term<'x'>) -> ctll::push<ctll::anything, ctll::term<'d'>, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_xdigit>; static constexpr auto rule(class_named_name, ctll::term<'d'>) -> ctll::push<ctll::anything, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_digit>; static constexpr auto rule(class_named_name, ctll::term<'b'>) -> ctll::push<ctll::anything, ctll::term<'l'>, ctll::term<'a'>, ctll::term<'n'>, ctll::term<'k'>, class_named_blank>; static constexpr auto rule(class_named_name, ctll::term<'c'>) -> ctll::push<ctll::anything, ctll::term<'n'>, ctll::term<'t'>, ctll::term<'r'>, ctll::term<'l'>, class_named_cntrl>; static constexpr auto rule(class_named_name, ctll::term<'w'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'r'>, ctll::term<'d'>, class_named_word>; static constexpr auto rule(class_named_name, ctll::term<'l'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'w'>, ctll::term<'e'>, ctll::term<'r'>, class_named_lower>; static constexpr auto rule(class_named_name, ctll::term<'s'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'a'>, ctll::term<'c'>, ctll::term<'e'>, class_named_space>; static constexpr auto rule(class_named_name, ctll::term<'u'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'p'>, ctll::term<'e'>, ctll::term<'r'>, class_named_upper>; static constexpr auto rule(class_named_name, ctll::term<'g'>) -> ctll::push<ctll::anything, ctll::term<'r'>, ctll::term<'a'>, ctll::term<'p'>, ctll::term<'h'>, class_named_graph>; static constexpr auto rule(class_named_name, ctll::term<'a'>) -> ctll::push<ctll::anything, g>; static constexpr auto rule(class_named_name, ctll::term<'p'>) -> ctll::push<ctll::anything, h>; static constexpr auto rule(content2, ctll::term<'\x29'>) -> ctll::epsilon; static constexpr auto rule(content2, ctll::epsilon) -> ctll::epsilon; static constexpr auto rule(content2, ctll::term<'|'>) -> ctll::push<ctll::anything, a>; static constexpr auto rule(content_in_capture, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>; static constexpr auto rule(content_in_capture, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>; static constexpr auto rule(content_in_capture, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>; static constexpr auto rule(content_in_capture, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>; static constexpr auto rule(content_in_capture, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>; static constexpr auto rule(content_in_capture, ctll::set<'!',',','-',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',']','_','0','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>; static constexpr auto rule(content_in_capture, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>; static constexpr auto rule(content_in_capture, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>; static constexpr auto rule(content_in_capture, ctll::term<'\x29'>) -> ctll::push<push_empty>; static constexpr auto rule(content_in_capture, ctll::set<'*','+','?','\x7B','|','\x7D'>) -> ctll::reject; static constexpr auto rule(d, ctll::term<'<'>) -> ctll::push<ctll::anything, block_name, ctll::term<'>'>, content_in_capture, make_capture_with_name, ctll::term<'\x29'>>; static constexpr auto rule(d, ctll::term<':'>) -> ctll::push<reset_capture, ctll::anything, content_in_capture, ctll::term<'\x29'>>; static constexpr auto rule(d, ctll::term<'!'>) -> ctll::push<reset_capture, ctll::anything, start_lookahead_negative, content_in_capture, look_finish, ctll::term<'\x29'>>; static constexpr auto rule(d, ctll::term<'='>) -> ctll::push<reset_capture, ctll::anything, start_lookahead_positive, content_in_capture, look_finish, ctll::term<'\x29'>>; static constexpr auto rule(e, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>; static constexpr auto rule(e, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>; static constexpr auto rule(e, ctll::term<'H'>) -> ctll::push<ctll::anything, class_non_horizontal_space>; static constexpr auto rule(e, ctll::term<'V'>) -> ctll::push<ctll::anything, class_non_vertical_space>; static constexpr auto rule(e, ctll::term<'D'>) -> ctll::push<ctll::anything, class_nondigit>; static constexpr auto rule(e, ctll::term<'N'>) -> ctll::push<ctll::anything, class_nonnewline>; static constexpr auto rule(e, ctll::term<'S'>) -> ctll::push<ctll::anything, class_nonspace>; static constexpr auto rule(e, ctll::term<'W'>) -> ctll::push<ctll::anything, class_nonword>; static constexpr auto rule(e, ctll::term<'s'>) -> ctll::push<ctll::anything, class_space>; static constexpr auto rule(e, ctll::term<'v'>) -> ctll::push<ctll::anything, class_vertical_space>; static constexpr auto rule(e, ctll::term<'w'>) -> ctll::push<ctll::anything, class_word>; static constexpr auto rule(e, ctll::set<'1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, make_back_reference>; static constexpr auto rule(e, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property>; static constexpr auto rule(e, ctll::term<'P'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property_negative>; static constexpr auto rule(e, ctll::term<'u'>) -> ctll::push<ctll::anything, k, range>; static constexpr auto rule(e, ctll::term<'x'>) -> ctll::push<ctll::anything, l, range>; static constexpr auto rule(e, ctll::term<'-'>) -> ctll::push<ctll::anything, p>; static constexpr auto rule(e, ctll::set<'$','\x28','\x29','*','+','.','?','[','\\',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character>; static constexpr auto rule(e, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm, range>; static constexpr auto rule(e, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape, range>; static constexpr auto rule(e, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed, range>; static constexpr auto rule(e, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline, range>; static constexpr auto rule(e, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null, range>; static constexpr auto rule(e, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage, range>; static constexpr auto rule(e, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab, range>; static constexpr auto rule(f, ctll::term<'d'>) -> ctll::push<ctll::anything, class_digit>; static constexpr auto rule(f, ctll::term<'h'>) -> ctll::push<ctll::anything, class_horizontal_space>; static constexpr auto rule(f, ctll::term<'H'>) -> ctll::push<ctll::anything, class_non_horizontal_space>; static constexpr auto rule(f, ctll::term<'V'>) -> ctll::push<ctll::anything, class_non_vertical_space>; static constexpr auto rule(f, ctll::term<'D'>) -> ctll::push<ctll::anything, class_nondigit>; static constexpr auto rule(f, ctll::term<'N'>) -> ctll::push<ctll::anything, class_nonnewline>; static constexpr auto rule(f, ctll::term<'S'>) -> ctll::push<ctll::anything, class_nonspace>; static constexpr auto rule(f, ctll::term<'W'>) -> ctll::push<ctll::anything, class_nonword>; static constexpr auto rule(f, ctll::term<'s'>) -> ctll::push<ctll::anything, class_space>; static constexpr auto rule(f, ctll::term<'v'>) -> ctll::push<ctll::anything, class_vertical_space>; static constexpr auto rule(f, ctll::term<'w'>) -> ctll::push<ctll::anything, class_word>; static constexpr auto rule(f, ctll::set<'1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, make_back_reference>; static constexpr auto rule(f, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property>; static constexpr auto rule(f, ctll::term<'P'>) -> ctll::push<ctll::anything, ctll::term<'\x7B'>, property_name, ctll::term<'\x7D'>, make_property_negative>; static constexpr auto rule(f, ctll::term<'u'>) -> ctll::push<ctll::anything, k, range>; static constexpr auto rule(f, ctll::term<'x'>) -> ctll::push<ctll::anything, l, range>; static constexpr auto rule(f, ctll::set<'$','\x28','\x29','*','+','.','?','[','\\',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character>; static constexpr auto rule(f, ctll::term<'a'>) -> ctll::push<ctll::anything, push_character_alarm, range>; static constexpr auto rule(f, ctll::term<'e'>) -> ctll::push<ctll::anything, push_character_escape, range>; static constexpr auto rule(f, ctll::term<'f'>) -> ctll::push<ctll::anything, push_character_formfeed, range>; static constexpr auto rule(f, ctll::term<'n'>) -> ctll::push<ctll::anything, push_character_newline, range>; static constexpr auto rule(f, ctll::term<'0'>) -> ctll::push<ctll::anything, push_character_null, range>; static constexpr auto rule(f, ctll::term<'r'>) -> ctll::push<ctll::anything, push_character_return_carriage, range>; static constexpr auto rule(f, ctll::term<'t'>) -> ctll::push<ctll::anything, push_character_tab, range>; static constexpr auto rule(f, ctll::term<'-'>) -> ctll::push<ctll::anything, q>; static constexpr auto rule(g, ctll::term<'s'>) -> ctll::push<ctll::anything, ctll::term<'c'>, ctll::term<'i'>, ctll::term<'i'>, class_named_ascii>; static constexpr auto rule(g, ctll::term<'l'>) -> ctll::push<ctll::anything, o>; static constexpr auto rule(h, ctll::term<'r'>) -> ctll::push<ctll::anything, ctll::term<'i'>, ctll::term<'n'>, ctll::term<'t'>, class_named_print>; static constexpr auto rule(h, ctll::term<'u'>) -> ctll::push<ctll::anything, ctll::term<'n'>, ctll::term<'c'>, ctll::term<'t'>, class_named_punct>; static constexpr auto rule(hexdec_repeat, ctll::term<'\x7D'>) -> ctll::epsilon; static constexpr auto rule(hexdec_repeat, ctll::set<'0','A','B','C','D','E','F','a','b','c','d','e','f','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_hexdec, hexdec_repeat>; static constexpr auto rule(i, ctll::term<'^'>) -> ctll::push<ctll::anything, class_named_name, negate_class_named, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'x'>) -> ctll::push<ctll::anything, ctll::term<'d'>, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_xdigit, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'d'>) -> ctll::push<ctll::anything, ctll::term<'i'>, ctll::term<'g'>, ctll::term<'i'>, ctll::term<'t'>, class_named_digit, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'b'>) -> ctll::push<ctll::anything, ctll::term<'l'>, ctll::term<'a'>, ctll::term<'n'>, ctll::term<'k'>, class_named_blank, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'c'>) -> ctll::push<ctll::anything, ctll::term<'n'>, ctll::term<'t'>, ctll::term<'r'>, ctll::term<'l'>, class_named_cntrl, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'w'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'r'>, ctll::term<'d'>, class_named_word, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'l'>) -> ctll::push<ctll::anything, ctll::term<'o'>, ctll::term<'w'>, ctll::term<'e'>, ctll::term<'r'>, class_named_lower, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'s'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'a'>, ctll::term<'c'>, ctll::term<'e'>, class_named_space, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'u'>) -> ctll::push<ctll::anything, ctll::term<'p'>, ctll::term<'p'>, ctll::term<'e'>, ctll::term<'r'>, class_named_upper, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'g'>) -> ctll::push<ctll::anything, ctll::term<'r'>, ctll::term<'a'>, ctll::term<'p'>, ctll::term<'h'>, class_named_graph, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'a'>) -> ctll::push<ctll::anything, g, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(i, ctll::term<'p'>) -> ctll::push<ctll::anything, h, ctll::term<':'>, ctll::term<']'>>; static constexpr auto rule(j, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash_range, make_range>; static constexpr auto rule(j, ctll::set<'!','$','\x28','\x29','*','+',',','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','0','s','t','u','v','w','x','y','z','\x7B','\x7D','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, make_range>; static constexpr auto rule(j, _others) -> ctll::push<ctll::anything, push_character, make_range>; static constexpr auto rule(j, ctll::set<'-','[',']','^','|'>) -> ctll::reject; static constexpr auto rule(k, ctll::term<'\x7B'>) -> ctll::push<create_hexdec, ctll::anything, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, hexdec_repeat, ctll::term<'\x7D'>, finish_hexdec>; static constexpr auto rule(k, ctll::set<'0','A','B','C','D','E','F','a','b','c','d','e','f','1','2','3','4','5','6','7','8','9'>) -> ctll::push<create_hexdec, ctll::anything, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, finish_hexdec>; static constexpr auto rule(l, ctll::term<'\x7B'>) -> ctll::push<create_hexdec, ctll::anything, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, hexdec_repeat, ctll::term<'\x7D'>, finish_hexdec>; static constexpr auto rule(l, ctll::set<'0','A','B','C','D','E','F','a','b','c','d','e','f','1','2','3','4','5','6','7','8','9'>) -> ctll::push<create_hexdec, ctll::anything, push_hexdec, ctll::set<'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>, push_hexdec, finish_hexdec>; static constexpr auto rule(m, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, number2, ctll::term<'\x7D'>, make_back_reference>; static constexpr auto rule(m, ctll::term<'-'>) -> ctll::push<ctll::anything, number, ctll::term<'\x7D'>, make_relative_back_reference>; static constexpr auto rule(m, ctll::set<'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'>) -> ctll::push<ctll::anything, push_name, block_name2, ctll::term<'\x7D'>, make_back_reference>; static constexpr auto rule(mod, ctll::set<'!','$','\x28','\x29',',','-','.',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|','0','1','2','3','4','5','6','7','8','9'>) -> ctll::epsilon; static constexpr auto rule(mod, ctll::epsilon) -> ctll::epsilon; static constexpr auto rule(mod, _others) -> ctll::epsilon; static constexpr auto rule(mod, ctll::term<'?'>) -> ctll::push<ctll::anything, make_lazy>; static constexpr auto rule(mod, ctll::term<'+'>) -> ctll::push<ctll::anything, make_possessive>; static constexpr auto rule(mod, ctll::set<'*','\x7B','\x7D'>) -> ctll::reject; static constexpr auto rule(mod_opt, ctll::set<'!','$','\x28','\x29',',','-','.',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|','0','1','2','3','4','5','6','7','8','9'>) -> ctll::epsilon; static constexpr auto rule(mod_opt, ctll::epsilon) -> ctll::epsilon; static constexpr auto rule(mod_opt, _others) -> ctll::epsilon; static constexpr auto rule(mod_opt, ctll::term<'?'>) -> ctll::push<ctll::anything, make_lazy>; static constexpr auto rule(mod_opt, ctll::set<'*','+','\x7B','\x7D'>) -> ctll::reject; static constexpr auto rule(n, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, number2, repeat_ab, ctll::term<'\x7D'>, mod>; static constexpr auto rule(n, ctll::term<'\x7D'>) -> ctll::push<repeat_at_least, ctll::anything, mod>; static constexpr auto rule(number2, ctll::set<',','\x7D'>) -> ctll::epsilon; static constexpr auto rule(number2, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_number, number2>; static constexpr auto rule(number, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, create_number, number2>; static constexpr auto rule(o, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'h'>, ctll::term<'a'>, class_named_alpha>; static constexpr auto rule(o, ctll::term<'n'>) -> ctll::push<ctll::anything, ctll::term<'u'>, ctll::term<'m'>, class_named_alnum>; static constexpr auto rule(p, ctll::term<'-'>) -> ctll::push<push_character, ctll::anything, j>; static constexpr auto rule(p, ctll::set<'!','$','\x28','\x29','*','+',',','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','\x7D','0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<push_character>; static constexpr auto rule(p, ctll::epsilon) -> ctll::push<push_character>; static constexpr auto rule(p, _others) -> ctll::push<push_character>; static constexpr auto rule(p, ctll::term<'|'>) -> ctll::reject; static constexpr auto rule(property_name2, ctll::term<'\x7D'>) -> ctll::epsilon; static constexpr auto rule(property_name2, ctll::term<'='>) -> ctll::push<ctll::anything, property_value>; static constexpr auto rule(property_name2, ctll::set<'0','.','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_property_name, property_name2>; static constexpr auto rule(property_name, ctll::set<'0','.','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_property_name, property_name2>; static constexpr auto rule(property_value2, ctll::term<'\x7D'>) -> ctll::epsilon; static constexpr auto rule(property_value2, ctll::set<'0','.','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_property_value, property_value2>; static constexpr auto rule(property_value, ctll::set<'0','.','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_property_value, property_value2>; static constexpr auto rule(q, ctll::term<'-'>) -> ctll::push<push_character, ctll::anything, j>; static constexpr auto rule(q, ctll::set<'!','$','\x28','\x29','*','+',',','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','\x7D','0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<push_character>; static constexpr auto rule(q, ctll::epsilon) -> ctll::push<push_character>; static constexpr auto rule(q, _others) -> ctll::push<push_character>; static constexpr auto rule(q, ctll::term<'|'>) -> ctll::reject; static constexpr auto rule(range, ctll::set<'!','$','\x28','\x29','*','+',',','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','\x7D','0','1','2','3','4','5','6','7','8','9'>) -> ctll::epsilon; static constexpr auto rule(range, ctll::epsilon) -> ctll::epsilon; static constexpr auto rule(range, _others) -> ctll::epsilon; static constexpr auto rule(range, ctll::term<'-'>) -> ctll::push<ctll::anything, j>; static constexpr auto rule(range, ctll::term<'|'>) -> ctll::reject; static constexpr auto rule(repeat, ctll::set<'!','$','\x28','\x29',',','-','.',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|','0','1','2','3','4','5','6','7','8','9'>) -> ctll::epsilon; static constexpr auto rule(repeat, ctll::epsilon) -> ctll::epsilon; static constexpr auto rule(repeat, _others) -> ctll::epsilon; static constexpr auto rule(repeat, ctll::term<'?'>) -> ctll::push<ctll::anything, make_optional, mod_opt>; static constexpr auto rule(repeat, ctll::term<'\x7B'>) -> ctll::push<ctll::anything, number, b>; static constexpr auto rule(repeat, ctll::term<'+'>) -> ctll::push<ctll::anything, repeat_plus, mod>; static constexpr auto rule(repeat, ctll::term<'*'>) -> ctll::push<ctll::anything, repeat_star, mod>; static constexpr auto rule(repeat, ctll::term<'\x7D'>) -> ctll::reject; static constexpr auto rule(set2a, ctll::term<']'>) -> ctll::epsilon; static constexpr auto rule(set2a, ctll::term<'['>) -> ctll::push<ctll::anything, ctll::term<':'>, i, range, set_start, set2b>; static constexpr auto rule(set2a, ctll::term<'\\'>) -> ctll::push<ctll::anything, f, set_start, set2b>; static constexpr auto rule(set2a, ctll::set<'!','$','\x28','\x29','*','+',',','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','0','s','t','u','v','w','x','y','z','\x7B','\x7D','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, range, set_start, set2b>; static constexpr auto rule(set2a, _others) -> ctll::push<ctll::anything, push_character, range, set_start, set2b>; static constexpr auto rule(set2a, ctll::set<'-','|'>) -> ctll::reject; static constexpr auto rule(set2b, ctll::term<']'>) -> ctll::epsilon; static constexpr auto rule(set2b, ctll::term<'['>) -> ctll::push<ctll::anything, ctll::term<':'>, i, range, set_combine, set2b>; static constexpr auto rule(set2b, ctll::term<'\\'>) -> ctll::push<ctll::anything, f, set_combine, set2b>; static constexpr auto rule(set2b, ctll::set<'!','$','\x28','\x29','*','+',',','.',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','0','s','t','u','v','w','x','y','z','\x7B','\x7D','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, range, set_combine, set2b>; static constexpr auto rule(set2b, _others) -> ctll::push<ctll::anything, push_character, range, set_combine, set2b>; static constexpr auto rule(set2b, ctll::set<'-','|'>) -> ctll::reject; static constexpr auto rule(string2, ctll::set<'\x29','|'>) -> ctll::epsilon; static constexpr auto rule(string2, ctll::epsilon) -> ctll::epsilon; static constexpr auto rule(string2, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, make_sequence>; static constexpr auto rule(string2, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, make_sequence>; static constexpr auto rule(string2, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, make_sequence>; static constexpr auto rule(string2, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, make_sequence>; static constexpr auto rule(string2, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, make_sequence>; static constexpr auto rule(string2, ctll::set<'!',',','-',':','<','=','>','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',']','_','0','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9'>) -> ctll::push<ctll::anything, push_character, repeat, string2, make_sequence>; static constexpr auto rule(string2, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, make_sequence>; static constexpr auto rule(string2, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, make_sequence>; static constexpr auto rule(string2, ctll::set<'*','+','?','\x7B','\x7D'>) -> ctll::reject; }; } #endif //CTRE__PCRE__HPP #ifndef CTRE__ATOMS__HPP #define CTRE__ATOMS__HPP #include <cstdint> namespace ctre { // special helpers for matching struct accept { }; struct reject { }; struct start_mark { }; struct end_mark { }; struct end_cycle_mark { }; struct end_lookahead_mark { }; template <size_t Id> struct numeric_mark { }; // actual AST of regexp template <auto... Str> struct string { }; template <typename... Opts> struct select { }; template <typename... Content> struct optional { }; template <typename... Content> struct lazy_optional { }; template <typename... Content> struct sequence { }; struct empty { }; template <typename... Content> struct plus { }; template <typename... Content> struct star { }; template <size_t a, size_t b, typename... Content> struct repeat { }; template <typename... Content> struct lazy_plus { }; template <typename... Content> struct lazy_star { }; template <size_t a, size_t b, typename... Content> struct lazy_repeat { }; template <typename... Content> struct possessive_plus { }; template <typename... Content> struct possessive_star { }; template <size_t a, size_t b, typename... Content> struct possessive_repeat { }; template <size_t Index, typename... Content> struct capture { }; template <size_t Index, typename Name, typename... Content> struct capture_with_name { }; template <size_t Index> struct back_reference { }; template <typename Name> struct back_reference_with_name { }; template <typename Type> struct look_start { }; template <typename... Content> struct lookahead_positive { }; template <typename... Content> struct lookahead_negative { }; struct assert_begin { }; struct assert_end { }; } #endif #ifndef CTRE__ATOMS_CHARACTERS__HPP #define CTRE__ATOMS_CHARACTERS__HPP #ifndef CTRE__UTILITY__HPP #define CTRE__UTILITY__HPP #ifdef _MSC_VER #define CTRE_FORCE_INLINE __forceinline #define CTRE_FLATTEN #else #define CTRE_FORCE_INLINE inline __attribute__((always_inline)) #define CTRE_FLATTEN __attribute__((flatten)) #endif #endif #include <cstdint> namespace ctre { // sfinae check for types here template <typename T> class MatchesCharacter { template <typename Y, typename CharT> static auto test(CharT c) -> decltype(Y::match_char(c), std::true_type()); template <typename> static auto test(...) -> std::false_type; public: template <typename CharT> static inline constexpr bool value = decltype(test<T>(std::declval<CharT>()))(); }; template <auto V> struct character { template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value) noexcept { return value == V; } }; struct any { template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT) noexcept { return true; } }; template <typename... Content> struct negative_set { template <typename CharT> inline static constexpr bool match_char(CharT value) noexcept { return !(Content::match_char(value) || ... || false); } }; template <typename... Content> struct set { template <typename CharT> inline static constexpr bool match_char(CharT value) noexcept { return (Content::match_char(value) || ... || false); } }; template <auto... Cs> struct enumeration : set<character<Cs>...> { }; template <typename... Content> struct negate { template <typename CharT> inline static constexpr bool match_char(CharT value) noexcept { return !(Content::match_char(value) || ... || false); } }; template <auto A, auto B> struct char_range { template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value) noexcept { return (value >= A) && (value <= B); } }; using word_chars = set<char_range<'A','Z'>, char_range<'a','z'>, char_range<'0','9'>, character<'_'> >; using space_chars = enumeration<' ', '\t', '\n', '\v', '\f', '\r'>; using vertical_space_chars = enumeration< (char)0x000A, // Linefeed (LF) (char)0x000B, // Vertical tab (VT) (char)0x000C, // Form feed (FF) (char)0x000D, // Carriage return (CR) (char32_t)0x0085, // Next line (NEL) (char32_t)0x2028, // Line separator (char32_t)0x2029 // Paragraph separator >; using horizontal_space_chars = enumeration< (char)0x0009, // Horizontal tab (HT) (char)0x0020, // Space (char32_t)0x00A0, // Non-break space (char32_t)0x1680, // Ogham space mark (char32_t)0x180E, // Mongolian vowel separator (char32_t)0x2000, // En quad (char32_t)0x2001, // Em quad (char32_t)0x2002, // En space (char32_t)0x2003, // Em space (char32_t)0x2004, // Three-per-em space (char32_t)0x2005, // Four-per-em space (char32_t)0x2006, // Six-per-em space (char32_t)0x2007, // Figure space (char32_t)0x2008, // Punctuation space (char32_t)0x2009, // Thin space (char32_t)0x200A, // Hair space (char32_t)0x202F, // Narrow no-break space (char32_t)0x205F, // Medium mathematical space (char32_t)0x3000 // Ideographic space >; using alphanum_chars = set<char_range<'A','Z'>, char_range<'a','z'>, char_range<'0','9'> >; using alpha_chars = set<char_range<'A','Z'>, char_range<'a','z'> >; using xdigit_chars = set<char_range<'A','F'>, char_range<'a','f'>, char_range<'0','9'> >; using punct_chars = enumeration<'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'>; using digit_chars = char_range<'0','9'>; using ascii_chars = char_range<'\x00','\x7F'>; } #endif #ifndef CTRE__ATOMS_UNICODE__HPP #define CTRE__ATOMS_UNICODE__HPP // master branch is not including unicode db (for now) // #include "../unicode-db/unicode.hpp" #include <array> namespace ctre { // properties name & value template <auto... Str> struct property_name { }; template <auto... Str> struct property_value { }; template <size_t Sz> constexpr std::string_view get_string_view(const std::array<char, Sz> & arr) noexcept { return std::string_view(arr.data(), arr.size()); } // basic support for binary and type-value properties template <auto Name> struct binary_property; template <auto Name, auto Value> struct property; // unicode TS#18 level 1.2 general_category //template <uni::__binary_prop Property> struct binary_property<Property> { // template <typename CharT> inline static constexpr bool match_char(CharT) noexcept { // return uni::__get_binary_prop<Property>(c); // } //}; // unicode TS#18 level 1.2.2 enum class property_type { script, script_extension, age, block, unknown }; // unicode TS#18 level 1.2.2 //template <uni::script Script> struct binary_property<Script> { // template <typename CharT> inline static constexpr bool match_char(CharT) noexcept { // return uni::cp_script(c) == Script; // } //}; // //template <uni::script Script> struct property<property_type::script_extension, Script> { // template <typename CharT> inline static constexpr bool match_char(CharT c) noexcept { // for (uni::script sc: uni::cp_script_extensions(c)) { // if (sc == Script) return true; // } // return false; // } //}; //template <uni::version Age> struct binary_property<Age> { // template <typename CharT> inline static constexpr bool match_char(CharT c) noexcept { // return uni::cp_age(c) <= Age; // } //}; // //template <uni::block Block> struct binary_property<Block> { // template <typename CharT> inline static constexpr bool match_char(CharT c) noexcept { // return uni::cp_block(c) == Block; // } //}; // nonbinary properties constexpr property_type property_type_from_name(std::string_view) noexcept { return property_type::unknown; //using namespace std::string_view_literals; //if (uni::__pronamecomp(str, "script"sv) == 0 || uni::__pronamecomp(str, "sc"sv) == 0) { // return property_type::script; //} else if (uni::__pronamecomp(str, "script_extension"sv) == 0 || uni::__pronamecomp(str, "scx"sv) == 0) { // return property_type::script_extension; //} else if (uni::__pronamecomp(str, "age"sv) == 0) { // return property_type::age; //} else if (uni::__pronamecomp(str, "block"sv) == 0) { // return property_type::block; //} else { // return property_type::unknown; //} } template <property_type Property> struct property_type_builder { template <auto... Value> static constexpr auto get() { return ctll::reject{}; } }; template <auto... Name> struct property_builder { static constexpr std::array<char, sizeof...(Name)> name{static_cast<char>(Name)...}; static constexpr property_type type = property_type_from_name(get_string_view(name)); using helper = property_type_builder<type>; template <auto... Value> static constexpr auto get() { return helper::template get<Value...>(); } }; // unicode TS#18 level 1.2.2 script support //template <> struct property_type_builder<property_type::script> { // template <auto... Value> static constexpr auto get() { // constexpr std::array<char, sizeof...(Value)> value{Value...}; // constexpr auto sc = uni::__script_from_string(get_string_view(value)); // if constexpr (sc == uni::script::unknown) { // return ctll::reject{}; // } else { // return binary_property<sc>(); // } // } //}; // //template <> struct property_type_builder<property_type::script_extension> { // template <auto... Value> static constexpr auto get() { // constexpr std::array<char, sizeof...(Value)> value{Value...}; // constexpr auto sc = uni::__script_from_string(get_string_view(value)); // if constexpr (sc == uni::script::unknown) { // return ctll::reject{}; // } else { // return property<property_type::script_extension, sc>(); // } // } //}; // //template <> struct property_type_builder<property_type::age> { // template <auto... Value> static constexpr auto get() { // constexpr std::array<char, sizeof...(Value)> value{Value...}; // constexpr auto age = uni::__age_from_string(get_string_view(value)); // if constexpr (age == uni::version::unassigned) { // return ctll::reject{}; // } else { // return binary_property<age>(); // } // } //}; // //template <> struct property_type_builder<property_type::block> { // template <auto... Value> static constexpr auto get() { // constexpr std::array<char, sizeof...(Value)> value{Value...}; // constexpr auto block = uni::__block_from_string(get_string_view(value)); // if constexpr (block == uni::block::no_block) { // return ctll::reject{}; // } else { // return binary_property<block>(); // } // } //}; } #endif #ifndef CTRE__ID__HPP #define CTRE__ID__HPP #include <type_traits> namespace ctre { template <auto... Name> struct id { static constexpr auto name = ctll::fixed_string<sizeof...(Name)>{{Name...}}; }; template <auto... Name> constexpr auto operator==(id<Name...>, id<Name...>) noexcept -> std::true_type { return {}; } template <auto... Name1, auto... Name2> constexpr auto operator==(id<Name1...>, id<Name2...>) noexcept -> std::false_type { return {}; } template <auto... Name, typename T> constexpr auto operator==(id<Name...>, T) noexcept -> std::false_type { return {}; } } #endif #include <cstdint> #include <limits> namespace ctre { template <size_t Counter> struct pcre_parameters { static constexpr size_t current_counter = Counter; }; template <typename Stack = ctll::list<>, typename Parameters = pcre_parameters<0>> struct pcre_context { using stack_type = Stack; using parameters_type = Parameters; static constexpr inline auto stack = stack_type(); static constexpr inline auto parameters = parameters_type(); constexpr pcre_context() noexcept { } constexpr pcre_context(Stack, Parameters) noexcept { } }; template <typename... Content, typename Parameters> pcre_context(ctll::list<Content...>, Parameters) -> pcre_context<ctll::list<Content...>, Parameters>; template <size_t Value> struct number { }; template <size_t Id> struct capture_id { }; struct pcre_actions { // i know it's ugly, but it's more readable #ifndef CTRE__ACTIONS__ASSERTS__HPP #define CTRE__ACTIONS__ASSERTS__HPP // push_assert_begin template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_begin, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(assert_begin(), subject.stack), subject.parameters}; } // push_assert_end template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_end, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(assert_end(), subject.stack), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__BACKREFERENCE__HPP #define CTRE__ACTIONS__BACKREFERENCE__HPP // backreference with name template <auto... Str, auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_back_reference, ctll::term<V>, pcre_context<ctll::list<id<Str...>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::push_front(back_reference_with_name<id<Str...>>(), ctll::list<Ts...>()), pcre_parameters<Counter>()}; } // with just a number template <auto V, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_back_reference, ctll::term<V>, pcre_context<ctll::list<number<Id>, Ts...>, pcre_parameters<Counter>>) { // if we are looking outside of existing list of Ids ... reject input during parsing if constexpr (Counter < Id) { return ctll::reject{}; } else { return pcre_context{ctll::push_front(back_reference<Id>(), ctll::list<Ts...>()), pcre_parameters<Counter>()}; } } // relative backreference template <auto V, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_relative_back_reference, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<number<Id>, Ts...>, pcre_parameters<Counter>>) { // if we are looking outside of existing list of Ids ... reject input during parsing if constexpr (Counter < Id) { return ctll::reject{}; } else { constexpr size_t absolute_id = (Counter + 1) - Id; return pcre_context{ctll::push_front(back_reference<absolute_id>(), ctll::list<Ts...>()), pcre_parameters<Counter>()}; } } #endif #ifndef CTRE__ACTIONS__CAPTURE__HPP #define CTRE__ACTIONS__CAPTURE__HPP // prepare_capture template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::prepare_capture, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::push_front(capture_id<Counter+1>(), ctll::list<Ts...>()), pcre_parameters<Counter+1>()}; } // reset_capture template <auto V, typename... Ts, size_t Id, size_t Counter> static constexpr auto apply(pcre::reset_capture, ctll::term<V>, pcre_context<ctll::list<capture_id<Id>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::list<Ts...>(), pcre_parameters<Counter-1>()}; } // capture template <auto V, typename A, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture, ctll::term<V>, pcre_context<ctll::list<A, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::push_front(capture<Id, A>(), ctll::list<Ts...>()), pcre_parameters<Counter>()}; } // capture (sequence) template <auto V, typename... Content, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::push_front(capture<Id, Content...>(), ctll::list<Ts...>()), pcre_parameters<Counter>()}; } // push_name template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_name, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(id<V>(), subject.stack), subject.parameters}; } // push_name (concat) template <auto... Str, auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_name, ctll::term<V>, pcre_context<ctll::list<id<Str...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(id<Str..., V>(), ctll::list<Ts...>()), subject.parameters}; } // capture with name template <auto... Str, auto V, typename A, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture_with_name, ctll::term<V>, pcre_context<ctll::list<A, id<Str...>, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::push_front(capture_with_name<Id, id<Str...>, A>(), ctll::list<Ts...>()), pcre_parameters<Counter>()}; } // capture with name (sequence) template <auto... Str, auto V, typename... Content, size_t Id, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_capture_with_name, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, id<Str...>, capture_id<Id>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::push_front(capture_with_name<Id, id<Str...>, Content...>(), ctll::list<Ts...>()), pcre_parameters<Counter>()}; } #endif #ifndef CTRE__ACTIONS__CHARACTERS__HPP #define CTRE__ACTIONS__CHARACTERS__HPP // push character template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<V>(), subject.stack), subject.parameters}; } // push_any_character template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_anything, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(any(), subject.stack), subject.parameters}; } // character_alarm template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_alarm, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<'\x07'>(), subject.stack), subject.parameters}; } // character_escape template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_escape, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<'\x14'>(), subject.stack), subject.parameters}; } // character_formfeed template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_formfeed, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<'\x0C'>(), subject.stack), subject.parameters}; } // push_character_newline template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_newline, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<'\x0A'>(), subject.stack), subject.parameters}; } // push_character_null template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_null, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<'\0'>(), subject.stack), subject.parameters}; } // push_character_return_carriage template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_return_carriage, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<'\x0D'>(), subject.stack), subject.parameters}; } // push_character_tab template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_character_tab, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(character<'\x09'>(), subject.stack), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__CLASS__HPP #define CTRE__ACTIONS__CLASS__HPP // class_digit template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_digit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::set<ctre::digit_chars>(), subject.stack), subject.parameters}; } // class_non_digit template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nondigit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::negative_set<ctre::digit_chars>(), subject.stack), subject.parameters}; } // class_space template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::set<ctre::space_chars>(), subject.stack), subject.parameters}; } // class_nonspace template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nonspace, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::negative_set<ctre::space_chars>(), subject.stack), subject.parameters}; } // class_horizontal_space template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_horizontal_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::set<ctre::horizontal_space_chars>(), subject.stack), subject.parameters}; } // class_horizontal_nonspace template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_non_horizontal_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::negative_set<ctre::horizontal_space_chars>(), subject.stack), subject.parameters}; } // class_vertical_space template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_vertical_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::set<ctre::vertical_space_chars>(), subject.stack), subject.parameters}; } // class_vertical_nonspace template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_non_vertical_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::negative_set<ctre::vertical_space_chars>(), subject.stack), subject.parameters}; } // class_word template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_word, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::set<ctre::word_chars>(), subject.stack), subject.parameters}; } // class_nonword template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nonword, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::negative_set<ctre::word_chars>(), subject.stack), subject.parameters}; } // class_nonnewline template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_nonnewline, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::negative_set<character<'\n'>>(), subject.stack), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__HEXDEC__HPP #define CTRE__ACTIONS__HEXDEC__HPP // hexdec character support (seed) template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::create_hexdec, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(number<0ull>(), subject.stack), subject.parameters}; } // hexdec character support (push value) template <auto V, size_t N, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_hexdec, ctll::term<V>, pcre_context<ctll::list<number<N>, Ts...>, Parameters> subject) { constexpr auto previous = N << 4ull; if constexpr (V >= 'a' && V <= 'f') { return pcre_context{ctll::push_front(number<(previous + (V - 'a' + 10))>(), ctll::list<Ts...>()), subject.parameters}; } else if constexpr (V >= 'A' && V <= 'F') { return pcre_context{ctll::push_front(number<(previous + (V - 'A' + 10))>(), ctll::list<Ts...>()), subject.parameters}; } else { return pcre_context{ctll::push_front(number<(previous + (V - '0'))>(), ctll::list<Ts...>()), subject.parameters}; } } // hexdec character support (convert to character) template <auto V, size_t N, typename... Ts, typename Parameters> static constexpr auto apply(pcre::finish_hexdec, ctll::term<V>, pcre_context<ctll::list<number<N>, Ts...>, Parameters> subject) { constexpr size_t max_char = std::numeric_limits<char>::max(); if constexpr (N <= max_char) { return pcre_context{ctll::push_front(character<(char)N>(), ctll::list<Ts...>()), subject.parameters}; } else { return pcre_context{ctll::push_front(character<(char32_t)N>(), ctll::list<Ts...>()), subject.parameters}; } } #endif #ifndef CTRE__ACTIONS__LOOKAHEAD__HPP #define CTRE__ACTIONS__LOOKAHEAD__HPP // lookahead positive start template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookahead_positive, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::list<look_start<lookahead_positive<>>, Ts...>(), pcre_parameters<Counter>()}; } // lookahead positive end template <auto V, typename Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<Look, look_start<lookahead_positive<>>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::list<lookahead_positive<Look>, Ts...>(), pcre_parameters<Counter>()}; } // lookahead positive end (sequence) template <auto V, typename... Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<ctre::sequence<Look...>, look_start<lookahead_positive<>>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::list<lookahead_positive<Look...>, Ts...>(), pcre_parameters<Counter>()}; } // lookahead negative start template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookahead_negative, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::list<look_start<lookahead_negative<>>, Ts...>(), pcre_parameters<Counter>()}; } // lookahead negative end template <auto V, typename Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<Look, look_start<lookahead_negative<>>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::list<lookahead_negative<Look>, Ts...>(), pcre_parameters<Counter>()}; } // lookahead negative end (sequence) template <auto V, typename... Look, typename... Ts, size_t Counter> static constexpr auto apply(pcre::look_finish, ctll::term<V>, pcre_context<ctll::list<ctre::sequence<Look...>, look_start<lookahead_negative<>>, Ts...>, pcre_parameters<Counter>>) { return pcre_context{ctll::list<lookahead_negative<Look...>, Ts...>(), pcre_parameters<Counter>()}; } #endif #ifndef CTRE__ACTIONS__NAMED_CLASS__HPP #define CTRE__ACTIONS__NAMED_CLASS__HPP // class_named_alnum template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_alnum, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::alphanum_chars(), subject.stack), subject.parameters}; } // class_named_alpha template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_alpha, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::alpha_chars(), subject.stack), subject.parameters}; } // class_named_digit template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_digit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::digit_chars(), subject.stack), subject.parameters}; } // class_named_ascii template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_ascii, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::ascii_chars(), subject.stack), subject.parameters}; } // class_named_blank template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_blank, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::enumeration<' ','\t'>(), subject.stack), subject.parameters}; } // class_named_cntrl template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_cntrl, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::set<ctre::char_range<'\x00','\x1F'>, ctre::character<'\x7F'>>(), subject.stack), subject.parameters}; } // class_named_graph template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_graph, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::char_range<'\x21','\x7E'>(), subject.stack), subject.parameters}; } // class_named_lower template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_lower, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::char_range<'a','z'>(), subject.stack), subject.parameters}; } // class_named_upper template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_upper, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::char_range<'A','Z'>(), subject.stack), subject.parameters}; } // class_named_print template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_print, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(ctre::char_range<'\x20','\x7E'>(), subject.stack), subject.parameters}; } // class_named_space template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_space, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(space_chars(), subject.stack), subject.parameters}; } // class_named_word template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_word, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(word_chars(), subject.stack), subject.parameters}; } // class_named_punct template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_punct, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(punct_chars(), subject.stack), subject.parameters}; } // class_named_xdigit template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::class_named_xdigit, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(xdigit_chars(), subject.stack), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__OPTIONS__HPP #define CTRE__ACTIONS__OPTIONS__HPP // empty option for alternate template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_empty, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(empty(), subject.stack), subject.parameters}; } // empty option for empty regex template <typename Parameters> static constexpr auto apply(pcre::push_empty, ctll::epsilon, pcre_context<ctll::list<>, Parameters> subject) { return pcre_context{ctll::push_front(empty(), subject.stack), subject.parameters}; } // make_alternate (A|B) template <auto V, typename A, typename B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<B, A, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(select<A,B>(), ctll::list<Ts...>()), subject.parameters}; } // make_alternate (As..)|B => (As..|B) template <auto V, typename A, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_alternate, ctll::term<V>, pcre_context<ctll::list<ctre::select<Bs...>, A, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(select<A,Bs...>(), ctll::list<Ts...>()), subject.parameters}; } // make_optional template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(optional<A>(), ctll::list<Ts...>()), subject.parameters}; } template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(optional<Content...>(), ctll::list<Ts...>()), subject.parameters}; } // make_lazy (optional) template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<optional<Subject...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(lazy_optional<Subject...>(), ctll::list<Ts...>()), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__REPEAT__HPP #define CTRE__ACTIONS__REPEAT__HPP // repeat 1..N template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_plus, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(plus<A>(), ctll::list<Ts...>()), subject.parameters}; } // repeat 1..N (sequence) template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_plus, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(plus<Content...>(), ctll::list<Ts...>()), subject.parameters}; } // repeat 0..N template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_star, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(star<A>(), ctll::list<Ts...>()), subject.parameters}; } // repeat 0..N (sequence) template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_star, ctll::term<V>, pcre_context<ctll::list<sequence<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(star<Content...>(), ctll::list<Ts...>()), subject.parameters}; } // create_number (seed) template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::create_number, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(number<static_cast<size_t>(V - '0')>(), subject.stack), subject.parameters}; } // push_number template <auto V, size_t N, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_number, ctll::term<V>, pcre_context<ctll::list<number<N>, Ts...>, Parameters> subject) { constexpr size_t previous = N * 10ull; return pcre_context{ctll::push_front(number<(previous + (V - '0'))>(), ctll::list<Ts...>()), subject.parameters}; } // repeat A..B template <auto V, typename Subject, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_ab, ctll::term<V>, pcre_context<ctll::list<number<B>, number<A>, Subject, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(repeat<A,B,Subject>(), ctll::list<Ts...>()), subject.parameters}; } // repeat A..B (sequence) template <auto V, typename... Content, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_ab, ctll::term<V>, pcre_context<ctll::list<number<B>, number<A>, sequence<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(repeat<A,B,Content...>(), ctll::list<Ts...>()), subject.parameters}; } // repeat_exactly template <auto V, typename Subject, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_exactly, ctll::term<V>, pcre_context<ctll::list<number<A>, Subject, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(repeat<A,A,Subject>(), ctll::list<Ts...>()), subject.parameters}; } // repeat_exactly A..B (sequence) template <auto V, typename... Content, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_exactly, ctll::term<V>, pcre_context<ctll::list<number<A>, sequence<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(repeat<A,A,Content...>(), ctll::list<Ts...>()), subject.parameters}; } // repeat_at_least (A+) template <auto V, typename Subject, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_at_least, ctll::term<V>, pcre_context<ctll::list<number<A>, Subject, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(repeat<A,0,Subject>(), ctll::list<Ts...>()), subject.parameters}; } // repeat_at_least (A+) (sequence) template <auto V, typename... Content, size_t A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::repeat_at_least, ctll::term<V>, pcre_context<ctll::list<number<A>, sequence<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(repeat<A,0,Content...>(), ctll::list<Ts...>()), subject.parameters}; } // make_lazy (plus) template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<plus<Subject...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(lazy_plus<Subject...>(), ctll::list<Ts...>()), subject.parameters}; } // make_lazy (star) template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<star<Subject...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(lazy_star<Subject...>(), ctll::list<Ts...>()), subject.parameters}; } // make_lazy (repeat<A,B>) template <auto V, typename... Subject, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<repeat<A,B,Subject...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(lazy_repeat<A,B,Subject...>(), ctll::list<Ts...>()), subject.parameters}; } // make_possessive (plus) template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_possessive, ctll::term<V>, pcre_context<ctll::list<plus<Subject...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(possessive_plus<Subject...>(), ctll::list<Ts...>()), subject.parameters}; } // make_possessive (star) template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_possessive, ctll::term<V>, pcre_context<ctll::list<star<Subject...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(possessive_star<Subject...>(), ctll::list<Ts...>()), subject.parameters}; } // make_possessive (repeat<A,B>) template <auto V, typename... Subject, size_t A, size_t B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_possessive, ctll::term<V>, pcre_context<ctll::list<repeat<A,B,Subject...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(possessive_repeat<A,B,Subject...>(), ctll::list<Ts...>()), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__SEQUENCE__HPP #define CTRE__ACTIONS__SEQUENCE__HPP // make_sequence template <auto V, typename A, typename B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<B,A,Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(sequence<A,B>(), ctll::list<Ts...>()), subject.parameters}; } // make_sequence (concat) template <auto V, typename... As, typename B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<As...>,B,Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(sequence<B,As...>(), ctll::list<Ts...>()), subject.parameters}; } // make_sequence (make string) template <auto V, auto A, auto B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<character<B>,character<A>,Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(string<A,B>(), ctll::list<Ts...>()), subject.parameters}; } // make_sequence (concat string) template <auto V, auto... As, auto B, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<string<As...>,character<B>,Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(string<B,As...>(), ctll::list<Ts...>()), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__SET__HPP #define CTRE__ACTIONS__SET__HPP // UTILITY // add into set if not exists template <template <typename...> typename SetType, typename T, typename... As, bool Exists = (std::is_same_v<T, As> || ... || false)> static constexpr auto push_back_into_set(T, SetType<As...>) -> ctll::conditional<Exists, SetType<As...>, SetType<As...,T>> { return {}; } //template <template <typename...> typename SetType, typename A, typename BHead, typename... Bs> struct set_merge_helper { // using step = decltype(push_back_into_set<SetType>(BHead(), A())); // using type = ctll::conditional<(sizeof...(Bs) > 0), set_merge_helper<SetType, step, Bs...>, step>; //}; // //// add set into set if not exists //template <template <typename...> typename SetType, typename... As, typename... Bs> static constexpr auto push_back_into_set(SetType<As...>, SetType<Bs...>) -> typename set_merge_helper<SetType, SetType<As...>, Bs...>::type { return pcre_context{{};), subject.parameters}} // //template <template <typename...> typename SetType, typename... As> static constexpr auto push_back_into_set(SetType<As...>, SetType<>) -> SetType<As...> { return pcre_context{{};), subject.parameters}} // END OF UTILITY // set_start template <auto V, typename A,typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_start, ctll::term<V>, pcre_context<ctll::list<A,Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(set<A>(), ctll::list<Ts...>()), subject.parameters}; } // set_make template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_make, ctll::term<V>, pcre_context<ctll::list<set<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(set<Content...>(), ctll::list<Ts...>()), subject.parameters}; } // set_make_negative template <auto V, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_make_negative, ctll::term<V>, pcre_context<ctll::list<set<Content...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(negative_set<Content...>(), ctll::list<Ts...>()), subject.parameters}; } // set{A...} + B = set{A,B} template <auto V, typename A, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<A,set<Content...>,Ts...>, Parameters> subject) { auto new_set = push_back_into_set<set>(A(), set<Content...>()); return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters}; } // TODO checkme //// set{A...} + set{B...} = set{A...,B...} //template <auto V, typename... As, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<set<As...>,set<Bs...>,Ts...>, Parameters> subject) { // auto new_set = push_back_into_set<set>(set<As...>(), set<Bs...>()); // return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters}; //} // negative_set{A...} + B = negative_set{A,B} template <auto V, typename A, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<A,negative_set<Content...>,Ts...>, Parameters> subject) { auto new_set = push_back_into_set<set>(A(), set<Content...>()); return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters}; } // TODO checkme //// negative_set{A...} + negative_set{B...} = negative_set{A...,B...} //template <auto V, typename... As, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_combine, ctll::term<V>, pcre_context<ctll::list<negative_set<As...>,negative_set<Bs...>,Ts...>, Parameters> subject) { // auto new_set = push_back_into_set<negative_set>(negative_set<As...>(), negative_set<Bs...>()); // return pcre_context{ctll::push_front(new_set, ctll::list<Ts...>()), subject.parameters}; //} // negate_class_named: [[^:digit:]] = [^[:digit:]] template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::negate_class_named, ctll::term<V>, pcre_context<ctll::list<A, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(negate<A>(), ctll::list<Ts...>()), subject.parameters}; } // add range to set template <auto V, auto B, auto A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_range, ctll::term<V>, pcre_context<ctll::list<character<B>,character<A>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(char_range<A,B>(), ctll::list<Ts...>()), subject.parameters}; } #endif #ifndef CTRE__ACTIONS__PROPERTIES__HPP #define CTRE__ACTIONS__PROPERTIES__HPP // push_property_name template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_name, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(property_name<V>(), subject.stack), subject.parameters}; } // push_property_name (concat) template <auto... Str, auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_name, ctll::term<V>, pcre_context<ctll::list<property_name<Str...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(property_name<Str..., V>(), ctll::list<Ts...>()), subject.parameters}; } // push_property_value template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_value, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(property_value<V>(), subject.stack), subject.parameters}; } // push_property_value (concat) template <auto... Str, auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_property_value, ctll::term<V>, pcre_context<ctll::list<property_value<Str...>, Ts...>, Parameters> subject) { return pcre_context{ctll::push_front(property_value<Str..., V>(), ctll::list<Ts...>()), subject.parameters}; } // make_property template <auto V, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_name<Name...>, Ts...>, Parameters> subject) { return ctll::reject{}; //constexpr std::array<char, sizeof...(Name)> name{static_cast<char>(Name)...}; //constexpr auto p = uni::__binary_prop_from_string(get_string_view(name)); // //if constexpr (p == uni::__binary_prop::unknown) { // return ctll::reject{}; //} else { // return pcre_context{ctll::push_front(binary_property<p>(), ctll::list<Ts...>()), subject.parameters}; //} } // make_property template <auto V, auto... Value, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_value<Value...>, property_name<Name...>, Ts...>, Parameters> subject) { return ctll::reject{}; //constexpr auto prop = property_builder<Name...>::template get<Value...>(); // //if constexpr (std::is_same_v<decltype(prop), ctll::reject>) { // return ctll::reject{}; //} else { // return pcre_context{ctll::push_front(prop, ctll::list<Ts...>()), subject.parameters}; //} } // make_property_negative template <auto V, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property_negative, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_name<Name...>, Ts...>, Parameters> subject) { return ctll::reject{}; //constexpr std::array<char, sizeof...(Name)> name{static_cast<char>(Name)...}; //constexpr auto p = uni::__binary_prop_from_string(get_string_view(name)); // //if constexpr (p == uni::__binary_prop::unknown) { // return ctll::reject{}; //} else { // return pcre_context{ctll::push_front(negate<binary_property<p>>(), ctll::list<Ts...>()), subject.parameters}; //} } // make_property_negative template <auto V, auto... Value, auto... Name, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_property_negative, ctll::term<V>, [[maybe_unused]] pcre_context<ctll::list<property_value<Value...>, property_name<Name...>, Ts...>, Parameters> subject) { return ctll::reject{}; //constexpr auto prop = property_builder<Name...>::template get<Value...>(); // //if constexpr (std::is_same_v<decltype(prop), ctll::reject>) { // return ctll::reject{}; //} else { // return pcre_context{ctll::push_front(negate<decltype(prop)>(), ctll::list<Ts...>()), subject.parameters}; //} } #endif }; } #endif #ifndef CTRE__EVALUATION__HPP #define CTRE__EVALUATION__HPP #ifndef CTRE__STARTS_WITH_ANCHOR__HPP #define CTRE__STARTS_WITH_ANCHOR__HPP namespace ctre { template <typename... Content> constexpr bool starts_with_anchor(ctll::list<Content...>) noexcept { return false; } template <typename... Content> constexpr bool starts_with_anchor(ctll::list<assert_begin, Content...>) noexcept { // yes! start anchor is here return true; } template <typename... Options, typename... Content> constexpr bool starts_with_anchor(ctll::list<select<Options...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return (starts_with_anchor(ctll::list<Options, Content...>{}) && ... && true); } template <typename... Optional, typename... Content> constexpr bool starts_with_anchor(ctll::list<optional<Optional...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Optional..., Content...>{}) && starts_with_anchor(ctll::list<Content...>{}); } template <typename... Optional, typename... Content> constexpr bool starts_with_anchor(ctll::list<lazy_optional<Optional...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Optional..., Content...>{}) && starts_with_anchor(ctll::list<Content...>{}); } template <typename... Seq, typename... Content> constexpr bool starts_with_anchor(ctll::list<sequence<Seq...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Seq..., Content...>{}); } template <size_t A, size_t B, typename... Seq, typename... Content> constexpr bool starts_with_anchor(ctll::list<repeat<A, B, Seq...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Seq..., Content...>{}); } template <size_t A, size_t B, typename... Seq, typename... Content> constexpr bool starts_with_anchor(ctll::list<lazy_repeat<A, B, Seq...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Seq..., Content...>{}); } template <size_t A, size_t B, typename... Seq, typename... Content> constexpr bool starts_with_anchor(ctll::list<possessive_repeat<A, B, Seq...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Seq..., Content...>{}); } template <size_t Index, typename... Seq, typename... Content> constexpr bool starts_with_anchor(ctll::list<capture<Index, Seq...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Seq..., Content...>{}); } template <size_t Index, typename... Seq, typename... Content> constexpr bool starts_with_anchor(ctll::list<capture_with_name<Index, Seq...>, Content...>) noexcept { // check if all options starts with anchor or if they are empty, there is an anchor behind them return starts_with_anchor(ctll::list<Seq..., Content...>{}); } } #endif #ifndef CTRE__RETURN_TYPE__HPP #define CTRE__RETURN_TYPE__HPP #include <type_traits> #include <tuple> #include <string_view> #include <string> namespace ctre { struct not_matched_tag_t { }; static constexpr inline auto not_matched = not_matched_tag_t{}; template <size_t Id, typename Name = void> struct captured_content { template <typename Iterator> class storage { Iterator _begin{}; Iterator _end{}; bool _matched{false}; public: using char_type = typename std::iterator_traits<Iterator>::value_type; using name = Name; constexpr CTRE_FORCE_INLINE storage() noexcept {} constexpr CTRE_FORCE_INLINE void matched() noexcept { _matched = true; } constexpr CTRE_FORCE_INLINE void unmatch() noexcept { _matched = false; } constexpr CTRE_FORCE_INLINE void set_start(Iterator pos) noexcept { _begin = pos; } constexpr CTRE_FORCE_INLINE storage & set_end(Iterator pos) noexcept { _end = pos; return *this; } constexpr CTRE_FORCE_INLINE Iterator get_end() const noexcept { return _end; } constexpr auto begin() const noexcept { return _begin; } constexpr auto end() const noexcept { return _end; } constexpr CTRE_FORCE_INLINE operator bool() const noexcept { return _matched; } constexpr CTRE_FORCE_INLINE const auto * data() const noexcept { return &*_begin; } constexpr CTRE_FORCE_INLINE auto size() const noexcept { return static_cast<size_t>(std::distance(_begin, _end)); } constexpr CTRE_FORCE_INLINE auto to_view() const noexcept { return std::basic_string_view<char_type>(&*_begin, static_cast<size_t>(std::distance(_begin, _end))); } constexpr CTRE_FORCE_INLINE auto to_string() const noexcept { return std::basic_string<char_type>(begin(), end()); } constexpr CTRE_FORCE_INLINE auto view() const noexcept { return std::basic_string_view<char_type>(&*_begin, static_cast<size_t>(std::distance(_begin, _end))); } constexpr CTRE_FORCE_INLINE auto str() const noexcept { return std::basic_string<char_type>(begin(), end()); } constexpr CTRE_FORCE_INLINE operator std::basic_string_view<char_type>() const noexcept { return to_view(); } constexpr CTRE_FORCE_INLINE explicit operator std::basic_string<char_type>() const noexcept { return to_string(); } constexpr CTRE_FORCE_INLINE static size_t get_id() noexcept { return Id; } friend CTRE_FORCE_INLINE constexpr bool operator==(const storage & lhs, std::basic_string_view<char_type> rhs) noexcept { return bool(lhs) ? lhs.view() == rhs : false; } friend CTRE_FORCE_INLINE constexpr bool operator!=(const storage & lhs, std::basic_string_view<char_type> rhs) noexcept { return bool(lhs) ? lhs.view() != rhs : false; } friend CTRE_FORCE_INLINE constexpr bool operator==(std::basic_string_view<char_type> lhs, const storage & rhs) noexcept { return bool(rhs) ? lhs == rhs.view() : false; } friend CTRE_FORCE_INLINE constexpr bool operator!=(std::basic_string_view<char_type> lhs, const storage & rhs) noexcept { return bool(rhs) ? lhs != rhs.view() : false; } }; }; struct capture_not_exists_tag { }; static constexpr inline auto capture_not_exists = capture_not_exists_tag{}; template <typename... Captures> struct captures; template <typename Head, typename... Tail> struct captures<Head, Tail...>: captures<Tail...> { Head head{}; constexpr CTRE_FORCE_INLINE captures() noexcept { } template <size_t id> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { if constexpr (id == Head::get_id()) { return true; } else { return captures<Tail...>::template exists<id>(); } } template <typename Name> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { if constexpr (std::is_same_v<Name, typename Head::name>) { return true; } else { return captures<Tail...>::template exists<Name>(); } } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string Name> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { #else template <const auto & Name> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { #endif if constexpr (std::is_same_v<typename Head::name, void>) { return captures<Tail...>::template exists<Name>(); } else { if constexpr (Head::name::name.is_same_as(Name)) { return true; } else { return captures<Tail...>::template exists<Name>(); } } } template <size_t id> CTRE_FORCE_INLINE constexpr auto & select() noexcept { if constexpr (id == Head::get_id()) { return head; } else { return captures<Tail...>::template select<id>(); } } template <typename Name> CTRE_FORCE_INLINE constexpr auto & select() noexcept { if constexpr (std::is_same_v<Name, typename Head::name>) { return head; } else { return captures<Tail...>::template select<Name>(); } } template <size_t id> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { if constexpr (id == Head::get_id()) { return head; } else { return captures<Tail...>::template select<id>(); } } template <typename Name> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { if constexpr (std::is_same_v<Name, typename Head::name>) { return head; } else { return captures<Tail...>::template select<Name>(); } } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string Name> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { #else template <const auto & Name> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { #endif if constexpr (std::is_same_v<typename Head::name, void>) { return captures<Tail...>::template select<Name>(); } else { if constexpr (Head::name::name.is_same_as(Name)) { return head; } else { return captures<Tail...>::template select<Name>(); } } } }; template <> struct captures<> { constexpr CTRE_FORCE_INLINE captures() noexcept { } template <size_t> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { return false; } template <typename> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { return false; } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { #else template <const auto &> CTRE_FORCE_INLINE static constexpr bool exists() noexcept { #endif return false; } template <size_t> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { return capture_not_exists; } template <typename> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { return capture_not_exists; } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { #else template <const auto &> CTRE_FORCE_INLINE constexpr auto & select() const noexcept { #endif return capture_not_exists; } }; template <typename Iterator, typename... Captures> class regex_results { captures<captured_content<0>::template storage<Iterator>, typename Captures::template storage<Iterator>...> _captures{}; public: using char_type = typename std::iterator_traits<Iterator>::value_type; constexpr CTRE_FORCE_INLINE regex_results() noexcept { } constexpr CTRE_FORCE_INLINE regex_results(not_matched_tag_t) noexcept { } // special constructor for deducting constexpr CTRE_FORCE_INLINE regex_results(Iterator, ctll::list<Captures...>) noexcept { } template <size_t Id, typename = std::enable_if_t<decltype(_captures)::template exists<Id>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept { return _captures.template select<Id>(); } template <typename Name, typename = std::enable_if_t<decltype(_captures)::template exists<Name>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept { return _captures.template select<Name>(); } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string Name, typename = std::enable_if_t<decltype(_captures)::template exists<Name>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept { #else template <const auto & Name, typename = std::enable_if_t<decltype(_captures)::template exists<Name>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept { #endif return _captures.template select<Name>(); } static constexpr size_t count() noexcept { return sizeof...(Captures) + 1; } constexpr CTRE_FORCE_INLINE regex_results & matched() noexcept { _captures.template select<0>().matched(); return *this; } constexpr CTRE_FORCE_INLINE regex_results & unmatch() noexcept { _captures.template select<0>().unmatch(); return *this; } constexpr CTRE_FORCE_INLINE operator bool() const noexcept { return bool(_captures.template select<0>()); } constexpr CTRE_FORCE_INLINE operator std::basic_string_view<char_type>() const noexcept { return to_view(); } constexpr CTRE_FORCE_INLINE explicit operator std::basic_string<char_type>() const noexcept { return to_string(); } constexpr CTRE_FORCE_INLINE auto to_view() const noexcept { return _captures.template select<0>().to_view(); } constexpr CTRE_FORCE_INLINE auto to_string() const noexcept { return _captures.template select<0>().to_string(); } constexpr CTRE_FORCE_INLINE auto view() const noexcept { return _captures.template select<0>().view(); } constexpr CTRE_FORCE_INLINE auto str() const noexcept { return _captures.template select<0>().to_string(); } constexpr CTRE_FORCE_INLINE size_t size() const noexcept { return _captures.template select<0>().size(); } constexpr CTRE_FORCE_INLINE const auto * data() const noexcept { return _captures.template select<0>().data(); } constexpr CTRE_FORCE_INLINE regex_results & set_start_mark(Iterator pos) noexcept { _captures.template select<0>().set_start(pos); return *this; } constexpr CTRE_FORCE_INLINE regex_results & set_end_mark(Iterator pos) noexcept { _captures.template select<0>().set_end(pos); return *this; } constexpr CTRE_FORCE_INLINE Iterator get_end_position() const noexcept { return _captures.template select<0>().get_end(); } template <size_t Id> CTRE_FORCE_INLINE constexpr regex_results & start_capture(Iterator pos) noexcept { _captures.template select<Id>().set_start(pos); return *this; } template <size_t Id> CTRE_FORCE_INLINE constexpr regex_results & end_capture(Iterator pos) noexcept { _captures.template select<Id>().set_end(pos).matched(); return *this; } friend CTRE_FORCE_INLINE constexpr bool operator==(const regex_results & lhs, std::basic_string_view<char_type> rhs) noexcept { return bool(lhs) ? lhs.view() == rhs : false; } friend CTRE_FORCE_INLINE constexpr bool operator!=(const regex_results & lhs, std::basic_string_view<char_type> rhs) noexcept { return bool(lhs) ? lhs.view() != rhs : true; } friend CTRE_FORCE_INLINE constexpr bool operator==(std::basic_string_view<char_type> lhs, const regex_results & rhs) noexcept { return bool(rhs) ? lhs == rhs.view() : false; } friend CTRE_FORCE_INLINE constexpr bool operator!=(std::basic_string_view<char_type> lhs, const regex_results & rhs) noexcept { return bool(rhs) ? lhs != rhs.view() : true; } }; template <typename Iterator, typename... Captures> regex_results(Iterator, ctll::list<Captures...>) -> regex_results<Iterator, Captures...>; } // support for structured bindings #ifndef __EDG__ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmismatched-tags" #endif namespace std { template <typename... Captures> struct tuple_size<ctre::regex_results<Captures...>> : public std::integral_constant<size_t, ctre::regex_results<Captures...>::count()> { }; template <size_t N, typename... Captures> struct tuple_element<N, ctre::regex_results<Captures...>> { public: using type = decltype( std::declval<const ctre::regex_results<Captures...> &>().template get<N>() ); }; } #ifdef __clang__ #pragma clang diagnostic pop #endif #endif #endif #ifndef CTRE__FIND_CAPTURES__HPP #define CTRE__FIND_CAPTURES__HPP namespace ctre { template <typename Pattern> constexpr auto find_captures(Pattern) noexcept { return find_captures(ctll::list<Pattern>(), ctll::list<>()); } template <typename... Output> constexpr auto find_captures(ctll::list<>, ctll::list<Output...> output) noexcept { return output; } template <auto... String, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<string<String...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Tail...>(), output); } template <typename... Options, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<select<Options...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Options..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<optional<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_optional<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<sequence<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<empty, Tail...>, Output output) noexcept { return find_captures(ctll::list<Tail...>(), output); } template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<assert_begin, Tail...>, Output output) noexcept { return find_captures(ctll::list<Tail...>(), output); } template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<assert_end, Tail...>, Output output) noexcept { return find_captures(ctll::list<Tail...>(), output); } // , typename = std::enable_if_t<(MatchesCharacter<CharacterLike>::template value<char>) template <typename CharacterLike, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<CharacterLike, Tail...>, Output output) noexcept { return find_captures(ctll::list<Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<plus<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<star<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <size_t A, size_t B, typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<repeat<A,B,Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_plus<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_star<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <size_t A, size_t B, typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lazy_repeat<A,B,Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<possessive_plus<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<possessive_star<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <size_t A, size_t B, typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<possessive_repeat<A,B,Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lookahead_positive<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <typename... Content, typename... Tail, typename Output> constexpr auto find_captures(ctll::list<lookahead_negative<Content...>, Tail...>, Output output) noexcept { return find_captures(ctll::list<Content..., Tail...>(), output); } template <size_t Id, typename... Content, typename... Tail, typename... Output> constexpr auto find_captures(ctll::list<capture<Id,Content...>, Tail...>, ctll::list<Output...>) noexcept { return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id>>()); } template <size_t Id, typename Name, typename... Content, typename... Tail, typename... Output> constexpr auto find_captures(ctll::list<capture_with_name<Id,Name,Content...>, Tail...>, ctll::list<Output...>) noexcept { return find_captures(ctll::list<Content..., Tail...>(), ctll::list<Output..., captured_content<Id, Name>>()); } } #endif #ifndef CTRE__FIRST__HPP #define CTRE__FIRST__HPP namespace ctre { struct can_be_anything {}; template <typename... Content> constexpr auto first(ctll::list<Content...> l, ctll::list<>) noexcept { return l; } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<accept, Tail...>) noexcept { return l; } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<end_mark, Tail...>) noexcept { return l; } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<end_cycle_mark, Tail...>) noexcept { return l; } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<end_lookahead_mark, Tail...>) noexcept { return l; } template <typename... Content, size_t Id, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<numeric_mark<Id>, Tail...>) noexcept { return first(l, ctll::list<Tail...>{}); } // empty template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<empty, Tail...>) noexcept { return first(l, ctll::list<Tail...>{}); } // asserts template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<assert_begin, Tail...>) noexcept { return first(l, ctll::list<Tail...>{}); } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<assert_end, Tail...>) noexcept { return l; } // sequence template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<sequence<Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } // plus template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<plus<Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } // lazy_plus template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_plus<Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } // possessive_plus template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_plus<Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } // star template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<star<Seq...>, Tail...>) noexcept { return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{}); } // lazy_star template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_star<Seq...>, Tail...>) noexcept { return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{}); } // possessive_star template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_star<Seq...>, Tail...>) noexcept { return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{}); } // lazy_repeat template <typename... Content, size_t A, size_t B, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_repeat<A, B, Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } template <typename... Content, size_t B, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_repeat<0, B, Seq...>, Tail...>) noexcept { return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{}); } // possessive_repeat template <typename... Content, size_t A, size_t B, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_repeat<A, B, Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } template <typename... Content, size_t B, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<possessive_repeat<0, B, Seq...>, Tail...>) noexcept { return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{}); } // repeat template <typename... Content, size_t A, size_t B, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<repeat<A, B, Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } template <typename... Content, size_t B, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<repeat<0, B, Seq...>, Tail...>) noexcept { return first(first(l, ctll::list<Tail...>{}), ctll::list<Seq..., Tail...>{}); } // lookahead_positive template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<lookahead_positive<Seq...>, Tail...>) noexcept { return ctll::list<can_be_anything>{}; } // lookahead_negative TODO fixme template <typename... Content, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<lookahead_negative<Seq...>, Tail...>) noexcept { return ctll::list<can_be_anything>{}; } // capture template <typename... Content, size_t Id, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<capture<Id, Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } template <typename... Content, size_t Id, typename Name, typename... Seq, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<capture_with_name<Id, Name, Seq...>, Tail...>) noexcept { return first(l, ctll::list<Seq..., Tail...>{}); } // backreference template <typename... Content, size_t Id, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<back_reference<Id>, Tail...>) noexcept { return ctll::list<can_be_anything>{}; } template <typename... Content, typename Name, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<back_reference_with_name<Name>, Tail...>) noexcept { return ctll::list<can_be_anything>{}; } // string First extraction template <typename... Content, auto First, auto... String, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<string<First, String...>, Tail...>) noexcept { return ctll::list<Content..., character<First>>{}; } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<string<>, Tail...>) noexcept { return first(l, ctll::list<Tail...>{}); } // optional template <typename... Content, typename... Opt, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<optional<Opt...>, Tail...>) noexcept { return first(first(l, ctll::list<Opt..., Tail...>{}), ctll::list<Tail...>{}); } template <typename... Content, typename... Opt, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<lazy_optional<Opt...>, Tail...>) noexcept { return first(first(l, ctll::list<Opt..., Tail...>{}), ctll::list<Tail...>{}); } // select (alternation) template <typename... Content, typename SHead, typename... STail, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<select<SHead, STail...>, Tail...>) noexcept { return first(first(l, ctll::list<SHead, Tail...>{}), ctll::list<select<STail...>, Tail...>{}); } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...> l, ctll::list<select<>, Tail...>) noexcept { return l; } // characters / sets template <typename... Content, auto V, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<character<V>, Tail...>) noexcept { return ctll::list<Content..., character<V>>{}; } template <typename... Content, auto... Values, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<enumeration<Values...>, Tail...>) noexcept { return ctll::list<Content..., character<Values>...>{}; } template <typename... Content, typename... SetContent, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<set<SetContent...>, Tail...>) noexcept { return ctll::list<Content..., SetContent...>{}; } template <typename... Content, auto A, auto B, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<char_range<A,B>, Tail...>) noexcept { return ctll::list<Content..., char_range<A,B>>{}; } template <typename... Content, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<any, Tail...>) noexcept { return ctll::list<can_be_anything>{}; } // negative template <typename... Content, typename... SetContent, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<negate<SetContent...>, Tail...>) noexcept { return ctll::list<Content..., negative_set<SetContent...>>{}; } template <typename... Content, typename... SetContent, typename... Tail> constexpr auto first(ctll::list<Content...>, ctll::list<negative_set<SetContent...>, Tail...>) noexcept { return ctll::list<Content..., negative_set<SetContent...>>{}; } // user facing interface template <typename... Content> constexpr auto calculate_first(Content...) noexcept { return first(ctll::list<>{}, ctll::list<Content...>{}); } // calculate mutual exclusivity template <typename... Content> constexpr size_t calculate_size_of_first(ctre::negative_set<Content...>) { return 1 + 1 * sizeof...(Content); } template <auto... V> constexpr size_t calculate_size_of_first(ctre::enumeration<V...>) { return sizeof...(V); } constexpr size_t calculate_size_of_first(...) { return 1; } template <typename... Content> constexpr size_t calculate_size_of_first(ctll::list<Content...>) { return (calculate_size_of_first(Content{}) + ... + 0); } template <typename... Content> constexpr size_t calculate_size_of_first(ctre::set<Content...>) { return (calculate_size_of_first(Content{}) + ... + 0); } template <auto A, typename CB> constexpr int64_t negative_helper(ctre::character<A>, CB & cb, int64_t start) { if (A != std::numeric_limits<int64_t>::min()) { if (start < A) { cb(start, A-1); } } if (A != std::numeric_limits<int64_t>::max()) { return A+1; } else { return A; } } template <auto A, auto B, typename CB> constexpr int64_t negative_helper(ctre::char_range<A,B>, CB & cb, int64_t start) { if (A != std::numeric_limits<int64_t>::min()) { if (start < A) { cb(start, A-1); } } if (B != std::numeric_limits<int64_t>::max()) { return B+1; } else { return B; } } template <auto Head, auto... Tail, typename CB> constexpr int64_t negative_helper(ctre::enumeration<Head, Tail...>, CB & cb, int64_t start) { int64_t nstart = negative_helper(ctre::character<Head>{}, cb, start); return negative_helper(ctre::enumeration<Tail...>{}, cb, nstart); } template <typename CB> constexpr int64_t negative_helper(ctre::enumeration<>, CB &, int64_t start) { return start; } template <typename CB> constexpr int64_t negative_helper(ctre::set<>, CB &, int64_t start) { return start; } template <typename Head, typename... Rest, typename CB> constexpr int64_t negative_helper(ctre::set<Head, Rest...>, CB & cb, int64_t start) { start = negative_helper(Head{}, cb, start); return negative_helper(ctre::set<Rest...>{}, cb, start); } template <typename Head, typename... Rest, typename CB> constexpr void negative_helper(ctre::negative_set<Head, Rest...>, CB && cb, int64_t start = std::numeric_limits<int64_t>::min()) { start = negative_helper(Head{}, cb, start); negative_helper(ctre::negative_set<Rest...>{}, std::forward<CB>(cb), start); } template <typename CB> constexpr void negative_helper(ctre::negative_set<>, CB && cb, int64_t start = std::numeric_limits<int64_t>::min()) { if (start < std::numeric_limits<int64_t>::max()) { cb(start, std::numeric_limits<int64_t>::max()); } } // simple fixed set // TODO: this needs some optimizations template <size_t Capacity> class point_set { struct point { int64_t low{}; int64_t high{}; constexpr bool operator<(const point & rhs) const { return low < rhs.low; } constexpr point() { } constexpr point(int64_t l, int64_t h): low{l}, high{h} { } }; point points[Capacity+1]{}; size_t used{0}; constexpr point * begin() { return points; } constexpr point * begin() const { return points; } constexpr point * end() { return points + used; } constexpr point * end() const { return points + used; } constexpr point * lower_bound(point obj) { auto first = begin(); auto last = end(); auto it = first; size_t count = std::distance(first, last); while (count > 0) { it = first; size_t step = count / 2; std::advance(it, step); if (*it < obj) { first = ++it; count -= step + 1; } else { count = step; } } return it; } constexpr point * insert_point(int64_t position, int64_t other) { point obj{position, other}; auto it = lower_bound(obj); if (it == end()) { *it = obj; used++; return it; } else { auto out = it; auto e = end(); while (it != e) { auto tmp = *it; *it = obj; obj = tmp; //std::swap(*it, obj); it++; } auto tmp = *it; *it = obj; obj = tmp; //std::swap(*it, obj); used++; return out; } } public: constexpr point_set() { } constexpr void insert(int64_t low, int64_t high) { insert_point(low, high); //insert_point(high, low); } constexpr bool check(int64_t low, int64_t high) { for (auto r: *this) { if (r.low <= low && low <= r.high) { return true; } else if (r.low <= high && high <= r.high) { return true; } else if (low <= r.low && r.low <= high) { return true; } else if (low <= r.high && r.high <= high) { return true; } } return false; } template <auto V> constexpr bool check(ctre::character<V>) { return check(V,V); } template <auto A, auto B> constexpr bool check(ctre::char_range<A,B>) { return check(A,B); } constexpr bool check(can_be_anything) { return used > 0; } template <typename... Content> constexpr bool check(ctre::negative_set<Content...> nset) { bool collision = false; negative_helper(nset, [&](int64_t low, int64_t high){ collision |= this->check(low, high); }); return collision; } template <auto... V> constexpr bool check(ctre::enumeration<V...>) { return (check(V,V) || ... || false); } template <typename... Content> constexpr bool check(ctll::list<Content...>) { return (check(Content{}) || ... || false); } template <typename... Content> constexpr bool check(ctre::set<Content...>) { return (check(Content{}) || ... || false); } template <auto V> constexpr void populate(ctre::character<V>) { insert(V,V); } template <auto A, auto B> constexpr void populate(ctre::char_range<A,B>) { insert(A,B); } constexpr void populate(can_be_anything) { insert(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max()); } template <typename... Content> constexpr void populate(ctre::negative_set<Content...> nset) { negative_helper(nset, [&](int64_t low, int64_t high){ this->insert(low, high); }); } template <typename... Content> constexpr void populate(ctre::set<Content...>) { (populate(Content{}), ...); } template <typename... Content> constexpr void populate(ctll::list<Content...>) { (populate(Content{}), ...); } }; template <typename... A, typename... B> constexpr bool collides(ctll::list<A...> rhs, ctll::list<B...> lhs) { constexpr size_t capacity = calculate_size_of_first(rhs); point_set<capacity> set; set.populate(rhs); return set.check(lhs); } } #endif // remove me when MSVC fix the constexpr bug #ifdef _MSC_VER #ifndef CTRE_MSVC_GREEDY_WORKAROUND #define CTRE_MSVC_GREEDY_WORKAROUND #endif #endif namespace ctre { template <size_t Limit> constexpr CTRE_FORCE_INLINE bool less_than_or_infinite(size_t i) { if constexpr (Limit == 0) { // infinite return true; } else { return i < Limit; } } template <size_t Limit> constexpr CTRE_FORCE_INLINE bool less_than(size_t i) { if constexpr (Limit == 0) { // infinite return false; } else { return i < Limit; } } // calling with pattern prepare stack and triplet of iterators template <typename Iterator, typename EndIterator, typename Pattern> constexpr inline auto match_re(const Iterator begin, const EndIterator end, Pattern pattern) noexcept { using return_type = decltype(regex_results(std::declval<Iterator>(), find_captures(pattern))); return evaluate(begin, begin, end, return_type{}, ctll::list<start_mark, Pattern, assert_end, end_mark, accept>()); } template <typename Iterator, typename EndIterator, typename Pattern> constexpr inline auto starts_with_re(const Iterator begin, const EndIterator end, Pattern pattern) noexcept { using return_type = decltype(regex_results(std::declval<Iterator>(), find_captures(pattern))); return evaluate(begin, begin, end, return_type{}, ctll::list<start_mark, Pattern, end_mark, accept>()); } template <typename Iterator, typename EndIterator, typename Pattern> constexpr inline auto search_re(const Iterator begin, const EndIterator end, Pattern pattern) noexcept { using return_type = decltype(regex_results(std::declval<Iterator>(), find_captures(pattern))); constexpr bool fixed = starts_with_anchor(ctll::list<Pattern>{}); auto it = begin; for (; end != it && !fixed; ++it) { if (auto out = evaluate(begin, it, end, return_type{}, ctll::list<start_mark, Pattern, end_mark, accept>())) { return out; } } // in case the RE is empty or fixed return evaluate(begin, it, end, return_type{}, ctll::list<start_mark, Pattern, end_mark, accept>()); } // sink for making the errors shorter template <typename R, typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterator, R, ...) noexcept { return R{}; } // if we found "accept" object on stack => ACCEPT template <typename R, typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterator, R captures, ctll::list<accept>) noexcept { return captures.matched(); } // if we found "reject" object on stack => REJECT template <typename R, typename... Rest, typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterator, R, ctll::list<reject, Rest...>) noexcept { return R{}; // just return not matched return type } // mark start of outer capture template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<start_mark, Tail...>) noexcept { return evaluate(begin, current, end, captures.set_start_mark(current), ctll::list<Tail...>()); } // mark end of outer capture template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<end_mark, Tail...>) noexcept { return evaluate(begin, current, end, captures.set_end_mark(current), ctll::list<Tail...>()); } // mark end of cycle template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator current, const EndIterator, R captures, ctll::list<end_cycle_mark>) noexcept { return captures.set_end_mark(current).matched(); } // matching everything which behave as a one character matcher template <typename R, typename Iterator, typename EndIterator, typename CharacterLike, typename... Tail, typename = std::enable_if_t<(MatchesCharacter<CharacterLike>::template value<decltype(*std::declval<Iterator>())>)>> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<CharacterLike, Tail...>) noexcept { if (end == current) return not_matched; if (!CharacterLike::match_char(*current)) return not_matched; return evaluate(begin, current+1, end, captures, ctll::list<Tail...>()); } // matching strings in patterns template <typename Iterator> struct string_match_result { Iterator current; bool match; }; template <auto Head, auto... String, typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE string_match_result<Iterator> evaluate_match_string(Iterator current, const EndIterator end) noexcept { if ((end != current) && (Head == *current)) { if constexpr (sizeof...(String) > 0) { return evaluate_match_string<String...>(++current, end); } else { return {++current, true}; } } else { return {current, false}; // not needed but will optimize } } template <typename R, typename Iterator, typename EndIterator, auto... String, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<string<String...>, Tail...>) noexcept { if constexpr (sizeof...(String) == 0) { return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } else if (auto tmp = evaluate_match_string<String...>(current, end); tmp.match) { return evaluate(begin, tmp.current, end, captures, ctll::list<Tail...>()); } else { return not_matched; } } // matching select in patterns template <typename R, typename Iterator, typename EndIterator, typename HeadOptions, typename... TailOptions, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<select<HeadOptions, TailOptions...>, Tail...>) noexcept { if (auto r = evaluate(begin, current, end, captures, ctll::list<HeadOptions, Tail...>())) { return r; } else { return evaluate(begin, current, end, captures, ctll::list<select<TailOptions...>, Tail...>()); } } template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterator, R, ctll::list<select<>, Tail...>) noexcept { // no previous option was matched => REJECT return not_matched; } // matching optional in patterns template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<optional<Content...>, Tail...>) noexcept { if (auto r1 = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, Tail...>())) { return r1; } else if (auto r2 = evaluate(begin, current, end, captures, ctll::list<Tail...>())) { return r2; } else { return not_matched; } } // lazy optional template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<lazy_optional<Content...>, Tail...>) noexcept { if (auto r1 = evaluate(begin, current, end, captures, ctll::list<Tail...>())) { return r1; } else if (auto r2 = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, Tail...>())) { return r2; } else { return not_matched; } } // matching sequence in patterns template <typename R, typename Iterator, typename EndIterator, typename HeadContent, typename... TailContent, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<sequence<HeadContent, TailContent...>, Tail...>) noexcept { if constexpr (sizeof...(TailContent) > 0) { return evaluate(begin, current, end, captures, ctll::list<HeadContent, sequence<TailContent...>, Tail...>()); } else { return evaluate(begin, current, end, captures, ctll::list<HeadContent, Tail...>()); } } // matching empty in patterns template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<empty, Tail...>) noexcept { return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } // matching asserts template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<assert_begin, Tail...>) noexcept { if (begin != current) { return not_matched; } return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<assert_end, Tail...>) noexcept { if (end != current) { return not_matched; } return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } // lazy repeat template <typename R, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<lazy_repeat<A,B,Content...>, Tail...>) noexcept { // A..B size_t i{0}; for (; less_than<A>(i); ++i) { if (auto outer_result = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, end_cycle_mark>())) { captures = outer_result.unmatch(); current = outer_result.get_end_position(); } else { return not_matched; } } if (auto outer_result = evaluate(begin, current, end, captures, ctll::list<Tail...>())) { return outer_result; } else { for (; less_than_or_infinite<B>(i); ++i) { if (auto inner_result = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, end_cycle_mark>())) { if (auto outer_result = evaluate(begin, inner_result.get_end_position(), end, inner_result.unmatch(), ctll::list<Tail...>())) { return outer_result; } else { captures = inner_result.unmatch(); current = inner_result.get_end_position(); continue; } } else { return not_matched; } } return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } } // possessive repeat template <typename R, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<possessive_repeat<A,B,Content...>, Tail...>) noexcept { for (size_t i{0}; less_than_or_infinite<B>(i); ++i) { // try as many of inner as possible and then try outer once if (auto inner_result = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, end_cycle_mark>())) { captures = inner_result.unmatch(); current = inner_result.get_end_position(); } else { if (less_than<A>(i)) return not_matched; else return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } } return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } // (gready) repeat template <typename R, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail> #ifdef CTRE_MSVC_GREEDY_WORKAROUND constexpr inline void evaluate_recursive(R & result, size_t i, const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<repeat<A,B,Content...>, Tail...> stack) { #else constexpr inline R evaluate_recursive(size_t i, const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<repeat<A,B,Content...>, Tail...> stack) { #endif if (less_than_or_infinite<B>(i)) { // a*ab // aab if (auto inner_result = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, end_cycle_mark>())) { // TODO MSVC issue: // if I uncomment this return it will not fail in constexpr (but the matching result will not be correct) // return inner_result // I tried to add all constructors to R but without any success #ifdef CTRE_MSVC_GREEDY_WORKAROUND evaluate_recursive(result, i+1, begin, inner_result.get_end_position(), end, inner_result.unmatch(), stack); if (result) { return; } #else if (auto rec_result = evaluate_recursive(i+1, begin, inner_result.get_end_position(), end, inner_result.unmatch(), stack)) { return rec_result; } #endif } } #ifdef CTRE_MSVC_GREEDY_WORKAROUND result = evaluate(begin, current, end, captures, ctll::list<Tail...>()); #else return evaluate(begin, current, end, captures, ctll::list<Tail...>()); #endif } // (gready) repeat optimization // basic one, if you are at the end of RE, just change it into possessive // TODO do the same if there is no collision with rest of the RE template <typename R, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<repeat<A,B,Content...>,assert_end, Tail...>) { return evaluate(begin, current, end, captures, ctll::list<possessive_repeat<A,B,Content...>, assert_end, Tail...>()); } template <typename... T> struct identify_type; // (greedy) repeat template <typename R, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, [[maybe_unused]] ctll::list<repeat<A,B,Content...>, Tail...> stack) { // check if it can be optimized #ifndef CTRE_DISABLE_GREEDY_OPT if constexpr (collides(calculate_first(Content{}...), calculate_first(Tail{}...))) { #endif // A..B size_t i{0}; for (; less_than<A>(i); ++i) { if (auto inner_result = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, end_cycle_mark>())) { captures = inner_result.unmatch(); current = inner_result.get_end_position(); } else { return not_matched; } } #ifdef CTRE_MSVC_GREEDY_WORKAROUND R result; evaluate_recursive(result, i, begin, current, end, captures, stack); return result; #else return evaluate_recursive(i, begin, current, end, captures, stack); #endif #ifndef CTRE_DISABLE_GREEDY_OPT } else { // if there is no collision we can go possessive return evaluate(begin, current, end, captures, ctll::list<possessive_repeat<A,B,Content...>, Tail...>()); } #endif } // repeat lazy_star template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<lazy_star<Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures, ctll::list<lazy_repeat<0,0,Content...>, Tail...>()); } // repeat (lazy_plus) template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<lazy_plus<Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures, ctll::list<lazy_repeat<1,0,Content...>, Tail...>()); } // repeat (possessive_star) template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<possessive_star<Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures, ctll::list<possessive_repeat<0,0,Content...>, Tail...>()); } // repeat (possessive_plus) template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<possessive_plus<Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures, ctll::list<possessive_repeat<1,0,Content...>, Tail...>()); } // repeat (greedy) star template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<star<Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures, ctll::list<repeat<0,0,Content...>, Tail...>()); } // repeat (greedy) plus template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<plus<Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures, ctll::list<repeat<1,0,Content...>, Tail...>()); } // capture (numeric ID) template <typename R, typename Iterator, typename EndIterator, size_t Id, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<capture<Id, Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures.template start_capture<Id>(current), ctll::list<sequence<Content...>, numeric_mark<Id>, Tail...>()); } // capture end mark (numeric and string ID) template <typename R, typename Iterator, typename EndIterator, size_t Id, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<numeric_mark<Id>, Tail...>) noexcept { return evaluate(begin, current, end, captures.template end_capture<Id>(current), ctll::list<Tail...>()); } // capture (string ID) template <typename R, typename Iterator, typename EndIterator, size_t Id, typename Name, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<capture_with_name<Id, Name, Content...>, Tail...>) noexcept { return evaluate(begin, current, end, captures.template start_capture<Id>(current), ctll::list<sequence<Content...>, numeric_mark<Id>, Tail...>()); } // backreference support (match agains content of iterators) template <typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE string_match_result<Iterator> match_against_range(Iterator current, const EndIterator end, Iterator range_current, const Iterator range_end) noexcept { while (end != current && range_end != range_current) { if (*current == *range_current) { current++; range_current++; } else { return {current, false}; } } return {current, range_current == range_end}; } // backreference with name template <typename R, typename Id, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<back_reference_with_name<Id>, Tail...>) noexcept { if (const auto ref = captures.template get<Id>()) { if (auto tmp = match_against_range(current, end, ref.begin(), ref.end()); tmp.match) { return evaluate(begin, tmp.current, end, captures, ctll::list<Tail...>()); } } return not_matched; } // backreference template <typename R, size_t Id, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<back_reference<Id>, Tail...>) noexcept { if (const auto ref = captures.template get<Id>()) { if (auto tmp = match_against_range(current, end, ref.begin(), ref.end()); tmp.match) { return evaluate(begin, tmp.current, end, captures, ctll::list<Tail...>()); } } return not_matched; } // end of lookahead template <typename R, typename Iterator, typename EndIterator, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator, Iterator, const EndIterator, R captures, ctll::list<end_lookahead_mark>) noexcept { return captures.matched(); } // lookahead positive template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<lookahead_positive<Content...>, Tail...>) noexcept { if (auto lookahead_result = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, end_lookahead_mark>())) { captures = lookahead_result.unmatch(); return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } else { return not_matched; } } // lookahead negative template <typename R, typename Iterator, typename EndIterator, typename... Content, typename... Tail> constexpr CTRE_FORCE_INLINE R evaluate(const Iterator begin, Iterator current, const EndIterator end, R captures, ctll::list<lookahead_negative<Content...>, Tail...>) noexcept { if (auto lookahead_result = evaluate(begin, current, end, captures, ctll::list<sequence<Content...>, end_lookahead_mark>())) { return not_matched; } else { return evaluate(begin, current, end, captures, ctll::list<Tail...>()); } } // property matching } #endif #ifndef CTRE__WRAPPER__HPP #define CTRE__WRAPPER__HPP #include <string_view> #include <string> namespace ctre { struct zero_terminated_string_end_iterator { constexpr inline zero_terminated_string_end_iterator() = default; constexpr CTRE_FORCE_INLINE bool operator==(const char * ptr) const noexcept { return *ptr == '\0'; } constexpr CTRE_FORCE_INLINE bool operator==(const wchar_t * ptr) const noexcept { return *ptr == 0; } constexpr CTRE_FORCE_INLINE bool operator!=(const char * ptr) const noexcept { return *ptr != '\0'; } constexpr CTRE_FORCE_INLINE bool operator!=(const wchar_t * ptr) const noexcept { return *ptr != 0; } }; template <typename T> class RangeLikeType { template <typename Y> static auto test(Y *) -> decltype(std::declval<const Y &>().begin(), std::declval<const Y &>().end(), std::true_type()); template <typename> static auto test(...) -> std::false_type; public: static inline constexpr bool value = decltype(test<std::remove_reference_t<std::remove_const_t<T>>>( nullptr ))::value; }; template <typename RE> struct regular_expression { template <typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto match_2(IteratorBegin begin, IteratorEnd end) noexcept { return match_re(begin, end, RE()); } template <typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto search_2(IteratorBegin begin, IteratorEnd end) noexcept { return search_re(begin, end, RE()); } template <typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto starts_with_2(IteratorBegin begin, IteratorEnd end) noexcept { return starts_with(begin, end, RE()); } constexpr CTRE_FORCE_INLINE regular_expression() noexcept { } constexpr CTRE_FORCE_INLINE regular_expression(RE) noexcept { } template <typename Iterator> constexpr CTRE_FORCE_INLINE static auto match(Iterator begin, Iterator end) noexcept { return match_re(begin, end, RE()); } static constexpr CTRE_FORCE_INLINE auto match(const char * s) noexcept { return match_2(s, zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto match(const wchar_t * s) noexcept { return match_2(s, zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto match(const std::string & s) noexcept { return match_2(s.c_str(), zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto match(const std::wstring & s) noexcept { return match_2(s.c_str(), zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto match(std::string_view sv) noexcept { return match(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto match(std::wstring_view sv) noexcept { return match(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto match(std::u16string_view sv) noexcept { return match(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto match(std::u32string_view sv) noexcept { return match(sv.begin(), sv.end()); } template <typename Range, typename = typename std::enable_if<RangeLikeType<Range>::value>::type> static constexpr CTRE_FORCE_INLINE auto match(Range && range) noexcept { return match(std::begin(range), std::end(range)); } template <typename Iterator> constexpr CTRE_FORCE_INLINE static auto search(Iterator begin, Iterator end) noexcept { return search_re(begin, end, RE()); } constexpr CTRE_FORCE_INLINE static auto search(const char * s) noexcept { return search_2(s, zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto search(const wchar_t * s) noexcept { return search_2(s, zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto search(const std::string & s) noexcept { return search_2(s.c_str(), zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto search(const std::wstring & s) noexcept { return search_2(s.c_str(), zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto search(std::string_view sv) noexcept { return search(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto search(std::wstring_view sv) noexcept { return search(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto search(std::u16string_view sv) noexcept { return search(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto search(std::u32string_view sv) noexcept { return search(sv.begin(), sv.end()); } template <typename Range> static constexpr CTRE_FORCE_INLINE auto search(Range && range) noexcept { return search(std::begin(range), std::end(range)); } template <typename Iterator> constexpr CTRE_FORCE_INLINE static auto starts_with(Iterator begin, Iterator end) noexcept { return starts_with_re(begin, end, RE()); } constexpr CTRE_FORCE_INLINE static auto starts_with(const char * s) noexcept { return starts_with_2(s, zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto starts_with(const wchar_t * s) noexcept { return starts_with_2(s, zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto starts_with(const std::string & s) noexcept { return starts_with_2(s.c_str(), zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto starts_with(const std::wstring & s) noexcept { return starts_with_2(s.c_str(), zero_terminated_string_end_iterator()); } static constexpr CTRE_FORCE_INLINE auto starts_with(std::string_view sv) noexcept { return starts_with(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto starts_with(std::wstring_view sv) noexcept { return starts_with(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto starts_with(std::u16string_view sv) noexcept { return starts_with(sv.begin(), sv.end()); } static constexpr CTRE_FORCE_INLINE auto starts_with(std::u32string_view sv) noexcept { return starts_with(sv.begin(), sv.end()); } template <typename Range> static constexpr CTRE_FORCE_INLINE auto starts_with(Range && range) noexcept { return starts_with(std::begin(range), std::end(range)); } }; template <typename RE> regular_expression(RE) -> regular_expression<RE>; } #endif #ifndef __EDG__ namespace ctre { // in C++17 (clang & gcc with gnu extension) we need translate character pack into ctll::fixed_string // in C++20 we have `class nontype template parameters` #if !(__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <typename CharT, CharT... input> static inline constexpr auto _fixed_string_reference = ctll::fixed_string< sizeof...(input)>({input...}); #endif namespace literals { // clang and GCC <9 supports LITERALS with packs #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template" #define CTRE_ENABLE_LITERALS #endif #ifdef __INTEL_COMPILER // not enable literals #elif defined __GNUC__ #if not(__GNUC__ == 9) #define CTRE_ENABLE_LITERALS #endif #endif #ifdef CTRE_ENABLE_LITERALS // add this when we will have concepts // requires ctll::parser<ctre::pcre, _fixed_string_reference<CharT, charpack...>, ctre::pcre_actions>::template correct_with<pcre_context<>> #if !(__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre() noexcept { constexpr auto & _input = _fixed_string_reference<CharT, charpack...>; #else template <ctll::fixed_string input> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre() noexcept { constexpr auto _input = input; // workaround for GCC 9 bug 88092 #endif using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); if constexpr (tmp()) { using re = decltype(front(typename tmp::output_type::stack_type())); return ctre::regular_expression(re()); } else { return ctre::regular_expression(reject()); } } // this will need to be fixed with C++20 #if !(__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre_id() noexcept { return id<charpack...>(); } #endif #endif // CTRE_ENABLE_LITERALS } namespace test_literals { #ifdef CTRE_ENABLE_LITERALS #if !(__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr inline auto operator""_ctre_test() noexcept { constexpr auto & _input = _fixed_string_reference<CharT, charpack...>; #else template <ctll::fixed_string input> CTRE_FLATTEN constexpr inline auto operator""_ctre_test() noexcept { constexpr auto _input = input; // workaround for GCC 9 bug 88092 #endif return ctll::parser<ctre::pcre, _input>::template correct_with<>; } #if !(__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr inline auto operator""_ctre_gen() noexcept { constexpr auto & _input = _fixed_string_reference<CharT, charpack...>; #else template <ctll::fixed_string input> CTRE_FLATTEN constexpr inline auto operator""_ctre_gen() noexcept { constexpr auto _input = input; // workaround for GCC 9 bug 88092 #endif using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); return typename tmp::output_type::stack_type(); } #if !(__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <typename CharT, CharT... charpack> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre_syntax() noexcept { constexpr auto & _input = _fixed_string_reference<CharT, charpack...>; #else template <ctll::fixed_string input> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto operator""_ctre_syntax() noexcept { constexpr auto _input = input; // workaround for GCC 9 bug 88092 #endif return ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template correct_with<pcre_context<>>; } #endif #ifdef __clang__ #pragma clang diagnostic pop #endif } // literals } // ctre #endif #endif #ifndef CTRE_V2__CTRE__FUNCTIONS__HPP #define CTRE_V2__CTRE__FUNCTIONS__HPP namespace ctre { #if !(__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) // avoiding CTAD limitation in C++17 template <typename CharT, size_t N> class pattern: public ctll::fixed_string<N> { using parent = ctll::fixed_string<N>; public: constexpr pattern(const CharT (&input)[N]) noexcept: parent(input) { } }; template <typename CharT, size_t N> pattern(const CharT (&)[N]) -> pattern<CharT, N>; // for better examples template <typename CharT, size_t N> class fixed_string: public ctll::fixed_string<N> { using parent = ctll::fixed_string<N>; public: constexpr fixed_string(const CharT (&input)[N]) noexcept: parent(input) { } }; template <typename CharT, size_t N> fixed_string(const CharT (&)[N]) -> fixed_string<CharT, N>; #endif #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string input> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto re() noexcept { constexpr auto _input = input; // workaround for GCC 9 bug 88092 #else template <auto & input> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto re() noexcept { constexpr auto & _input = input; #endif using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); using re = decltype(front(typename tmp::output_type::stack_type())); return ctre::regular_expression(re()); } // in moment when we get C++20 support this will start to work :) template <typename RE> struct regex_match_t { template <typename... Args> CTRE_FORCE_INLINE constexpr auto operator()(Args && ... args) const noexcept { auto re_obj = ctre::regular_expression<RE>(); return re_obj.match(std::forward<Args>(args)...); } template <typename... Args> CTRE_FORCE_INLINE constexpr auto try_extract(Args && ... args) const noexcept { return operator()(std::forward<Args>(args)...); } }; template <typename RE> struct regex_search_t { template <typename... Args> CTRE_FORCE_INLINE constexpr auto operator()(Args && ... args) const noexcept { auto re_obj = ctre::regular_expression<RE>(); return re_obj.search(std::forward<Args>(args)...); } template <typename... Args> CTRE_FORCE_INLINE constexpr auto try_extract(Args && ... args) const noexcept { return operator()(std::forward<Args>(args)...); } }; template <typename RE> struct regex_starts_with_t { template <typename... Args> CTRE_FORCE_INLINE constexpr auto operator()(Args && ... args) const noexcept { auto re_obj = ctre::regular_expression<RE>(); return re_obj.starts_with(std::forward<Args>(args)...); } template <typename... Args> CTRE_FORCE_INLINE constexpr auto try_extract(Args && ... args) const noexcept { return operator()(std::forward<Args>(args)...); } }; #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <auto input> struct regex_builder { static constexpr auto _input = input; using _tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(_tmp(), "Regular Expression contains syntax error."); using type = ctll::conditional<(bool)(_tmp()), decltype(ctll::front(typename _tmp::output_type::stack_type())), ctll::list<reject>>; }; template <ctll::fixed_string input> static constexpr inline auto match = regex_match_t<typename regex_builder<input>::type>(); template <ctll::fixed_string input> static constexpr inline auto search = regex_search_t<typename regex_builder<input>::type>(); template <ctll::fixed_string input> static constexpr inline auto starts_with = regex_starts_with_t<typename regex_builder<input>::type>(); #else template <auto & input> struct regex_builder { using _tmp = typename ctll::parser<ctre::pcre, input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(_tmp(), "Regular Expression contains syntax error."); using type = ctll::conditional<(bool)(_tmp()), decltype(ctll::front(typename _tmp::output_type::stack_type())), ctll::list<reject>>; }; template <auto & input> static constexpr inline auto match = regex_match_t<typename regex_builder<input>::type>(); template <auto & input> static constexpr inline auto search = regex_search_t<typename regex_builder<input>::type>(); template <auto & input> static constexpr inline auto starts_with = regex_starts_with_t<typename regex_builder<input>::type>(); #endif } #endif #ifndef CTRE_V2__CTRE__ITERATOR__HPP #define CTRE_V2__CTRE__ITERATOR__HPP namespace ctre { struct regex_end_iterator { constexpr regex_end_iterator() noexcept { } }; template <typename BeginIterator, typename EndIterator, typename RE> struct regex_iterator { BeginIterator current; const EndIterator end; decltype(RE::search_2(std::declval<BeginIterator>(), std::declval<EndIterator>())) current_match; constexpr regex_iterator(BeginIterator begin, EndIterator end) noexcept: current{begin}, end{end}, current_match{RE::search_2(current, end)} { if (current_match) { current = current_match.template get<0>().end(); } } constexpr const auto & operator*() const noexcept { return current_match; } constexpr regex_iterator & operator++() noexcept { current_match = RE::search_2(current, end); if (current_match) { current = current_match.template get<0>().end(); } return *this; } constexpr regex_iterator operator++(int) noexcept { auto previous = *this; current_match = RE::search_2(current, end); if (current_match) { current = current_match.template get<0>().end(); } return previous; } }; template <typename BeginIterator, typename EndIterator, typename RE> constexpr bool operator!=(const regex_iterator<BeginIterator, EndIterator, RE> & left, regex_end_iterator) { return bool(left.current_match); } template <typename BeginIterator, typename EndIterator, typename RE> constexpr bool operator!=(regex_end_iterator, const regex_iterator<BeginIterator, EndIterator, RE> & right) { return bool(right.current_match); } template <typename BeginIterator, typename EndIterator, typename RE> constexpr auto iterator(BeginIterator begin, EndIterator end, RE) noexcept { return regex_iterator<BeginIterator, EndIterator, RE>(begin, end); } constexpr auto iterator() noexcept { return regex_end_iterator{}; } template <typename Subject, typename RE> constexpr auto iterator(const Subject & subject, RE re) noexcept { return iterator(subject.begin(), subject.end(), re); } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string input, typename BeginIterator, typename EndIterator> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto iterator(BeginIterator begin, EndIterator end) noexcept { constexpr auto _input = input; using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); using re = decltype(front(typename tmp::output_type::stack_type())); return iterator(begin, end, re()); } #endif #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string input, typename Subject> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto iterator(const Subject & subject) noexcept { constexpr auto _input = input; using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); using re = decltype(front(typename tmp::output_type::stack_type())); return iterator(subject.begin(), subject.end(), re()); } #endif } // ctre #endif #ifndef CTRE_V2__CTRE__RANGE__HPP #define CTRE_V2__CTRE__RANGE__HPP namespace ctre { template <typename BeginIterator, typename EndIterator, typename RE> struct regex_range { BeginIterator _begin; const EndIterator _end; constexpr regex_range(BeginIterator begin, EndIterator end) noexcept: _begin{begin}, _end{end} { } constexpr auto begin() const noexcept { return regex_iterator<BeginIterator, EndIterator, RE>(_begin, _end); } constexpr auto end() const noexcept { return regex_end_iterator{}; } }; template <typename BeginIterator, typename EndIterator, typename RE> constexpr auto range(BeginIterator begin, EndIterator end, RE) noexcept { return regex_range<BeginIterator, EndIterator, RE>(begin, end); } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string input, typename BeginIterator, typename EndIterator> constexpr auto range(BeginIterator begin, EndIterator end) noexcept { constexpr auto _input = input; using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); using re = decltype(front(typename tmp::output_type::stack_type())); auto re_obj = ctre::regular_expression(re()); return range(begin, end, re_obj); } #endif template <typename Subject, typename RE> constexpr auto range(const Subject & subject, RE re) noexcept { return range(subject.begin(), subject.end(), re); } template <typename RE> constexpr auto range(const char * subject, RE re) noexcept { return range(subject, zero_terminated_string_end_iterator(), re); } #if (__cpp_nontype_template_parameter_class || (__cpp_nontype_template_args >= 201911L)) template <ctll::fixed_string input, typename Subject> constexpr auto range(const Subject & subject) noexcept { constexpr auto _input = input; using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); using re = decltype(front(typename tmp::output_type::stack_type())); auto re_obj = ctre::regular_expression(re()); return range(subject.begin(), subject.end(), re_obj); } #else template <auto & input, typename Subject> constexpr auto range(const Subject & subject) noexcept { constexpr auto & _input = input; using tmp = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>; static_assert(tmp(), "Regular Expression contains syntax error."); using re = decltype(front(typename tmp::output_type::stack_type())); auto re_obj = ctre::regular_expression(re()); return range(subject.begin(), subject.end(), re_obj); } #endif } #endif #ifndef CTRE_V2__CTRE__OPERATORS__HPP #define CTRE_V2__CTRE__OPERATORS__HPP template <typename A, typename B> constexpr auto operator|(ctre::regular_expression<A>, ctre::regular_expression<B>) -> ctre::regular_expression<ctre::select<A,B>> { return {}; } template <typename A, typename B> constexpr auto operator>>(ctre::regular_expression<A>, ctre::regular_expression<B>) -> ctre::regular_expression<ctre::sequence<A,B>> { return {}; } #endif #endif static constexpr ctll::fixed_string pattern = "^abc^"; bool match(std::string_view subject) { return ctre::match<pattern>(subject); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
About the author
Statistics
Changelog
Version tree