gnucash stable: Multiple changes pushed
Christopher Lam
clam at code.gnucash.org
Sat May 16 20:43:43 EDT 2026
Updated via https://github.com/Gnucash/gnucash/commit/df9380c2 (commit)
via https://github.com/Gnucash/gnucash/commit/384043ac (commit)
via https://github.com/Gnucash/gnucash/commit/0d21fdc9 (commit)
via https://github.com/Gnucash/gnucash/commit/96dac7bb (commit)
from https://github.com/Gnucash/gnucash/commit/bf1264b5 (commit)
commit df9380c2a80f92e8d0c003cb461e898489233d06
Merge: bf1264b561 384043ac41
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sun May 17 08:41:06 2026 +0800
Merge branch 'ctre-regex' into stable
commit 384043ac41ab2f8e59ab746b5b87f503c7c74483
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sat May 16 18:27:12 2026 +0800
[gnc-filepath-utils.cpp] use ctre instead of std::regex
diff --git a/libgnucash/core-utils/CMakeLists.txt b/libgnucash/core-utils/CMakeLists.txt
index 4fc2ad7ff1..3f66cf7410 100644
--- a/libgnucash/core-utils/CMakeLists.txt
+++ b/libgnucash/core-utils/CMakeLists.txt
@@ -57,6 +57,7 @@ target_link_libraries(gnc-core-utils
${GOBJECT_LDFLAGS}
${GTK_MAC_LDFLAGS}
${ICU_LIBRARIES}
+ ctre
"$<$<BOOL:${MAC_INTEGRATION}>:${OSX_EXTRA_LIBRARIES}>")
target_compile_definitions(gnc-core-utils
diff --git a/libgnucash/core-utils/gnc-filepath-utils.cpp b/libgnucash/core-utils/gnc-filepath-utils.cpp
index fe3e31e5ee..dea726b135 100644
--- a/libgnucash/core-utils/gnc-filepath-utils.cpp
+++ b/libgnucash/core-utils/gnc-filepath-utils.cpp
@@ -66,7 +66,7 @@
#include "gnc-locale-utils.hpp"
#include <boost/filesystem.hpp>
#include <boost/locale.hpp>
-#include <regex>
+#include <ctre.hpp>
#include <iostream>
/* Below cvt and bfs_locale should be used with boost::filesystem::path (bfs)
@@ -1321,23 +1321,22 @@ gnc_list_all_paths ()
};
}
-static const std::regex
+static constexpr ctll::fixed_string
backup_regex (".*[.](?:xac|gnucash)[.][0-9]{14}[.](?:xac|gnucash)$");
gboolean gnc_filename_is_backup (const char *filename)
{
g_return_val_if_fail (filename, FALSE);
- return std::regex_match (filename, backup_regex);
+ return ctre::match<backup_regex>(filename);
}
-static const std::regex
+static constexpr ctll::fixed_string
datafile_regex (".*[.](?:xac|gnucash)$");
gboolean gnc_filename_is_datafile (const char *filename)
{
g_return_val_if_fail (filename, FALSE);
- return !gnc_filename_is_backup (filename) &&
- std::regex_match (filename, datafile_regex);
+ return !gnc_filename_is_backup (filename) && ctre::match<datafile_regex>(filename);
}
std::ofstream
diff --git a/libgnucash/core-utils/test/CMakeLists.txt b/libgnucash/core-utils/test/CMakeLists.txt
index f5879a696f..1e5ad913a1 100644
--- a/libgnucash/core-utils/test/CMakeLists.txt
+++ b/libgnucash/core-utils/test/CMakeLists.txt
@@ -37,6 +37,7 @@ set(gtest_core_utils_LIBS
PkgConfig::GLIB2
${Boost_LIBRARIES}
${GTHREAD_LDFLAGS}
+ ctre
gtest)
set(test_gnc_path_util_SOURCES
commit 0d21fdc9f7815b878314e31970717d20cb5ee01f
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Fri May 15 17:22:53 2026 +0800
[ctre.hpp] add single-header ctre v3.11.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0fbab46baa..e9811d4de9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -900,6 +900,7 @@ endif()
# The subdirectories
add_subdirectory (borrowed)
+add_library(ctre_global ALIAS ctre)
add_subdirectory (data)
add_subdirectory (doc)
# Note: po should be processed before gnucash - it provides LINGUAS, used to generate desktop and appdata files
diff --git a/borrowed/CMakeLists.txt b/borrowed/CMakeLists.txt
index eb2c5159da..301f2ea59d 100644
--- a/borrowed/CMakeLists.txt
+++ b/borrowed/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(goffice)
add_subdirectory(chartjs-2)
add_subdirectory(chartjs-4)
add_subdirectory(guile-json)
+add_subdirectory(ctre)
set_local_dist(borrowed_DIST_local jenny/jenny.c CMakeLists.txt README)
set(borrowed_DIST
@@ -12,4 +13,5 @@ set(borrowed_DIST
${libc_DIST}
${guile-json_DIST}
${goffice_DIST}
+ ${ctre_DIST}
PARENT_SCOPE)
diff --git a/borrowed/ctre/CMakeLists.txt b/borrowed/ctre/CMakeLists.txt
new file mode 100644
index 0000000000..a99c637517
--- /dev/null
+++ b/borrowed/ctre/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+add_library(ctre INTERFACE)
+
+target_include_directories(ctre INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(ctre_DIST ${ctre_DIST_LOCAL} PARENT_SCOPE)
+
+set_local_dist(ctre_DIST_LOCAL
+ CMakeLists.txt
+ ctre.hpp
+)
+
+set(ctre_DIST ${ctre_DIST_LOCAL} PARENT_SCOPE)
diff --git a/borrowed/ctre/LICENSE b/borrowed/ctre/LICENSE
new file mode 100644
index 0000000000..bd8b243dfa
--- /dev/null
+++ b/borrowed/ctre/LICENSE
@@ -0,0 +1,218 @@
+ 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.
diff --git a/borrowed/ctre/ctre.hpp b/borrowed/ctre/ctre.hpp
new file mode 100644
index 0000000000..0e0ac4a487
--- /dev/null
+++ b/borrowed/ctre/ctre.hpp
@@ -0,0 +1,5993 @@
+/*
+ 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
+
+#ifndef CTLL_IN_A_MODULE
+#include <utility>
+#include <cstddef>
+#include <string_view>
+#include <array>
+#include <cstdint>
+#endif
+
+#ifndef CTLL__UTILITIES__HPP
+#define CTLL__UTILITIES__HPP
+
+#ifndef CTLL_IN_A_MODULE
+#include <type_traits>
+#endif
+
+#ifdef CTLL_IN_A_MODULE
+#define CTLL_EXPORT export
+#else
+#define CTLL_EXPORT
+#endif
+
+#if defined __cpp_nontype_template_parameter_class
+ #define CTLL_CNTTP_COMPILER_CHECK 1
+#elif defined __cpp_nontype_template_args
+// compiler which defines correctly feature test macro (not you clang)
+ #if __cpp_nontype_template_args >= 201911L
+ #define CTLL_CNTTP_COMPILER_CHECK 1
+ #elif __cpp_nontype_template_args >= 201411L
+// appleclang 13+
+ #if defined __apple_build_version__
+ #if defined __clang_major__ && __clang_major__ >= 13
+// but only in c++20 and more
+ #if __cplusplus > 201703L
+ #define CTLL_CNTTP_COMPILER_CHECK 1
+ #endif
+ #endif
+ #else
+// clang 12+
+ #if defined __clang_major__ && __clang_major__ >= 12
+// but only in c++20 and more
+ #if __cplusplus > 201703L
+ #define CTLL_CNTTP_COMPILER_CHECK 1
+ #endif
+ #endif
+ #endif
+ #endif
+#endif
+
+#ifndef CTLL_CNTTP_COMPILER_CHECK
+ #define CTLL_CNTTP_COMPILER_CHECK 0
+#endif
+
+#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 {
+
+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};
+}
+
+struct construct_from_pointer_t { };
+
+constexpr auto construct_from_pointer = construct_from_pointer_t{};
+
+CTLL_EXPORT 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(construct_from_pointer_t, const T * input) noexcept {
+ if constexpr (std::is_same_v<T, char>) {
+ #ifdef CTRE_STRING_IS_UTF8
+ size_t out{0};
+ for (size_t i{0}; i < N; ++i) {
+ 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]);
+ real_size++;
+ }
+ #endif
+#if defined(__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) {
+ 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)) + 0x10000;
+ } else {
+ correct_flag = false;
+ break;
+ }
+ }
+ } else {
+ 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] = static_cast<char32_t>(input[i]);
+ real_size++;
+ }
+ }
+ }
+
+ template <typename T> constexpr fixed_string(const std::array<T, N> & in) noexcept: fixed_string{construct_from_pointer, in.data()} { }
+ template <typename T> constexpr fixed_string(const T (&input)[N+1]) noexcept: fixed_string{construct_from_pointer, input} { }
+
+ 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 <typename CharT, size_t N> fixed_string(const std::array<CharT,N> &) -> fixed_string<N>;
+
+template <size_t N> fixed_string(fixed_string<N>) -> fixed_string<N>;
+
+}
+
+#endif
+
+#ifndef CTLL__TYPE_STACK__HPP
+#define CTLL__TYPE_STACK__HPP
+
+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 {}; }
+
+// rotate list
+template <typename T> struct rotate_item {
+ template <typename... Ts> friend constexpr auto operator+(list<Ts...>, rotate_item<T>) noexcept -> list<T, Ts...> { return {}; }
+};
+
+template <typename... Ts> constexpr auto rotate(list<Ts...>) -> decltype((list<>{} + ... + rotate_item<Ts>{})) {
+ return {};
+}
+
+// set operations
+template <typename T> struct item_matcher {
+ struct not_selected {
+ template <typename... Ts> friend constexpr auto operator+(list<Ts...>, not_selected) -> list<Ts...>;
+ };
+ template <typename Y> struct wrapper {
+ template <typename... Ts> friend constexpr auto operator+(list<Ts...>, wrapper<Y>) -> list<Ts...,Y>;
+ };
+
+ static constexpr auto check(T) { return std::true_type{}; }
+ static constexpr auto check(...) { return std::false_type{}; }
+ static constexpr auto select(T) { return not_selected{}; }
+ template <typename Y> static constexpr auto select(Y) { return wrapper<Y>{}; }
+};
+
+template <typename T, typename... Ts> constexpr bool exists_in(T, list<Ts...>) noexcept {
+ return (item_matcher<T>::check(Ts{}) || ... || false);
+}
+
+template <typename T, typename... Ts> constexpr auto add_item(T item, list<Ts...> l) noexcept {
+ if constexpr (exists_in(item, l)) {
+ return l;
+ } else {
+ return list<Ts..., T>{};
+ }
+}
+
+template <typename T, typename... Ts> constexpr auto remove_item(T, list<Ts...>) noexcept {
+ item_matcher<T> matcher;
+ return decltype((list<>{} + ... + matcher.select(Ts{}))){};
+}
+
+}
+
+#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 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 set(term<V>) noexcept;
+ #else
+ template <auto V, typename = std::enable_if_t<((Def == V) || ... || false)>> constexpr 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 neg_set(term<V>) noexcept;
+ #else
+ template <auto V, typename = std::enable_if_t<!((Def == V) || ... || false)>> constexpr 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
+
+#ifndef CTLL_IN_A_MODULE
+#include <limits>
+#endif
+
+namespace ctll {
+
+enum class decision {
+ reject,
+ accept,
+ undecided
+};
+
+struct placeholder { };
+
+template <size_t> using index_placeholder = placeholder;
+
+#if CTLL_CNTTP_COMPILER_CHECK
+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 CTLL_CNTTP_COMPILER_CHECK
+ 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 {
+
+ static constexpr bool is_correct = Decision == decision::accept;
+
+ constexpr inline CTLL_FORCE_INLINE operator bool() const noexcept {
+ return is_correct;
+ }
+
+ #ifdef __GNUC__ // workaround to GCC bug
+ #if CTLL_CNTTP_COMPILER_CHECK
+ 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;
+ static constexpr size_t position = Pos;
+
+ 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 local_input = input;
+ return typename parser<Grammar, local_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 local_input = input;
+ return typename parser<Grammar, local_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 content_or_empty {};
+ 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 mode_switch2 {};
+ struct n {};
+ struct number2 {};
+ struct number {};
+ struct o {};
+ struct opt_content {};
+ struct p {};
+ struct property_name2 {};
+ struct property_name {};
+ struct property_value2 {};
+ struct property_value {};
+ 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_atomic: 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 mode_case_insensitive: ctll::action {};
+ struct mode_case_sensitive: ctll::action {};
+ struct mode_multiline: ctll::action {};
+ struct mode_singleline: 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_assert_subject_begin: ctll::action {};
+ struct push_assert_subject_end: ctll::action {};
+ struct push_assert_subject_end_with_lineend: 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_not_word_boundary: ctll::action {};
+ struct push_number: ctll::action {};
+ struct push_property_name: ctll::action {};
+ struct push_property_value: ctll::action {};
+ struct push_word_boundary: 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_empty: ctll::action {};
+ struct set_make: ctll::action {};
+ struct set_make_negative: ctll::action {};
+ struct set_start: ctll::action {};
+ struct start_atomic: ctll::action {};
+ struct start_lookahead_negative: ctll::action {};
+ struct start_lookahead_positive: ctll::action {};
+ struct start_lookbehind_negative: ctll::action {};
+ struct start_lookbehind_positive: ctll::action {};
+
+// (q)LL1 function:
+ using _others = ctll::neg_set<'!','$','\x28','\x29','*','+',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','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'>;
+ 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<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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_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::term<'|'>) -> ctll::push<ctll::anything, push_empty, opt_content, make_alternate>;
+ 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<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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_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::term<'A'>) -> ctll::push<ctll::anything, push_assert_subject_begin>;
+ static constexpr auto rule(backslash, ctll::term<'z'>) -> ctll::push<ctll::anything, push_assert_subject_end>;
+ static constexpr auto rule(backslash, ctll::term<'Z'>) -> ctll::push<ctll::anything, push_assert_subject_end_with_lineend>;
+ 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, ctll::term<'B'>) -> ctll::push<ctll::anything, push_not_word_boundary>;
+ static constexpr auto rule(backslash, ctll::term<'b'>) -> ctll::push<ctll::anything, push_word_boundary>;
+
+ 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::set<'$','\x28','\x29','*','+','-','.','/','<','>','?','[','\\','\"',']','^','\x7B','|','\x7D'>) -> 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<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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_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<'|'>) -> ctll::push<ctll::anything, push_empty, content_or_empty, make_alternate, 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','1','2','3','4','5','6','7','8','9','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(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','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','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'>) -> 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<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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_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<'|'>) -> ctll::push<ctll::anything, push_empty, content_or_empty, make_alternate>;
+ 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(content_or_empty, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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_character, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>;
+ static constexpr auto rule(content_or_empty, ctll::term<'\x29'>) -> ctll::push<push_empty>;
+ static constexpr auto rule(content_or_empty, ctll::set<'*','+','?','\x7B','|','\x7D'>) -> ctll::reject;
+
+ static constexpr auto rule(d, ctll::term<'i'>) -> ctll::push<ctll::anything, mode_case_insensitive, mode_switch2>;
+ static constexpr auto rule(d, ctll::term<'c'>) -> ctll::push<ctll::anything, mode_case_sensitive, mode_switch2>;
+ static constexpr auto rule(d, ctll::term<'m'>) -> ctll::push<ctll::anything, mode_multiline, mode_switch2>;
+ static constexpr auto rule(d, ctll::term<'s'>) -> ctll::push<ctll::anything, mode_singleline, mode_switch2>;
+ static constexpr auto rule(d, ctll::term<'<'>) -> ctll::push<ctll::anything, o>;
+ static constexpr auto rule(d, ctll::term<':'>) -> ctll::push<ctll::anything, reset_capture, content_in_capture, ctll::term<'\x29'>>;
+ static constexpr auto rule(d, ctll::term<'>'>) -> ctll::push<ctll::anything, reset_capture, start_atomic, content_in_capture, make_atomic, ctll::term<'\x29'>>;
+ static constexpr auto rule(d, ctll::term<'!'>) -> ctll::push<ctll::anything, reset_capture, start_lookahead_negative, content_in_capture, look_finish, ctll::term<'\x29'>>;
+ static constexpr auto rule(d, ctll::term<'='>) -> ctll::push<ctll::anything, reset_capture, 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::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::set<'$','\x28','\x29','*','+','-','.','/','<','>','?','[','\\','\"',']','^','\x7B','|','\x7D'>) -> ctll::push<ctll::anything, push_character, range>;
+ 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::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, range>;
+ 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(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, p>;
+
+ 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','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>) -> 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','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','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'>) -> 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','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>) -> 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','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'>) -> 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',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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::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(mode_switch2, ctll::term<'i'>) -> ctll::push<ctll::anything, mode_case_insensitive, mode_switch2>;
+ static constexpr auto rule(mode_switch2, ctll::term<'c'>) -> ctll::push<ctll::anything, mode_case_sensitive, mode_switch2>;
+ static constexpr auto rule(mode_switch2, ctll::term<'m'>) -> ctll::push<ctll::anything, mode_multiline, mode_switch2>;
+ static constexpr auto rule(mode_switch2, ctll::term<'s'>) -> ctll::push<ctll::anything, mode_singleline, mode_switch2>;
+ static constexpr auto rule(mode_switch2, ctll::term<'\x29'>) -> ctll::push<ctll::anything>;
+
+ static constexpr auto rule(n, ctll::set<'0','1','2','3','4','5','6','7','8','9'>) -> ctll::push<number, 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::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<block_name, ctll::term<'>'>, content_in_capture, make_capture_with_name, ctll::term<'\x29'>>;
+ static constexpr auto rule(o, ctll::term<'!'>) -> ctll::push<ctll::anything, reset_capture, start_lookbehind_negative, content_in_capture, look_finish, ctll::term<'\x29'>>;
+ static constexpr auto rule(o, ctll::term<'='>) -> ctll::push<ctll::anything, reset_capture, start_lookbehind_positive, content_in_capture, look_finish, ctll::term<'\x29'>>;
+
+ static constexpr auto rule(opt_content, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, ctll::term<'\x28'>) -> ctll::push<ctll::anything, prepare_capture, block, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, ctll::term<'^'>) -> ctll::push<ctll::anything, push_assert_begin, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, ctll::term<'$'>) -> ctll::push<ctll::anything, push_assert_end, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, ctll::set<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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_character, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, _others) -> ctll::push<ctll::anything, push_character, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, ctll::term<'.'>) -> ctll::push<ctll::anything, push_character_anything, repeat, string2, content2>;
+ static constexpr auto rule(opt_content, ctll::epsilon) -> ctll::push<push_empty>;
+ static constexpr auto rule(opt_content, ctll::set<'\x29','*','+','?','\x7B','|','\x7D'>) -> ctll::reject;
+
+ static constexpr auto rule(p, ctll::term<'p'>) -> ctll::push<ctll::anything, ctll::term<'h'>, ctll::term<'a'>, class_named_alpha>;
+ static constexpr auto rule(p, ctll::term<'n'>) -> ctll::push<ctll::anything, ctll::term<'u'>, ctll::term<'m'>, class_named_alnum>;
+
+ 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','1','2','3','4','5','6','7','8','9','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_property_name, property_name2>;
+
+ static constexpr auto rule(property_name, ctll::set<'.','0','1','2','3','4','5','6','7','8','9','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_property_name, property_name2>;
+
+ static constexpr auto rule(property_value2, ctll::term<'\x7D'>) -> ctll::epsilon;
+ static constexpr auto rule(property_value2, ctll::set<'.','0','1','2','3','4','5','6','7','8','9','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_property_value, property_value2>;
+
+ static constexpr auto rule(property_value, ctll::set<'.','0','1','2','3','4','5','6','7','8','9','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_property_value, property_value2>;
+
+ static constexpr auto rule(range, ctll::set<'!','$','\x28','\x29','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','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'>) -> 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(repeat, ctll::set<'!','$','\x28','\x29',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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::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>;
+ 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::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','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','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'>) -> 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::term<']'>) -> ctll::push<set_empty>;
+ static constexpr auto rule(set2a, ctll::term<'-'>) -> 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','*','+',',','.','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','?','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'>) -> 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::term<'-'>) -> 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<'!',',','-','/','0','1','2','3','4','5','6','7','8','9',':','<','=','>','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_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__ROTATE__HPP
+#define CTRE__ROTATE__HPP
+
+#ifndef CTRE__ATOMS__HPP
+#define CTRE__ATOMS__HPP
+
+#ifndef CTRE__ATOMS_CHARACTERS__HPP
+#define CTRE__ATOMS_CHARACTERS__HPP
+
+#ifndef CTRE__UTILITY__HPP
+#define CTRE__UTILITY__HPP
+
+#define CTRE_CNTTP_COMPILER_CHECK CTLL_CNTTP_COMPILER_CHECK
+
+#ifdef CTRE_IN_A_MODULE
+#define CTRE_EXPORT export
+#else
+#define CTRE_EXPORT
+#endif
+
+#if __GNUC__ > 9
+#if __has_cpp_attribute(likely)
+#define CTRE_LIKELY [[likely]]
+#else
+#define CTRE_LIKELY
+#endif
+
+#if __has_cpp_attribute(unlikely)
+#define CTRE_UNLIKELY [[unlikely]]
+#else
+#define CTRE_UNLIKELY
+#endif
+#else
+#define CTRE_LIKELY
+#define CTRE_UNLIKELY
+#endif
+
+#ifdef _MSC_VER
+#define CTRE_FORCE_INLINE __forceinline
+#if __has_cpp_attribute(msvc::flatten)
+#define CTRE_FLATTEN [[msvc::flatten]]
+#elif _MSC_VER >= 1930 && !defined(__clang__)
+#define CTRE_FLATTEN [[msvc::flatten]]
+#else
+#define CTRE_FLATTEN
+#endif
+#else
+#define CTRE_FORCE_INLINE inline __attribute__((always_inline))
+#define CTRE_FLATTEN __attribute__((flatten))
+#endif
+
+#endif
+
+#ifndef CTRE_V2__CTRE__FLAGS_AND_MODES__HPP
+#define CTRE_V2__CTRE__FLAGS_AND_MODES__HPP
+
+namespace ctre {
+
+struct singleline { };
+struct multiline { };
+
+struct case_sensitive { };
+struct case_insensitive { };
+
+using ci = case_insensitive;
+using cs = case_sensitive;
+
+template <typename... Flags> struct flag_list { };
+
+struct flags {
+ bool block_empty_match = false;
+ bool multiline = false;
+ bool case_insensitive = false;
+
+ constexpr flags() = default;
+ constexpr flags(const flags &) = default;
+ constexpr flags(flags &&) = default;
+
+ constexpr CTRE_FORCE_INLINE flags(ctre::singleline v) noexcept { set_flag(v); }
+ constexpr CTRE_FORCE_INLINE flags(ctre::multiline v) noexcept { set_flag(v); }
+ constexpr CTRE_FORCE_INLINE flags(ctre::case_sensitive v) noexcept { set_flag(v); }
+ constexpr CTRE_FORCE_INLINE flags(ctre::case_insensitive v) noexcept { set_flag(v); }
+
+
+ template <typename... Args> constexpr CTRE_FORCE_INLINE flags(ctll::list<Args...>) noexcept {
+ (this->set_flag(Args{}), ...);
+ }
+
+ constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_case_insensitive) noexcept {
+ f.case_insensitive = true;
+ return f;
+ }
+
+ constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_case_sensitive) noexcept {
+ f.case_insensitive = false;
+ return f;
+ }
+
+ constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_singleline) noexcept {
+ f.multiline = false;
+ return f;
+ }
+
+ constexpr friend CTRE_FORCE_INLINE auto operator+(flags f, pcre::mode_multiline) noexcept {
+ f.multiline = true;
+ return f;
+ }
+
+ constexpr CTRE_FORCE_INLINE void set_flag(ctre::singleline) noexcept {
+ multiline = false;
+ }
+
+ constexpr CTRE_FORCE_INLINE void set_flag(ctre::multiline) noexcept {
+ multiline = true;
+ }
+
+ constexpr CTRE_FORCE_INLINE void set_flag(ctre::case_insensitive) noexcept {
+ case_insensitive = true;
+ }
+
+ constexpr CTRE_FORCE_INLINE void set_flag(ctre::case_sensitive) noexcept {
+ case_insensitive = false;
+ }
+};
+
+constexpr CTRE_FORCE_INLINE auto not_empty_match(flags f) {
+ f.block_empty_match = true;
+ return f;
+}
+
+constexpr CTRE_FORCE_INLINE auto consumed_something(flags f, bool condition = true) {
+ if (condition) f.block_empty_match = false;
+ return f;
+}
+
+constexpr CTRE_FORCE_INLINE bool cannot_be_empty_match(flags f) {
+ return f.block_empty_match;
+}
+
+constexpr CTRE_FORCE_INLINE bool multiline_mode(flags f) {
+ return f.multiline;
+}
+
+constexpr CTRE_FORCE_INLINE bool is_case_insensitive(flags f) {
+ return f.case_insensitive;
+}
+
+} // namespace ctre
+
+#endif
+
+#ifndef CTRE_IN_A_MODULE
+#include <cstdint>
+#endif
+
+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::declval<const flags &>()), 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 <typename T> constexpr CTRE_FORCE_INLINE bool is_ascii_alpha(T v) {
+ return ((v >= static_cast<T>('a') && v <= static_cast<T>('z')) || (v >= static_cast<T>('A') && v <= static_cast<T>('Z')));
+}
+
+template <typename T> constexpr CTRE_FORCE_INLINE bool is_ascii_alpha_lowercase(T v) {
+ return (v >= static_cast<T>('a')) && (v <= static_cast<T>('z'));
+}
+
+template <typename T> constexpr CTRE_FORCE_INLINE bool is_ascii_alpha_uppercase(T v) {
+ return (v >= static_cast<T>('A')) && v <= (static_cast<T>('Z'));
+}
+
+template <auto V> struct character {
+ template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value, const flags & f) noexcept {
+ if constexpr (is_ascii_alpha(V)) {
+ if (is_case_insensitive(f)) {
+ if (value == (V ^ static_cast<decltype(V)>(0x20))) {
+ return true;//
+ }
+ }
+ }
+ return static_cast<std::make_unsigned_t<CharT>>(value) == V;
+ }
+};
+
+template <typename... Content> struct negative_set {
+ template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char([[maybe_unused]] CharT value, const flags & f) noexcept {
+ return !(Content::match_char(value, f) || ... || false);
+ }
+};
+
+template <typename... Content> struct set {
+ template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char([[maybe_unused]] CharT value, const flags & f) noexcept {
+ return (Content::match_char(value, f) || ... || false);
+ }
+};
+
+template <auto... Cs> struct enumeration : set<character<Cs>...> { };
+
+template <typename... Content> struct negate {
+ template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char([[maybe_unused]] CharT value, const flags & f) noexcept {
+ return !(Content::match_char(value, f) || ... || false);
+ }
+};
+
+template <auto A, auto B> struct char_range {
+ template <typename CharT> CTRE_FORCE_INLINE static constexpr bool match_char(CharT value, const flags & f) noexcept {
+ if constexpr (is_ascii_alpha_lowercase(A) && is_ascii_alpha_lowercase(B)) {
+ if (is_case_insensitive(f)) {
+ if (value >= (A ^ static_cast<decltype(A)>(0x20)) && value <= (B ^ static_cast<decltype(B)>(0x20))) {
+ return true;//
+ }
+ }
+ } else if constexpr (is_ascii_alpha_uppercase(A) && is_ascii_alpha_uppercase(B)) {
+ if (is_case_insensitive(f)) {
+ if (value >= (A ^ static_cast<decltype(A)>(0x20)) && value <= (B ^ static_cast<decltype(B)>(0x20))) {
+ return true;//
+ }
+ }
+ }
+ return (static_cast<std::make_unsigned_t<CharT>>(value) >= A) && (static_cast<std::make_unsigned_t<CharT>>(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_IN_A_MODULE
+#include <cstdint>
+#endif
+
+namespace ctre {
+
+// special helpers for matching
+struct accept { };
+struct reject { };
+struct start_mark { };
+struct end_mark { };
+struct end_cycle_mark { };
+struct end_lookahead_mark { };
+struct end_lookbehind_mark { };
+template <size_t Id> struct numeric_mark { };
+
+struct any { };
+
+// actual AST of regexp
+template <auto... Str> struct string { };
+template <typename... Opts> struct select { };
+template <typename... Content> struct sequence { };
+struct empty { };
+
+template <size_t a, size_t b, typename... Content> struct repeat { };
+template <typename... Content> using plus = repeat<1,0,Content...>;
+template <typename... Content> using star = repeat<0,0,Content...>;
+
+template <size_t a, size_t b, typename... Content> struct lazy_repeat { };
+template <typename... Content> using lazy_plus = lazy_repeat<1,0,Content...>;
+template <typename... Content> using lazy_star = lazy_repeat<0,0,Content...>;
+
+template <size_t a, size_t b, typename... Content> struct possessive_repeat { };
+template <typename... Content> using possessive_plus = possessive_repeat<1,0,Content...>;
+template <typename... Content> using possessive_star = possessive_repeat<0,0,Content...>;
+
+template <typename... Content> using optional = repeat<0,1,Content...>;
+template <typename... Content> using lazy_optional = lazy_repeat<0,1,Content...>;
+template <typename... Content> using possessive_optional = possessive_repeat<0,1,Content...>;
+
+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 { };
+
+template <typename... Content> struct lookbehind_positive { };
+template <typename... Content> struct lookbehind_negative { };
+
+struct atomic_start { };
+
+template <typename... Content> struct atomic_group { };
+
+template <typename... Content> struct boundary { };
+template <typename... Content> struct not_boundary { };
+
+using word_boundary = boundary<word_chars>;
+using not_word_boundary = not_boundary<word_chars>;
+
+struct assert_subject_begin { };
+struct assert_subject_end { };
+struct assert_subject_end_line{ };
+struct assert_line_begin { };
+struct assert_line_end { };
+
+template <typename> struct mode_switch { };
+
+}
+
+#endif
+
+#ifndef CTRE__ATOMS_UNICODE__HPP
+#define CTRE__ATOMS_UNICODE__HPP
+
+// master branch is not including unicode db (for now)
+#ifndef H_COR3NTIN_UNICODE_SYNOPSYS
+#define H_COR3NTIN_UNICODE_SYNOPSYS
+
+#ifndef UNICODE_DB_IN_A_MODULE
+#include <string_view>
+#endif
+
+namespace uni
+{
+ enum class category;
+ enum class property;
+ enum class version : unsigned char;
+ enum class script ;
+ enum class block;
+
+ struct script_extensions_view {
+ constexpr script_extensions_view(char32_t);
+
+ struct sentinel {};
+ struct iterator {
+
+ constexpr iterator(char32_t c);
+ constexpr script operator*() const;
+
+ constexpr iterator& operator++(int);
+
+ constexpr iterator operator++();
+
+ constexpr bool operator==(sentinel) const;
+ constexpr bool operator!=(sentinel) const;
+
+ private:
+ char32_t m_c;
+ script m_script;
+ int idx = 1;
+ };
+
+ constexpr iterator begin() const;
+ constexpr sentinel end() const;
+
+ private:
+ char32_t c;
+ };
+
+ struct numeric_value {
+
+ constexpr double value() const;
+ constexpr long long numerator() const;
+ constexpr int denominator() const;
+ constexpr bool is_valid() const;
+
+ protected:
+ constexpr numeric_value() = default;
+ constexpr numeric_value(long long n, int16_t d);
+
+ long long _n = 0;
+ int16_t _d = 0;
+ friend constexpr numeric_value cp_numeric_value(char32_t cp);
+ };
+
+ constexpr category cp_category(char32_t cp);
+ constexpr script cp_script(char32_t cp);
+ constexpr script_extensions_view cp_script_extensions(char32_t cp);
+ constexpr version cp_age(char32_t cp);
+ constexpr block cp_block(char32_t cp);
+ constexpr bool cp_is_valid(char32_t cp);
+ constexpr bool cp_is_assigned(char32_t cp);
+ constexpr bool cp_is_ascii(char32_t cp);
+ constexpr numeric_value cp_numeric_value(char32_t cp);
+
+ template<script>
+ constexpr bool cp_script_is(char32_t);
+ template<property>
+ constexpr bool cp_property_is(char32_t);
+ template<category>
+ constexpr bool cp_category_is(char32_t);
+
+ namespace detail
+ {
+ enum class binary_prop;
+ constexpr int propnamecomp(std::string_view sa, std::string_view sb);
+ constexpr binary_prop binary_prop_from_string(std::string_view s);
+
+ template<binary_prop p>
+ constexpr bool get_binary_prop(char32_t) = delete;
+
+ constexpr script script_from_string(std::string_view s);
+ constexpr block block_from_string(std::string_view s);
+ constexpr version age_from_string(std::string_view a);
+ constexpr category category_from_string(std::string_view a);
+
+ constexpr bool is_unassigned(category cat);
+ constexpr bool is_unknown(script s);
+ constexpr bool is_unknown(block b);
+ constexpr bool is_unassigned(version v);
+ constexpr bool is_unknown(binary_prop s);
+ }
+}
+
+#endif
+
+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 char (& arr)[Sz]) noexcept {
+ return std::string_view(arr, Sz);
+}
+
+// basic support for binary and type-value properties
+
+template <typename T, T Type> struct binary_property;
+template <typename T, T Type, auto Value> struct property;
+
+template <auto Type> using make_binary_property = binary_property<std::remove_const_t<decltype(Type)>, Type>;
+template <auto Type, auto Value> using make_property = property<std::remove_const_t<decltype(Type)>, Type, Value>;
+
+// unicode TS#18 level 1.2 general_category
+template <uni::detail::binary_prop Property> struct binary_property<uni::detail::binary_prop, Property> {
+ template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
+ return uni::detail::get_binary_prop<Property>(static_cast<char32_t>(static_cast<std::make_unsigned_t<CharT>>(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<uni::script, Script> {
+ template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
+ return uni::cp_script(c) == Script;
+ }
+};
+
+template <uni::script Script> struct property<property_type, property_type::script_extension, Script> {
+ template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
+ for (uni::script sc: uni::cp_script_extensions(c)) {
+ if (sc == Script) return true;
+ }
+ return false;
+ }
+};
+
+template <uni::version Age> struct binary_property<uni::version, Age> {
+ template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
+ return uni::cp_age(c) <= Age;
+ }
+};
+
+template <uni::block Block> struct binary_property<uni::block, Block> {
+ template <typename CharT> inline static constexpr bool match_char(CharT c, const flags &) noexcept {
+ return uni::cp_block(c) == Block;
+ }
+};
+
+// nonbinary properties
+
+template <typename = void> // Make it always a template as propnamecomp isn't defined yet
+constexpr property_type property_type_from_name(std::string_view str) noexcept {
+ using namespace std::string_view_literals;
+ if (uni::detail::propnamecomp(str, "script"sv) == 0 || uni::detail::propnamecomp(str, "sc"sv) == 0) {
+ return property_type::script;
+ } else if (uni::detail::propnamecomp(str, "script_extension"sv) == 0 || uni::detail::propnamecomp(str, "scx"sv) == 0) {
+ return property_type::script_extension;
+ } else if (uni::detail::propnamecomp(str, "age"sv) == 0) {
+ return property_type::age;
+ } else if (uni::detail::propnamecomp(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 char name[sizeof...(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 char value[sizeof...(Value)]{static_cast<char>(Value)...};
+ constexpr auto sc = uni::detail::script_from_string(get_string_view(value));
+ if constexpr (uni::detail::is_unknown(sc)) {
+ return ctll::reject{};
+ } else {
+ return make_binary_property<sc>();
+ }
+ }
+};
+
+template <> struct property_type_builder<property_type::script_extension> {
+ template <auto... Value> static constexpr auto get() {
+ constexpr char value[sizeof...(Value)]{static_cast<char>(Value)...};
+ constexpr auto sc = uni::detail::script_from_string(get_string_view(value));
+ if constexpr (uni::detail::is_unknown(sc)) {
+ return ctll::reject{};
+ } else {
+ return make_property<property_type::script_extension, sc>();
+ }
+ }
+};
+
+template <> struct property_type_builder<property_type::age> {
+ template <auto... Value> static constexpr auto get() {
+ constexpr char value[sizeof...(Value)]{static_cast<char>(Value)...};
+ constexpr auto age = uni::detail::age_from_string(get_string_view(value));
+ if constexpr (uni::detail::is_unassigned(age)) {
+ return ctll::reject{};
+ } else {
+ return make_binary_property<age>();
+ }
+ }
+};
+
+template <> struct property_type_builder<property_type::block> {
+ template <auto... Value> static constexpr auto get() {
+ constexpr char value[sizeof...(Value)]{static_cast<char>(Value)...};
+ constexpr auto block = uni::detail::block_from_string(get_string_view(value));
+ if constexpr (uni::detail::is_unknown(block)) {
+ return ctll::reject{};
+ } else {
+ return make_binary_property<block>();
+ }
+ }
+};
+
+}
+
+#endif
+
+namespace ctre {
+
+// helper functions
+template <size_t Index, typename... Content> auto convert_to_capture(ctll::list<Content...>) -> capture<Index, Content...>;
+template <size_t Index, typename Name, typename... Content> auto convert_to_named_capture(ctll::list<Content...>) -> capture_with_name<Index, Name, Content...>;
+template <template <size_t, size_t, typename...> typename CycleType, size_t A, size_t B, typename... Content> auto convert_to_repeat(ctll::list<Content...>) -> CycleType<A, B, Content...>;
+template <template <typename...> typename ListType, typename... Content> auto convert_to_basic_list(ctll::list<Content...>) -> ListType<Content...>;
+
+template <auto V> struct rotate_value {
+ template <auto... Vs> friend constexpr auto operator+(string<Vs...>, rotate_value<V>) noexcept -> string<V, Vs...> { return {}; }
+};
+
+struct rotate_for_lookbehind {
+
+// from atoms_characters.hpp
+template <auto V> static auto rotate(character<V>) -> character<V>;
+template <typename... Content> static auto rotate(negative_set<Content...>) -> negative_set<Content...>;
+template <typename... Content> static auto rotate(set<Content...>) -> set<Content...>;
+template <auto... Cs> static auto rotate(enumeration<Cs...>) -> enumeration<Cs...>;
+template <typename... Content> static auto rotate(negate<Content...>) -> negate<Content...>;
+template <auto A, auto B> static auto rotate(char_range<A,B>) -> char_range<A,B>;
+
+// from atoms_unicode.hpp
+template <auto... Str> static auto rotate(property_name<Str...>) -> property_name<Str...>;
+template <auto... Str> static auto rotate(property_value<Str...>) -> property_value<Str...>;
+template <typename T, T Type> static auto rotate(binary_property<T, Type>) -> binary_property<T, Type>;
+template <typename T, T Type, auto Value> static auto rotate(property<T, Type, Value>) -> property<T, Type, Value>;
+
+// from atoms.hpp
+static auto rotate(accept) -> accept;
+static auto rotate(reject) -> reject;
+static auto rotate(start_mark) -> start_mark;
+static auto rotate(end_mark) -> end_mark;
+static auto rotate(end_cycle_mark) -> end_cycle_mark;
+static auto rotate(end_lookahead_mark) -> end_lookahead_mark;
+static auto rotate(end_lookbehind_mark) -> end_lookbehind_mark;
+template <size_t Id> static auto rotate(numeric_mark<Id>) -> numeric_mark<Id>;
+static auto rotate(any) -> any;
+
+static auto rotate(empty) -> empty;
+
+// select rotates only insides of selection, not select itself
+template <typename... Content> static auto rotate(select<Content...>) {
+ return select<decltype(rotate(Content{}))...>{};
+}
+
+template <size_t a, size_t b, typename... Content> static auto rotate(repeat<a,b,Content...>) -> decltype(ctre::convert_to_repeat<repeat, a, b>(ctll::rotate(ctll::list<decltype(rotate(Content{}))...>{})));
+template <size_t a, size_t b, typename... Content> static auto rotate(lazy_repeat<a,b,Content...>) -> decltype(ctre::convert_to_repeat<lazy_repeat, a, b>(ctll::rotate(ctll::list<decltype(rotate(Content{}))...>{})));
+template <size_t a, size_t b, typename... Content> static auto rotate(possessive_repeat<a,b,Content...>) -> decltype(ctre::convert_to_repeat<possessive_repeat, a, b>(ctll::rotate(ctll::list<decltype(rotate(Content{}))...>{})));
+
+template <size_t Index, typename... Content> static auto rotate(capture<Index, Content...>) {
+ return ctre::convert_to_capture<Index>(ctll::rotate(ctll::list<decltype(rotate(Content{}))...>{}));
+}
+
+template <size_t Index, typename Name, typename... Content> static auto rotate(capture_with_name<Index, Name, Content...>) {
+ return ctre::convert_to_named_capture<Index, Name>(ctll::rotate(ctll::list<decltype(rotate(Content{}))...>{}));
+}
+
+template <size_t Index> static auto rotate(back_reference<Index>) -> back_reference<Index>;
+template <typename Name> static auto rotate(back_reference_with_name<Name>) -> back_reference_with_name<Name>;
+
+template <typename... Content> static auto rotate(look_start<Content...>) -> look_start<Content...>;
+
+template <auto... Str> static auto rotate(string<Str...>) -> decltype((string<>{} + ... + rotate_value<Str>{}));
+
+template <typename... Content> static auto rotate(sequence<Content...>) {
+ return ctre::convert_to_basic_list<sequence>(ctll::rotate(ctll::list<decltype(rotate(Content{}))...>{}));
+}
+
+// we don't rotate lookaheads
+template <typename... Content> static auto rotate(lookahead_positive<Content...>) -> lookahead_positive<Content...>;
+template <typename... Content> static auto rotate(lookahead_negative<Content...>) -> lookahead_negative<Content...>;
+template <typename... Content> static auto rotate(lookbehind_positive<Content...>) -> lookbehind_positive<Content...>;
+template <typename... Content> static auto rotate(lookbehind_negative<Content...>) -> lookbehind_negative<Content...>;
+
+static auto rotate(atomic_start) -> atomic_start;
+
+template <typename... Content> static auto rotate(atomic_group<Content...>) {
+ return ctre::convert_to_basic_list<atomic_group>(ctll::rotate(ctll::list<decltype(rotate(Content{}))...>{}));
+}
+
+template <typename... Content> static auto rotate(boundary<Content...>) -> boundary<Content...>;
+template <typename... Content> static auto rotate(not_boundary<Content...>) -> not_boundary<Content...>;
+
+static auto rotate(assert_subject_begin) -> assert_subject_begin;
+static auto rotate(assert_subject_end) -> assert_subject_end;
+static auto rotate(assert_subject_end_line) -> assert_subject_end_line;
+static auto rotate(assert_line_begin) -> assert_line_begin;
+static auto rotate(assert_line_end) -> assert_line_end;
+
+};
+
+}
+
+#endif
+
+#ifndef CTRE__ID__HPP
+#define CTRE__ID__HPP
+
+#ifndef CTRE_IN_A_MODULE
+#include <type_traits>
+#endif
+
+namespace ctre {
+
+template <auto... Name> struct id {
+ static constexpr auto name = ctll::fixed_string<sizeof...(Name)>{{Name...}};
+
+ friend constexpr auto operator==(id<Name...>, id<Name...>) noexcept -> std::true_type { return {}; }
+
+ template <auto... Other> friend constexpr auto operator==(id<Name...>, id<Other...>) noexcept -> std::false_type { return {}; }
+
+ template <typename T> friend constexpr auto operator==(id<Name...>, T) noexcept -> std::false_type { return {}; }
+
+ template <typename T> friend constexpr auto operator==(T, id<Name...>) noexcept -> std::false_type { return {}; }
+};
+
+}
+
+#endif
+
+#ifndef CTRE_IN_A_MODULE
+#include <cstdint>
+#include <limits>
+#endif
+
+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>, typename Mode = ctll::list<>> struct pcre_context {
+ using stack_type = Stack;
+ using parameters_type = Parameters;
+ using mode_list = Mode;
+ static constexpr inline auto stack = stack_type();
+ static constexpr inline auto parameters = parameters_type();
+ static constexpr inline auto mode = mode_list();
+ constexpr pcre_context() noexcept { }
+ constexpr pcre_context(Stack, Parameters) noexcept { }
+ constexpr pcre_context(Stack, Parameters, Mode) 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_line_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_line_end(), subject.stack), subject.parameters};
+}
+
+// push_assert_begin
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_subject_begin, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(assert_subject_begin(), subject.stack), subject.parameters};
+}
+
+// push_assert_subject_end
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_subject_end, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(assert_subject_end(), subject.stack), subject.parameters};
+}
+
+// push_assert_subject_end_with_lineend
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_assert_subject_end_with_lineend, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(assert_subject_end_line(), subject.stack), subject.parameters};
+}
+
+#endif
+
+#ifndef CTRE__ACTIONS__ATOMIC_GROUP__HPP
+#define CTRE__ACTIONS__ATOMIC_GROUP__HPP
+
+// atomic start
+template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_atomic, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
+ return pcre_context{ctll::list<atomic_start, Ts...>(), pcre_parameters<Counter>()};
+}
+
+// atomic
+template <auto V, typename Atomic, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_atomic, ctll::term<V>, pcre_context<ctll::list<Atomic, atomic_start, Ts...>, pcre_parameters<Counter>>) {
+ return pcre_context{ctll::list<atomic_group<Atomic>, Ts...>(), pcre_parameters<Counter>()};
+}
+
+// atomic sequence
+template <auto V, typename... Atomic, typename... Ts, size_t Counter> static constexpr auto apply(pcre::make_atomic, ctll::term<V>, pcre_context<ctll::list<sequence<Atomic...>, atomic_start, Ts...>, pcre_parameters<Counter>>) {
+ return pcre_context{ctll::list<atomic_group<Atomic...>, Ts...>(), pcre_parameters<Counter>()};
+}
+
+#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__BOUNDARIES__HPP
+#define CTRE__ACTIONS__BOUNDARIES__HPP
+
+// push_word_boundary
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_word_boundary, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(boundary<word_chars>(), subject.stack), subject.parameters};
+}
+
+// push_not_word_boundary
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::push_not_word_boundary, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(boundary<negative_set<word_chars>>(), subject.stack), subject.parameters};
+}
+
+#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__FUSION__HPP
+#define CTRE__ACTIONS__FUSION__HPP
+
+static constexpr size_t combine_max_repeat_length(size_t A, size_t B) {
+ if (A && B) return A+B;
+ else return 0;
+}
+
+template <size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content> static constexpr auto combine_repeat(repeat<MinA, MaxA, Content...>, repeat<MinB, MaxB, Content...>) {
+ return repeat<MinA + MinB, combine_max_repeat_length(MaxA, MaxB), Content...>();
+}
+
+template <size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content> static constexpr auto combine_repeat(lazy_repeat<MinA, MaxA, Content...>, lazy_repeat<MinB, MaxB, Content...>) {
+ return lazy_repeat<MinA + MinB, combine_max_repeat_length(MaxA, MaxB), Content...>();
+}
+
+template <size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content> static constexpr auto combine_repeat(possessive_repeat<MinA, MaxA, Content...>, possessive_repeat<MinB, MaxB, Content...>) {
+ [[maybe_unused]] constexpr bool first_is_unbounded = (MaxA == 0);
+ [[maybe_unused]] constexpr bool second_is_nonempty = (MinB > 0);
+ [[maybe_unused]] constexpr bool second_can_be_empty = (MinB == 0);
+
+ if constexpr (first_is_unbounded && second_is_nonempty) {
+ // will always reject, but I keep the content, so I have some amount of captures
+ return sequence<reject, Content...>();
+ } else if constexpr (first_is_unbounded) {
+ return possessive_repeat<MinA, MaxA, Content...>();
+ } else if constexpr (second_can_be_empty) {
+ return possessive_repeat<MinA, combine_max_repeat_length(MaxA, MaxB), Content...>();
+ } else {
+ return possessive_repeat<MaxA + MinB, combine_max_repeat_length(MaxA, MaxB), Content...>();
+ }
+}
+
+// concat repeat sequences
+template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<repeat<MinB, MaxB, Content...>, repeat<MinA, MaxA, Content...>, Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(combine_repeat(repeat<MinA, MaxA, Content...>(), repeat<MinB, MaxB, Content...>()), ctll::list<Ts...>()), subject.parameters};
+}
+
+// concat lazy repeat sequences
+template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<lazy_repeat<MinB, MaxB, Content...>, lazy_repeat<MinA, MaxA, Content...>, Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(combine_repeat(lazy_repeat<MinA, MaxA, Content...>(), lazy_repeat<MinB, MaxB, Content...>()), ctll::list<Ts...>()), subject.parameters};
+}
+
+// concat possessive repeat seqeunces
+template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<possessive_repeat<MinB, MaxB, Content...>, possessive_repeat<MinA, MaxA, Content...>, Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(combine_repeat(possessive_repeat<MinA, MaxA, Content...>(), possessive_repeat<MinB, MaxB, Content...>()), ctll::list<Ts...>()), subject.parameters};
+}
+
+// concat repeat sequences into sequence
+template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... As, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<repeat<MinB, MaxB, Content...>, As...>,repeat<MinA, MaxA, Content...>,Ts...>, Parameters> subject) {
+ using result = decltype(combine_repeat(repeat<MinB, MaxB, Content...>(), repeat<MinA, MaxA, Content...>()));
+
+ return pcre_context{ctll::push_front(sequence<result,As...>(), ctll::list<Ts...>()), subject.parameters};
+}
+
+// concat lazy repeat sequences into sequence
+template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... As, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<lazy_repeat<MinB, MaxB, Content...>, As...>,lazy_repeat<MinA, MaxA, Content...>,Ts...>, Parameters> subject) {
+ using result = decltype(combine_repeat(lazy_repeat<MinB, MaxB, Content...>(), lazy_repeat<MinA, MaxA, Content...>()));
+
+ return pcre_context{ctll::push_front(sequence<result,As...>(), ctll::list<Ts...>()), subject.parameters};
+}
+
+// concat possessive repeat sequences into sequence
+template <auto V, size_t MinA, size_t MaxA, size_t MinB, size_t MaxB, typename... Content, typename... As, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<possessive_repeat<MinB, MaxB, Content...>, As...>,possessive_repeat<MinA, MaxA, Content...>,Ts...>, Parameters> subject) {
+ using result = decltype(combine_repeat(possessive_repeat<MinB, MaxB, Content...>(), possessive_repeat<MinA, MaxA, Content...>()));
+
+ return pcre_context{ctll::push_front(sequence<result,As...>(), ctll::list<Ts...>()), 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>()};
+}
+
+// LOOKBEHIND
+
+// lookbehind positive start
+template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookbehind_positive, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
+ return pcre_context{ctll::list<look_start<lookbehind_positive<>>, Ts...>(), pcre_parameters<Counter>()};
+}
+
+// lookbehind 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<lookbehind_positive<>>, Ts...>, pcre_parameters<Counter>>) {
+ return pcre_context{ctll::list<lookbehind_positive<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))>, Ts...>(), pcre_parameters<Counter>()};
+}
+
+// lookbehind 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<lookbehind_positive<>>, Ts...>, pcre_parameters<Counter>>) {
+ using my_lookbehind = decltype(ctre::convert_to_basic_list<lookbehind_positive>(ctll::rotate(ctll::list<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))...>{})));
+ return pcre_context{ctll::list<my_lookbehind, Ts...>(), pcre_parameters<Counter>()};
+}
+
+// lookbehind negative start
+template <auto V, typename... Ts, size_t Counter> static constexpr auto apply(pcre::start_lookbehind_negative, ctll::term<V>, pcre_context<ctll::list<Ts...>, pcre_parameters<Counter>>) {
+ return pcre_context{ctll::list<look_start<lookbehind_negative<>>, Ts...>(), pcre_parameters<Counter>()};
+}
+
+// lookbehind 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<lookbehind_negative<>>, Ts...>, pcre_parameters<Counter>>) {
+ return pcre_context{ctll::list<lookbehind_negative<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))>, Ts...>(), pcre_parameters<Counter>()};
+}
+
+// lookbehind 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<lookbehind_negative<>>, Ts...>, pcre_parameters<Counter>>) {
+ using my_lookbehind = decltype(ctre::convert_to_basic_list<lookbehind_negative>(ctll::rotate(ctll::list<decltype(ctre::rotate_for_lookbehind::rotate(Look{}))...>{})));
+ return pcre_context{ctll::list<my_lookbehind, 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};
+}
+
+// prevent from creating wrapped optionals
+template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<optional<A>, Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(optional<A>(), ctll::list<Ts...>()), subject.parameters};
+}
+
+// in case inner optional is lazy, result should be lazy too
+template <auto V, typename A, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_optional, ctll::term<V>, pcre_context<ctll::list<lazy_optional<A>, Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(lazy_optional<A>(), 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};
+}
+
+// if you already got a lazy optional, make_lazy is no-op
+template <auto V, typename... Subject, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_lazy, ctll::term<V>, pcre_context<ctll::list<lazy_optional<Subject...>, Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(lazy_optional<Subject...>(), 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 char name[sizeof...(Name)]{static_cast<char>(Name)...};
+ constexpr auto p = uni::detail::binary_prop_from_string(get_string_view(name));
+
+ if constexpr (uni::detail::is_unknown(p)) {
+ return ctll::reject{};
+ } else {
+ return pcre_context{ctll::push_front(make_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 char name[sizeof...(Name)]{static_cast<char>(Name)...};
+ constexpr auto p = uni::detail::binary_prop_from_string(get_string_view(name));
+
+ if constexpr (uni::detail::is_unknown(p)) {
+ return ctll::reject{};
+ } else {
+ return pcre_context{ctll::push_front(negate<make_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
+
+#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 A, typename... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<Bs...>,A,Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(sequence<A,Bs...>(), 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 A, auto... Bs, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<string<Bs...>,character<A>,Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(string<A,Bs...>(), ctll::list<Ts...>()), subject.parameters};
+}
+
+// make_sequence (make string in front of different items)
+template <auto V, auto A, auto B, typename... Sq, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<character<B>,Sq...>,character<A>,Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(sequence<string<A,B>,Sq...>(), ctll::list<Ts...>()), subject.parameters};
+}
+// make_sequence (concat string in front of different items)
+template <auto V, auto A, auto... Bs, typename... Sq, typename... Ts, typename Parameters> static constexpr auto apply(pcre::make_sequence, ctll::term<V>, pcre_context<ctll::list<sequence<string<Bs...>,Sq...>,character<A>,Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(sequence<string<A,Bs...>,Sq...>(), 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_empty
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::set_empty, ctll::term<V>, pcre_context<ctll::list<Ts...>, Parameters> subject) {
+ return pcre_context{ctll::push_front(set<>(), 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__MODE__HPP
+#define CTRE__ACTIONS__MODE__HPP
+
+// we need to reset counter and wrap Mode into mode_switch
+template <typename Mode, typename... Ts, typename Parameters> static constexpr auto apply_mode(Mode, ctll::list<Ts...>, Parameters) {
+ return pcre_context<ctll::list<mode_switch<Mode>, Ts...>, Parameters>{};
+}
+
+template <typename Mode, typename... Ts, size_t Id, size_t Counter> static constexpr auto apply_mode(Mode, ctll::list<capture_id<Id>, Ts...>, pcre_parameters<Counter>) {
+ return pcre_context<ctll::list<mode_switch<Mode>, Ts...>, pcre_parameters<Counter-1>>{};
+}
+
+// catch a semantic action into mode
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_case_insensitive mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
+ return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
+}
+
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_case_sensitive mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
+ return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
+}
+
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_singleline mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
+ return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
+}
+
+template <auto V, typename... Ts, typename Parameters> static constexpr auto apply(pcre::mode_multiline mode, ctll::term<V>,pcre_context<ctll::list<Ts...>, Parameters>) {
+ return apply_mode(mode, ctll::list<Ts...>{}, Parameters{});
+}
+
+// to properly reset capture
+
+#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(const flags &, ctll::list<Content...>) noexcept {
+ return false;
+}
+
+template <typename... Content>
+constexpr bool starts_with_anchor(const flags &, ctll::list<assert_subject_begin, Content...>) noexcept {
+ // yes! start subject anchor is here
+ return true;
+}
+
+template <typename... Content>
+constexpr bool starts_with_anchor(const flags & f, ctll::list<assert_line_begin, Content...>) noexcept {
+ // yes! start line anchor is here
+ return !ctre::multiline_mode(f) || starts_with_anchor(f, ctll::list<Content...>{});
+}
+
+template <typename CharLike, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, ctll::list<boundary<CharLike>, Content...>) noexcept {
+ // check if all options starts with anchor or if they are empty, there is an anchor behind them
+ return starts_with_anchor(f, ctll::list<Content...>{});
+}
+
+template <typename... Options, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Options, Content...>{}) && ... && true);
+}
+
+template <typename... Optional, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Optional..., Content...>{}) && starts_with_anchor(f, ctll::list<Content...>{});
+}
+
+template <typename... Optional, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Optional..., Content...>{}) && starts_with_anchor(f, ctll::list<Content...>{});
+}
+
+template <typename... Seq, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Seq..., Content...>{});
+}
+
+template <size_t A, size_t B, typename... Seq, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Seq..., Content...>{});
+}
+
+template <size_t A, size_t B, typename... Seq, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Seq..., Content...>{});
+}
+
+template <size_t A, size_t B, typename... Seq, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Seq..., Content...>{});
+}
+
+template <size_t Index, typename... Seq, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Seq..., Content...>{});
+}
+
+template <size_t Index, typename... Seq, typename... Content>
+constexpr bool starts_with_anchor(const flags & f, 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(f, ctll::list<Seq..., Content...>{});
+}
+
+}
+
+#endif
+
+#ifndef CTRE__RETURN_TYPE__HPP
+#define CTRE__RETURN_TYPE__HPP
+
+#ifndef CTRE__UTF8__HPP
+#define CTRE__UTF8__HPP
+
+#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811
+
+#ifndef CTRE_IN_A_MODULE
+#include <string_view>
+#include <iterator>
+#endif
+
+#if defined(__cpp_char8_t) &&__cpp_lib_char8_t >= 201811L
+#define CTRE_ENABLE_UTF8_RANGE
+#endif
+
+#if defined(__cpp_impl_three_way_comparison) && (__cpp_impl_three_way_comparison >= 201907L)
+#define CTRE_NO_NEED_FOR_ADDITIONAL_COMPARISONS
+#endif
+
+namespace ctre {
+
+struct utf8_iterator {
+ using self_type = utf8_iterator;
+ using value_type = char8_t;
+ using reference = char8_t;
+ using pointer = const char8_t *;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = int;
+
+ struct sentinel {
+ // this is here only because I want to support std::make_reverse_iterator
+ using self_type = sentinel;
+ using value_type = char8_t;
+ using reference = char8_t &;
+ using pointer = const char8_t *;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = int;
+
+ // it's just sentinel it won't be ever called
+ auto operator++() noexcept -> self_type &;
+ auto operator++(int) noexcept -> self_type;
+ auto operator--() noexcept -> self_type &;
+ auto operator--(int) noexcept -> self_type;
+ friend auto operator==(self_type, self_type) noexcept -> bool;
+ auto operator*() noexcept -> reference;
+
+ friend constexpr auto operator==(self_type, const char8_t * other_ptr) noexcept {
+ return *other_ptr == char8_t{0};
+ }
+#ifndef CTRE_NO_NEED_FOR_ADDITIONAL_COMPARISONS
+ friend constexpr auto operator!=(self_type, const char8_t * other_ptr) noexcept {
+ return *other_ptr != char8_t{0};
+ }
+
+ friend constexpr auto operator==(const char8_t * other_ptr, self_type) noexcept {
+ return *other_ptr == char8_t{0};
+ }
+
+ friend constexpr auto operator!=(const char8_t * other_ptr, self_type) noexcept {
+ return *other_ptr != char8_t{0};
+ }
+#endif
+ };
+
+ const char8_t * ptr{nullptr};
+ const char8_t * end{nullptr};
+#ifndef CTRE_NO_NEED_FOR_ADDITIONAL_COMPARISONS
+ constexpr friend bool operator!=(const utf8_iterator & lhs, sentinel) {
+ return lhs.ptr < lhs.end;
+ }
+
+ constexpr friend bool operator!=(const utf8_iterator & lhs, const char8_t * rhs) {
+ return lhs.ptr != rhs;
+ }
+
+ constexpr friend bool operator!=(const utf8_iterator & lhs, const utf8_iterator & rhs) {
+ return lhs.ptr != rhs.ptr;
+ }
+#endif
+ constexpr friend bool operator==(const utf8_iterator & lhs, sentinel) {
+ return lhs.ptr >= lhs.end;
+ }
+
+ constexpr friend bool operator==(const utf8_iterator & lhs, const char8_t * rhs) {
+ return lhs.ptr == rhs;
+ }
+
+ constexpr friend bool operator==(const utf8_iterator & lhs, const utf8_iterator & rhs) {
+ return lhs.ptr == rhs.ptr;
+ }
+
+#ifndef CTRE_NO_NEED_FOR_ADDITIONAL_COMPARISONS
+ constexpr friend bool operator!=(sentinel, const utf8_iterator & rhs) {
+ return rhs.ptr < rhs.end;
+ }
+
+ constexpr friend bool operator!=(const char8_t * lhs, const utf8_iterator & rhs) {
+ return lhs == rhs.ptr;
+ }
+
+ constexpr friend bool operator==(sentinel, const utf8_iterator & rhs) {
+ return rhs.ptr >= rhs.end;
+ }
+
+ constexpr friend bool operator==(const char8_t * lhs, const utf8_iterator & rhs) {
+ return lhs == rhs.ptr;
+ }
+#endif
+
+
+ constexpr utf8_iterator & operator=(const char8_t * rhs) {
+ ptr = rhs;
+ return *this;
+ }
+
+ constexpr operator const char8_t *() const noexcept {
+ return ptr;
+ }
+
+ constexpr utf8_iterator & operator++() noexcept {
+ // the contant is mapping from first 5 bits of first code unit to length of UTF8 code point -1
+ // xxxxx -> yy (5 bits to 2 bits)
+ // 5 bits are 32 combination, and for each I need 2 bits, hence 64 bit constant
+ // (*ptr >> 2) & 0b111110 look at the left 5 bits ignoring the least significant
+ // & 0b11u selects only needed two bits
+ // +1 because each iteration is at least one code unit forward
+
+ ptr += ((0x3A55000000000000ull >> ((*ptr >> 2) & 0b111110u)) & 0b11u) + 1;
+ return *this;
+ }
+
+ constexpr utf8_iterator & operator--() noexcept {
+ if (ptr > end) {
+ ptr = end-1;
+ } else {
+ --ptr;
+ }
+
+ while ((*ptr & 0b11000000u) == 0b10'000000) {
+ --ptr;
+ }
+
+ return *this;
+ }
+
+ constexpr utf8_iterator operator--(int) noexcept {
+ auto self = *this;
+ this->operator--();
+ return self;
+ }
+
+ constexpr utf8_iterator operator++(int) noexcept {
+ auto self = *this;
+ this->operator++();
+ return self;
+ }
+
+ constexpr utf8_iterator operator+(unsigned step) const noexcept {
+ utf8_iterator result = *this;
+ while (step > 0) {
+ ++result;
+ step--;
+ }
+ return result;
+ }
+
+ constexpr utf8_iterator operator-(unsigned step) const noexcept {
+ utf8_iterator result = *this;
+ while (step > 0) {
+ --result;
+ step--;
+ }
+ return result;
+ }
+
+ constexpr char32_t operator*() const noexcept {
+ constexpr char32_t mojibake = 0xFFFDull;
+
+ // quickpath
+ if (!(*ptr & 0b1000'0000u)) CTRE_LIKELY {
+ return static_cast<char32_t>(*ptr);
+ }
+
+ // calculate length based on first 5 bits
+ const unsigned length = ((0x3A55000000000000ull >> ((*ptr >> 2) & 0b111110u)) & 0b11u);
+
+ // actual length is number + 1 bytes
+
+ // length 0 here means it's a bad front unit
+ if (!length) CTRE_UNLIKELY {
+ return mojibake;
+ }
+
+ // if part of the utf-8 sequence is past the end
+ if (((ptr + length) >= end)) CTRE_UNLIKELY {
+ return mojibake;
+ }
+
+ if ((ptr[1] & 0b1100'0000u) != 0b1000'0000) CTRE_UNLIKELY {
+ return mojibake;
+ }
+
+ const char8_t mask = static_cast<char8_t>(0b0011'1111u >> length);
+
+ // length = 1 (2 bytes) mask = 0b0001'1111u
+ // length = 2 (3 bytes) mask = 0b0000'1111u
+ // length = 3 (4 bytes) mask = 0b0000'0111u
+
+ // remove utf8 front bits, get only significant part
+ // and add first trailing unit
+
+ char32_t result = static_cast<char32_t>((ptr[0] & mask) << 6u) | (ptr[1] & 0b0011'1111u);
+
+ // add rest of trailing units
+ if (length == 1) CTRE_LIKELY {
+ return result;
+ }
+
+ if ((ptr[2] & 0b1100'0000u) != 0b1000'0000) CTRE_UNLIKELY {
+ return mojibake;
+ }
+
+ result = (result << 6) | (ptr[2] & 0b0011'1111u);
+
+ if (length == 2) CTRE_LIKELY {
+ return result;
+ }
+
+ if ((ptr[3] & 0b1100'0000u) != 0b1000'0000) CTRE_UNLIKELY {
+ return mojibake;
+ }
+
+ return (result << 6) | (ptr[3] & 0b0011'1111u);
+ }
+};
+
+#ifdef CTRE_ENABLE_UTF8_RANGE
+struct utf8_range {
+ std::u8string_view range;
+ constexpr utf8_range(std::u8string_view r) noexcept: range{r} { }
+
+ constexpr auto begin() const noexcept {
+ return utf8_iterator{range.data(), range.data() + range.size()};
+ }
+ constexpr auto end() const noexcept {
+ return utf8_iterator::sentinel{};
+ }
+};
+#endif
+
+}
+
+#endif
+
+#endif
+
+#ifndef CTRE_IN_A_MODULE
+#include <type_traits>
+#include <tuple>
+#include <string_view>
+#include <string>
+#include <iterator>
+#include <optional>
+#ifdef _MSC_VER
+#include <memory>
+#endif
+#include <iosfwd>
+#if __has_include(<charconv>)
+#include <charconv>
+#endif
+#if defined(__cpp_concepts) && __cpp_concepts >= 202002L
+#include <concepts>
+#endif
+#endif
+
+namespace ctre {
+
+constexpr auto is_random_accessible_f(const std::random_access_iterator_tag &) { return std::true_type{}; }
+constexpr auto is_random_accessible_f(...) { return std::false_type{}; }
+
+template <typename T> constexpr auto is_reverse_iterator_f(const std::reverse_iterator<T> &) { return std::true_type{}; }
+constexpr auto is_reverse_iterator_f(...) { return std::false_type{}; }
+
+template <typename T> constexpr bool is_random_accessible = decltype(is_random_accessible_f(std::declval<const T &>())){};
+template <typename T> constexpr bool is_reverse_iterator = decltype(is_reverse_iterator_f(std::declval<const T &>())){};
+
+struct not_matched_tag_t { };
+
+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 explicit CTRE_FORCE_INLINE operator bool() const noexcept {
+ return _matched;
+ }
+
+ template <typename It = Iterator> constexpr CTRE_FORCE_INLINE const auto * data_unsafe() const noexcept {
+ static_assert(!is_reverse_iterator<It>, "Iterator in your capture must not be reverse!");
+
+#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811
+ if constexpr (std::is_same_v<Iterator, utf8_iterator>) {
+ return _begin.ptr;
+ } else { // I'm doing this to avoid warning about dead code
+#endif
+
+#ifdef _MSC_VER
+ return std::to_address(_begin); // I'm enabling this only for MSVC for now, as some clang old versions with various libraries (random combinations) has different problems
+#else
+ return &*_begin;
+#endif
+
+#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811
+ }
+#endif
+ }
+
+ template <typename It = Iterator> constexpr CTRE_FORCE_INLINE const auto * data() const noexcept {
+ constexpr bool must_be_contiguous_nonreverse_iterator = is_random_accessible<typename std::iterator_traits<It>::iterator_category> && !is_reverse_iterator<It>;
+
+ static_assert(must_be_contiguous_nonreverse_iterator, "To access result as a pointer you need to provide a random access iterator/range to regex (which is not reverse iterator based).");
+
+ return data_unsafe();
+ }
+
+ constexpr CTRE_FORCE_INLINE auto size() const noexcept {
+ return static_cast<size_t>(std::distance(begin(), end()));
+ }
+
+ constexpr CTRE_FORCE_INLINE size_t unit_size() const noexcept {
+#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811
+ if constexpr (std::is_same_v<Iterator, utf8_iterator>) {
+ return static_cast<size_t>(std::distance(_begin.ptr, _end.ptr));
+ } else {
+ return static_cast<size_t>(std::distance(begin(), end()));
+ }
+#else
+ return static_cast<size_t>(std::distance(begin(), end()));
+#endif
+ }
+
+#if __has_include(<charconv>)
+ template <typename R = int, typename... Ts> constexpr CTRE_FORCE_INLINE auto to_number(Ts && ... args) const noexcept -> R {
+ R result{0};
+ const auto view = to_view();
+ std::from_chars(view.data(), view.data() + view.size(), result, std::forward<Ts>(args)...);
+ return result;
+ }
+
+ template <typename R = int, typename... Ts> constexpr CTRE_FORCE_INLINE auto to_optional_number(Ts && ... args) const noexcept -> std::optional<R> {
+ if (!static_cast<bool>(*this)) {
+ return std::nullopt;
+ }
+
+ return to_number<R>(std::forward<Ts>(args)...);
+ }
+#endif
+
+ template <typename It = Iterator> constexpr CTRE_FORCE_INLINE auto to_view() const noexcept {
+ // random access, because C++ (waving hands around)
+ constexpr bool must_be_nonreverse_contiguous_iterator = is_random_accessible<typename std::iterator_traits<std::remove_const_t<It>>::iterator_category> && !is_reverse_iterator<It>;
+
+ static_assert(must_be_nonreverse_contiguous_iterator, "To convert capture into a basic_string_view you need to provide a pointer or a contiguous non-reverse iterator/range to regex.");
+
+ return std::basic_string_view<char_type>(data_unsafe(), static_cast<size_t>(unit_size()));
+ }
+
+ constexpr CTRE_FORCE_INLINE auto view() const noexcept {
+ return to_view();
+ }
+
+ template <typename It = Iterator> constexpr CTRE_FORCE_INLINE auto to_optional_view() const noexcept -> std::optional<std::basic_string_view<char_type>> {
+ if (!static_cast<bool>(*this)) {
+ return std::nullopt;
+ }
+ return to_view();
+ }
+
+ constexpr CTRE_FORCE_INLINE std::basic_string<char_type> to_string() const noexcept {
+#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811
+ if constexpr (std::is_same_v<Iterator, utf8_iterator>) {
+ return std::basic_string<char_type>(data_unsafe(), static_cast<size_t>(unit_size()));
+ } else {
+ return std::basic_string<char_type>(begin(), end());
+ }
+#else
+ return std::basic_string<char_type>(begin(), end());
+#endif
+ }
+
+ constexpr CTRE_FORCE_INLINE auto str() const noexcept {
+ return to_string();
+ }
+
+ template <typename It = Iterator> constexpr CTRE_FORCE_INLINE auto to_optional_string() const noexcept -> std::optional<std::basic_string<char_type>> {
+ if (!static_cast<bool>(*this)) {
+ return std::nullopt;
+ }
+ return to_string();
+ }
+
+ 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 operator std::optional<std::basic_string_view<char_type>>() const noexcept {
+ return to_optional_view();
+ }
+
+ constexpr CTRE_FORCE_INLINE explicit operator std::optional<std::basic_string<char_type>>() const noexcept {
+ return to_optional_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;
+ }
+ friend CTRE_FORCE_INLINE std::ostream & operator<<(std::ostream & str, const storage & rhs) {
+ return str << rhs.view();
+ }
+ };
+};
+
+#if defined(__cpp_concepts) && __cpp_concepts >= 202002L
+template <typename T> concept capture_group = requires(const T & cap) {
+ { T::get_id() } -> std::same_as<size_t>;
+ { cap.view() };
+ { cap.str() };
+ { cap.to_string() };
+ { cap.to_view() };
+ { cap.unit_size() } -> std::same_as<size_t>;
+ { cap.size() } -> std::same_as<size_t>;
+ { static_cast<bool>(cap) };
+ { cap.data() };
+ { cap.data_unsafe() };
+ { cap.begin() };
+ { cap.end() };
+};
+#endif
+
+struct capture_not_exists_tag { };
+
+constexpr 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 CTRE_CNTTP_COMPILER_CHECK
+ 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 CTRE_CNTTP_COMPILER_CHECK
+ 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 CTRE_CNTTP_COMPILER_CHECK
+ 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 CTRE_CNTTP_COMPILER_CHECK
+ 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> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
+ constexpr bool capture_of_provided_id_must_exists = decltype(_captures)::template exists<Id>();
+ static_assert(capture_of_provided_id_must_exists);
+
+ if constexpr (capture_of_provided_id_must_exists) {
+ return _captures.template select<Id>();
+ } else {
+ return false;
+ }
+ }
+ template <typename Name> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
+ constexpr bool capture_of_provided_name_must_exists = decltype(_captures)::template exists<Name>();
+ static_assert(capture_of_provided_name_must_exists);
+
+ if constexpr (capture_of_provided_name_must_exists) {
+ return _captures.template select<Name>();
+ } else {
+ return false;
+ }
+ }
+#if CTRE_CNTTP_COMPILER_CHECK
+ template <ctll::fixed_string Name> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
+#else
+ template <const auto & Name> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
+#endif
+ constexpr bool capture_of_provided_name_must_exists = decltype(_captures)::template exists<Name>();
+ static_assert(capture_of_provided_name_must_exists);
+
+ if constexpr (capture_of_provided_name_must_exists) {
+ return _captures.template select<Name>();
+ } else {
+ return false;
+ }
+ }
+ 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>());
+ }
+
+ // implicit conversions
+ 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 operator std::optional<std::basic_string_view<char_type>>() const noexcept {
+ return to_optional_view();
+ }
+
+ constexpr CTRE_FORCE_INLINE explicit operator std::optional<std::basic_string<char_type>>() const noexcept {
+ return to_optional_string();
+ }
+
+ // conversion to numbers
+#if __has_include(<charconv>)
+ template <typename R = int, typename... Ts> constexpr CTRE_FORCE_INLINE auto to_number(Ts && ... args) const noexcept -> R {
+ return _captures.template select<0>().template to_number<R>(std::forward<Ts>(args)...);
+ }
+
+ template <typename R = int, typename... Ts> constexpr CTRE_FORCE_INLINE auto to_optional_number(Ts && ... args) const noexcept -> std::optional<R> {
+ return _captures.template select<0>().template to_optional_number<R>(std::forward<Ts>(args)...);
+ }
+#endif
+
+ // conversion to basic_string_view
+ constexpr CTRE_FORCE_INLINE auto to_view() const noexcept {
+ return _captures.template select<0>().to_view();
+ }
+
+ constexpr CTRE_FORCE_INLINE auto view() const noexcept {
+ return _captures.template select<0>().view(); // this should be deprecated (??)
+ }
+
+ constexpr CTRE_FORCE_INLINE auto to_optional_view() const noexcept {
+ return _captures.template select<0>().to_optional_view();
+ }
+
+ // conversion to basic_string
+ constexpr CTRE_FORCE_INLINE auto to_string() const noexcept {
+ return _captures.template select<0>().to_string();
+ }
+
+ constexpr CTRE_FORCE_INLINE auto str() const noexcept {
+ return _captures.template select<0>().to_string(); // this should be deprecated (??)
+ }
+
+ constexpr CTRE_FORCE_INLINE auto to_optional_string() const noexcept {
+ return _captures.template select<0>().to_optional_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;
+ }
+ constexpr auto begin() const noexcept {
+ return _captures.template select<0>().begin();
+ }
+ constexpr auto end() const noexcept {
+ return _captures.template select<0>().end();
+ }
+ 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;
+ }
+ friend CTRE_FORCE_INLINE std::ostream & operator<<(std::ostream & str, const regex_results & rhs) {
+#ifdef CTRE_IN_A_MODULE
+ auto view = rhs.view();
+ str.write(view.data(), view.size());
+ return str;
+#else
+ return str << rhs.view();
+#endif
+ }
+};
+
+template <size_t Id, typename Iterator, typename... Captures> constexpr auto get(const regex_results<Iterator, Captures...> & results) noexcept {
+ return results.template get<Id>();
+}
+
+template <typename Iterator, typename... Captures> regex_results(Iterator, ctll::list<Captures...>) -> regex_results<Iterator, Captures...>;
+
+template <typename> struct is_regex_results_t: std::false_type { };
+
+template <typename Iterator, typename... Captures> struct is_regex_results_t<regex_results<Iterator, Captures...>>: std::true_type { };
+
+template <typename T> constexpr bool is_regex_results_v = is_regex_results_t<T>();
+
+#if defined(__cpp_concepts) && __cpp_concepts >= 201907L
+template <typename T> concept capture_groups = is_regex_results_v<T>;
+#endif
+
+template <typename ResultIterator, typename Pattern> using return_type = decltype(regex_results(std::declval<ResultIterator>(), find_captures(Pattern{})));
+
+}
+
+// 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 {
+
+CTRE_EXPORT template <typename Pattern> constexpr auto find_captures(Pattern) noexcept {
+ return find_captures(ctll::list<Pattern>(), ctll::list<>());
+}
+
+CTRE_EXPORT template <typename... Output> constexpr auto find_captures(ctll::list<>, ctll::list<Output...> output) noexcept {
+ return output;
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<empty, Tail...>, Output output) noexcept {
+ return find_captures(ctll::list<Tail...>(), output);
+}
+
+CTRE_EXPORT template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<assert_subject_begin, Tail...>, Output output) noexcept {
+ return find_captures(ctll::list<Tail...>(), output);
+}
+
+CTRE_EXPORT template <typename... Tail, typename Output> constexpr auto find_captures(ctll::list<assert_subject_end, Tail...>, Output output) noexcept {
+ return find_captures(ctll::list<Tail...>(), output);
+}
+
+// , typename = std::enable_if_t<(MatchesCharacter<CharacterLike>::template value<char>)
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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);
+}
+
+CTRE_EXPORT 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>>());
+}
+
+CTRE_EXPORT 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...>{});
+}
+
+// boundary
+template <typename... Content, typename CharLike, typename... Tail>
+constexpr auto first(ctll::list<Content...> l, ctll::list<boundary<CharLike>, Tail...>) noexcept {
+ return first(l, ctll::list<Tail...>{});
+}
+
+// asserts
+template <typename... Content, typename... Tail>
+constexpr auto first(ctll::list<Content...> l, ctll::list<assert_subject_begin, Tail...>) noexcept {
+ return first(l, ctll::list<Tail...>{});
+}
+
+template <typename... Content, typename... Tail>
+constexpr auto first(ctll::list<Content...> l, ctll::list<assert_subject_end, Tail...>) noexcept {
+ return l;
+}
+
+template <typename... Content, typename... Tail>
+constexpr auto first(ctll::list<Content...> l, ctll::list<assert_subject_end_line, Tail...>) noexcept {
+ // FIXME allow endline here
+ return l;
+}
+
+template <typename... Content, typename... Tail>
+constexpr auto first(ctll::list<Content...> l, ctll::list<assert_line_begin, Tail...>) noexcept {
+ // FIXME line begin is a bit different than subject begin
+ return first(l, ctll::list<Tail...>{});
+}
+
+template <typename... Content, typename... Tail>
+constexpr auto first(ctll::list<Content...> l, ctll::list<assert_line_end, Tail...>) noexcept {
+ // FIXME line end is a bit different than subject begin
+ 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...>{});
+}
+
+// atomic group
+template <typename... Content, typename... Seq, typename... Tail>
+constexpr auto first(ctll::list<Content...> l, ctll::list<atomic_group<Seq...>, Tail...>) noexcept {
+ return first(l, ctll::list<possessive_repeat<1, 1, 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>{};
+}
+
+// lookbehind_negative TODO fixme
+template <typename... Content, typename... Seq, typename... Tail>
+constexpr auto first(ctll::list<Content...>, ctll::list<lookbehind_negative<Seq...>, Tail...>) noexcept {
+ return ctll::list<can_be_anything>{};
+}
+
+// lookbehind_positive
+template <typename... Content, typename... Seq, typename... Tail>
+constexpr auto first(ctll::list<Content...>, ctll::list<lookbehind_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;
+}
+
+// unicode property => anything
+template <typename... Content, typename PropertyType, PropertyType Property, typename... Tail>
+constexpr auto first(ctll::list<Content...>, ctll::list<ctre::binary_property<PropertyType, Property>, Tail...>) noexcept {
+ return ctll::list<can_be_anything>{};
+}
+
+template <typename... Content, typename PropertyType, PropertyType Property, auto Value, typename... Tail>
+constexpr auto first(ctll::list<Content...>, ctll::list<ctre::property<PropertyType, Property, Value>, Tail...>) noexcept {
+ return ctll::list<can_be_anything>{};
+}
+
+// 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 + calculate_size_of_first(ctre::set<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 PropertyType, PropertyType Property, typename CB>
+constexpr auto negative_helper(ctre::binary_property<PropertyType, Property>, CB &&, int64_t start) {
+ return start;
+}
+
+template <typename PropertyType, PropertyType Property, auto Value, typename CB>
+constexpr auto negative_helper(ctre::property<PropertyType, Property, Value>, 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;
+ auto count = std::distance(first, last);
+ while (count != 0) {
+ it = first;
+ auto 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 (const 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 PropertyType, PropertyType Property>
+ constexpr bool check(ctre::binary_property<PropertyType, Property>) {
+ return check(can_be_anything{});
+ }
+
+ template <typename PropertyType, PropertyType Property, auto Value>
+ constexpr bool check(ctre::property<PropertyType, Property, Value>) {
+ return check(can_be_anything{});
+ }
+ 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(...) {
+ points[0].low = (std::numeric_limits<int64_t>::min)();
+ points[0].high = (std::numeric_limits<int64_t>::max)();
+ used = 1;
+ }
+ 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
+
+#ifndef CTRE_IN_A_MODULE
+#include <iterator>
+#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([[maybe_unused]] size_t i) noexcept {
+ if constexpr (Limit == 0) {
+ // infinite
+ return true;
+ } else {
+ return i < Limit;
+ }
+}
+
+template <size_t Limit> constexpr CTRE_FORCE_INLINE bool less_than([[maybe_unused]] size_t i) noexcept {
+ if constexpr (Limit == 0) {
+ // infinite
+ return false;
+ } else {
+ return i < Limit;
+ }
+}
+
+constexpr bool is_bidirectional(const std::bidirectional_iterator_tag &) { return true; }
+constexpr bool is_bidirectional(...) { return false; }
+
+// sink for making the errors shorter
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R, ...) noexcept {
+ return not_matched;
+}
+
+// if we found "accept" object on stack => ACCEPT
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R captures, ctll::list<accept>) noexcept {
+ return captures.matched();
+}
+
+// if we found "reject" object on stack => REJECT
+template <typename R, typename... Rest, typename BeginIterator, typename Iterator, typename EndIterator>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R, ctll::list<reject, Rest...>) noexcept {
+ return not_matched;
+}
+
+// mark start of outer capture
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<start_mark, Tail...>) noexcept {
+ return evaluate(begin, current, last, f, captures.set_start_mark(current), ctll::list<Tail...>());
+}
+
+// mark end of outer capture
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<end_mark, Tail...>) noexcept {
+ return evaluate(begin, current, last, f, captures.set_end_mark(current), ctll::list<Tail...>());
+}
+
+// mark end of cycle
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator current, const EndIterator, [[maybe_unused]] const flags & f, R captures, ctll::list<end_cycle_mark>) noexcept {
+ if (cannot_be_empty_match(f)) {
+ return not_matched;
+ }
+
+ return captures.set_end_mark(current).matched();
+}
+
+// matching everything which behave as a one character matcher
+
+template <typename R, typename BeginIterator, 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 BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<CharacterLike, Tail...>) noexcept {
+ if (current == last) return not_matched;
+ if (!CharacterLike::match_char(*current, f)) return not_matched;
+
+ return evaluate(begin, ++current, last, consumed_something(f), captures, ctll::list<Tail...>());
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<any, Tail...>) noexcept {
+ if (current == last) return not_matched;
+
+ if (multiline_mode(f)) {
+ // TODO add support for different line ending and unicode (in a future unicode mode)
+ if (*current == '\n') return not_matched;
+ }
+ return evaluate(begin, ++current, last, consumed_something(f), captures, ctll::list<Tail...>());
+}
+
+// matching strings in patterns
+template <auto... String, typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE bool match_string([[maybe_unused]] Iterator & current, [[maybe_unused]] const EndIterator last, [[maybe_unused]] const flags & f) {
+ return ((current != last && character<String>::match_char(*current++, f)) && ... && true);
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, auto... String, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<string<String...>, Tail...>) noexcept {
+ if (!match_string<String...>(current, last, f)) {
+ return not_matched;
+ }
+
+ return evaluate(begin, current, last, consumed_something(f, sizeof...(String) > 0), captures, ctll::list<Tail...>());
+}
+
+// matching select in patterns
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename HeadOptions, typename... TailOptions, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<select<HeadOptions, TailOptions...>, Tail...>) noexcept {
+ if (auto r = evaluate(begin, current, last, f, captures, ctll::list<HeadOptions, Tail...>())) {
+ return r;
+ } else {
+ return evaluate(begin, current, last, f, captures, ctll::list<select<TailOptions...>, Tail...>());
+ }
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R, ctll::list<select<>, Tail...>) noexcept {
+ // no previous option was matched => REJECT
+ return not_matched;
+}
+
+// matching sequence in patterns
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename HeadContent, typename... TailContent, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<sequence<HeadContent, TailContent...>, Tail...>) noexcept {
+ if constexpr (sizeof...(TailContent) > 0) {
+ return evaluate(begin, current, last, f, captures, ctll::list<HeadContent, sequence<TailContent...>, Tail...>());
+ } else {
+ return evaluate(begin, current, last, f, captures, ctll::list<HeadContent, Tail...>());
+ }
+}
+
+// matching empty in patterns
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<empty, Tail...>) noexcept {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+}
+
+// matching asserts
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_subject_begin, Tail...>) noexcept {
+ if (begin != current) {
+ return not_matched;
+ }
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_subject_end, Tail...>) noexcept {
+ if (last != current) {
+ return not_matched;
+ }
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_subject_end_line, Tail...>) noexcept {
+ if (multiline_mode(f)) {
+ if (last == current) {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else if (*current == '\n' && std::next(current) == last) {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else {
+ return not_matched;
+ }
+ } else {
+ if (last != current) {
+ return not_matched;
+ }
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ }
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_line_begin, Tail...>) noexcept {
+ if (multiline_mode(f)) {
+ if (begin == current) {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else if (*std::prev(current) == '\n') {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else {
+ return not_matched;
+ }
+ } else {
+ if (begin != current) {
+ return not_matched;
+ }
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ }
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<assert_line_end, Tail...>) noexcept {
+ if (multiline_mode(f)) {
+ if (last == current) {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else if (*current == '\n') {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else {
+ return not_matched;
+ }
+ }
+
+ // TODO properly match line end
+ if (last != current) {
+ return not_matched;
+ }
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+}
+
+// matching boundary
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename CharacterLike, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<boundary<CharacterLike>, Tail...>) noexcept {
+
+ // reason why I need bidirectional iterators or some clever hack
+ bool before = false;
+ bool after = false;
+
+ static_assert(is_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "To use boundary in regex you need to provide bidirectional iterator or range.");
+
+ if (last != current) {
+ after = CharacterLike::match_char(*current, f);
+ }
+ if (begin != current) {
+ before = CharacterLike::match_char(*std::prev(current), f);
+ }
+
+ if (before == after) return not_matched;
+
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+}
+
+// matching not_boundary
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename CharacterLike, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<not_boundary<CharacterLike>, Tail...>) noexcept {
+
+ // reason why I need bidirectional iterators or some clever hack
+ bool before = false;
+ bool after = false;
+
+ static_assert(is_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "To use boundary in regex you need to provide bidirectional iterator or range.");
+
+ if (last != current) {
+ after = CharacterLike::match_char(*current, f);
+ }
+ if (begin != current) {
+ before = CharacterLike::match_char(*std::prev(current), f);
+ }
+
+ if (before != after) return not_matched;
+
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+}
+
+// lazy repeat
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<lazy_repeat<A,B,Content...>, Tail...>) noexcept {
+
+ if constexpr (B != 0 && A > B) {
+ return not_matched;
+ } else {
+ const Iterator backup_current = current;
+
+ size_t i{0};
+
+ while (less_than<A>(i)) {
+ auto outer_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
+
+ if (!outer_result) return not_matched;
+
+ captures = outer_result.unmatch();
+ current = outer_result.get_end_position();
+
+ ++i;
+ }
+
+ if (auto outer_result = evaluate(begin, current, last, consumed_something(f, backup_current != current), captures, ctll::list<Tail...>())) {
+ return outer_result;
+ }
+
+ while (less_than_or_infinite<B>(i)) {
+ auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
+
+ if (!inner_result) return not_matched;
+
+ auto outer_result = evaluate(begin, inner_result.get_end_position(), last, consumed_something(f), inner_result.unmatch(), ctll::list<Tail...>());
+
+ if (outer_result) {
+ return outer_result;
+ }
+
+ captures = inner_result.unmatch();
+ current = inner_result.get_end_position();
+
+ ++i;
+ }
+
+ // rest of regex
+ return evaluate(begin, current, last, consumed_something(f), captures, ctll::list<Tail...>());
+ }
+}
+
+// possessive repeat
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<possessive_repeat<A,B,Content...>, Tail...>) noexcept {
+
+ if constexpr ((B != 0) && (A > B)) {
+ return not_matched;
+ } else {
+ const auto backup_current = current;
+
+ for (size_t i{0}; less_than_or_infinite<B>(i); ++i) {
+ // try as many of inner as possible and then try outer once
+ auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
+
+ if (!inner_result) {
+ if (!less_than<A>(i)) break;
+ return not_matched;
+ }
+
+ captures = inner_result.unmatch();
+ current = inner_result.get_end_position();
+ }
+
+ return evaluate(begin, current, last, consumed_something(f, backup_current != current), captures, ctll::list<Tail...>());
+ }
+}
+
+// (gready) repeat
+template <typename R, typename BeginIterator, 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 BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<repeat<A,B,Content...>, Tail...> stack) noexcept {
+#else
+constexpr inline R evaluate_recursive(size_t i, const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, ctll::list<repeat<A,B,Content...>, Tail...> stack) noexcept {
+#endif
+ if (less_than_or_infinite<B>(i)) {
+
+ // a*ab
+ // aab
+
+ if (auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<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
+ auto tmp_current = current;
+ tmp_current = inner_result.get_end_position();
+ #ifdef CTRE_MSVC_GREEDY_WORKAROUND
+ evaluate_recursive(result, i+1, begin, tmp_current, last, f, inner_result.unmatch(), stack);
+ if (result) {
+ return;
+ }
+ #else
+ if (auto rec_result = evaluate_recursive(i+1, begin, tmp_current, last, f, inner_result.unmatch(), stack)) {
+ return rec_result;
+ }
+ #endif
+ }
+ }
+ #ifdef CTRE_MSVC_GREEDY_WORKAROUND
+ result = evaluate(begin, current, last, consumed_something(f), captures, ctll::list<Tail...>());
+ #else
+ return evaluate(begin, current, last, consumed_something(f), captures, ctll::list<Tail...>());
+ #endif
+}
+
+// (greedy) repeat
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t A, size_t B, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, [[maybe_unused]] const flags & f, R captures, [[maybe_unused]] ctll::list<repeat<A,B,Content...>, Tail...> stack) {
+
+ if constexpr ((B != 0) && (A > B)) {
+ return not_matched;
+ }
+
+#ifndef CTRE_DISABLE_GREEDY_OPT
+ else if constexpr (!collides(calculate_first(Content{}...), calculate_first(Tail{}...))) {
+ return evaluate(begin, current, last, f, captures, ctll::list<possessive_repeat<A,B,Content...>, Tail...>());
+ }
+#endif
+ else {
+ // A..B
+ size_t i{0};
+ while (less_than<A>(i)) {
+ auto inner_result = evaluate(begin, current, last, not_empty_match(f), captures, ctll::list<Content..., end_cycle_mark>());
+
+ if (!inner_result) return not_matched;
+
+ captures = inner_result.unmatch();
+ current = inner_result.get_end_position();
+
+ ++i;
+ }
+
+#ifdef CTRE_MSVC_GREEDY_WORKAROUND
+ R result;
+ evaluate_recursive(result, i, begin, current, last, f, captures, stack);
+ return result;
+#else
+ return evaluate_recursive(i, begin, current, last, f, captures, stack);
+#endif
+ }
+
+}
+
+// capture (numeric ID)
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t Id, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<capture<Id, Content...>, Tail...>) noexcept {
+ return evaluate(begin, current, last, f, 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 BeginIterator, typename Iterator, typename EndIterator, size_t Id, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<numeric_mark<Id>, Tail...>) noexcept {
+ return evaluate(begin, current, last, f, captures.template end_capture<Id>(current), ctll::list<Tail...>());
+}
+
+// capture (string ID)
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, size_t Id, typename Name, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<capture_with_name<Id, Name, Content...>, Tail...>) noexcept {
+ return evaluate(begin, current, last, f, captures.template start_capture<Id>(current), ctll::list<sequence<Content...>, numeric_mark<Id>, Tail...>());
+}
+
+// backreference support (match agains content of iterators)
+template <typename Iterator> struct string_match {
+ Iterator position;
+ bool match;
+};
+
+template <typename Iterator, typename EndIterator> constexpr CTRE_FORCE_INLINE string_match<Iterator> match_against_range(Iterator current, const EndIterator last, Iterator range_current, const Iterator range_end, flags) noexcept {
+ while (last != 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 BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<back_reference_with_name<Id>, Tail...>) noexcept {
+
+ if (const auto ref = captures.template get<Id>()) {
+ if (auto result = match_against_range(current, last, ref.begin(), ref.end(), f); result.match) {
+ return evaluate(begin, result.position, last, consumed_something(f, ref.begin() != ref.end()), captures, ctll::list<Tail...>());
+ }
+ }
+ return not_matched;
+}
+
+// backreference
+template <typename R, size_t Id, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<back_reference<Id>, Tail...>) noexcept {
+
+ if (const auto ref = captures.template get<Id>()) {
+ if (auto result = match_against_range(current, last, ref.begin(), ref.end(), f); result.match) {
+ return evaluate(begin, result.position, last, consumed_something(f, ref.begin() != ref.end()), captures, ctll::list<Tail...>());
+ }
+ }
+ return not_matched;
+}
+
+// end of lookahead
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R captures, ctll::list<end_lookahead_mark>) noexcept {
+ // TODO check interaction with non-empty flag
+ return captures.matched();
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator, Iterator, const EndIterator, flags, R captures, ctll::list<end_lookbehind_mark>) noexcept {
+ // TODO check interaction with non-empty flag
+ return captures.matched();
+}
+
+// lookahead positive
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookahead_positive<Content...>, Tail...>) noexcept {
+
+ if (auto lookahead_result = evaluate(begin, current, last, f, captures, ctll::list<sequence<Content...>, end_lookahead_mark>())) {
+ captures = lookahead_result.unmatch();
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else {
+ return not_matched;
+ }
+}
+
+// lookahead negative
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookahead_negative<Content...>, Tail...>) noexcept {
+
+ if (auto lookahead_result = evaluate(begin, current, last, f, captures, ctll::list<sequence<Content...>, end_lookahead_mark>())) {
+ return not_matched;
+ } else {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ }
+}
+
+// lookbehind positive
+constexpr bool is_at_least_bidirectional(std::input_iterator_tag) {
+ return false;
+}
+
+constexpr bool is_at_least_bidirectional(std::bidirectional_iterator_tag) {
+ return true;
+}
+
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookbehind_positive<Content...>, Tail...>) noexcept {
+ static_assert(is_at_least_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "to use lookbehind you must provide bi-directional iterator");
+
+ if (auto lookbehind_result = evaluate(std::make_reverse_iterator(last), std::make_reverse_iterator(current), std::make_reverse_iterator(begin), f, captures, ctll::list<sequence<Content...>, end_lookbehind_mark>())) {
+ captures = lookbehind_result.unmatch();
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ } else {
+ return not_matched;
+ }
+}
+
+// lookbehind negative
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<lookbehind_negative<Content...>, Tail...>) noexcept {
+ static_assert(is_at_least_bidirectional(typename std::iterator_traits<Iterator>::iterator_category{}), "to use negative lookbehind you must provide bi-directional iterator");
+
+ if (auto lookbehind_result = evaluate(std::make_reverse_iterator(last), std::make_reverse_iterator(current), std::make_reverse_iterator(begin), f, captures, ctll::list<sequence<Content...>, end_lookbehind_mark>())) {
+ return not_matched;
+ } else {
+ return evaluate(begin, current, last, f, captures, ctll::list<Tail...>());
+ }
+}
+
+template <typename...> constexpr auto dependent_false = false;
+
+// atomic_group<...> is just transformation to possessive_repeat<1,1,...>
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename... Content, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<atomic_group<Content...>, Tail...>) noexcept {
+ return evaluate(begin, current, last, f, captures, ctll::list<possessive_repeat<1,1,Content...>, Tail...>{});
+}
+
+// switching modes
+template <typename R, typename BeginIterator, typename Iterator, typename EndIterator, typename Mode, typename... Tail>
+constexpr CTRE_FORCE_INLINE R evaluate(const BeginIterator begin, Iterator current, const EndIterator last, const flags & f, R captures, ctll::list<mode_switch<Mode>, Tail...>) noexcept {
+ return evaluate(begin, current, last, f + Mode{}, captures, ctll::list<Tail...>());
+}
+
+}
+
+#endif
+
+#ifndef CTRE__WRAPPER__HPP
+#define CTRE__WRAPPER__HPP
+
+#ifndef CTRE_V2__CTRE__RANGE__HPP
+#define CTRE_V2__CTRE__RANGE__HPP
+
+#ifndef CTRE_V2__CTRE__ITERATOR__HPP
+#define CTRE_V2__CTRE__ITERATOR__HPP
+
+#ifndef CTRE_IN_A_MODULE
+#include <cstddef>
+#endif
+
+namespace ctre {
+
+// TODO make proper iterator traits here
+
+struct regex_end_iterator {
+ constexpr regex_end_iterator() noexcept { }
+};
+
+template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_iterator {
+ using value_type = decltype(RE::template exec_with_result_iterator<ResultIterator>(std::declval<BeginIterator>(), std::declval<EndIterator>()));
+ using iterator_category = std::forward_iterator_tag;
+ using pointer = void;
+ using reference = const value_type &;
+ using difference_type = int;
+
+ BeginIterator orig_begin{};
+ BeginIterator current{};
+ EndIterator end{};
+ value_type current_match{};
+
+ constexpr CTRE_FORCE_INLINE regex_iterator() noexcept = default;
+ constexpr CTRE_FORCE_INLINE regex_iterator(const regex_iterator &) noexcept = default;
+ constexpr CTRE_FORCE_INLINE regex_iterator(regex_iterator &&) noexcept = default;
+
+ constexpr CTRE_FORCE_INLINE regex_iterator(BeginIterator begin, EndIterator last) noexcept: orig_begin{begin}, current{begin}, end{last}, current_match{RE::template exec_with_result_iterator<ResultIterator>(current, last)} {
+ if (current_match) {
+ current = current_match.template get<0>().end();
+ }
+ }
+
+ constexpr CTRE_FORCE_INLINE regex_iterator & operator=(const regex_iterator &) noexcept = default;
+ constexpr CTRE_FORCE_INLINE regex_iterator & operator=(regex_iterator &&) noexcept = default;
+
+ constexpr CTRE_FORCE_INLINE const value_type & operator*() const noexcept {
+ return current_match;
+ }
+ constexpr CTRE_FORCE_INLINE regex_iterator & operator++() noexcept {
+ if (current == end) {
+ current_match = decltype(current_match){};
+ return *this;
+ }
+
+ current_match = RE::template exec_with_result_iterator<ResultIterator>(orig_begin, current, end);
+
+ if (current_match) {
+ current = current_match.template get<0>().end();
+ }
+ return *this;
+ }
+ constexpr CTRE_FORCE_INLINE regex_iterator operator++(int) noexcept {
+ auto previous = *this;
+ this->operator++();
+ return previous;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current == right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return !(left.current == right.current);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator<(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current < right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator>(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current > right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator<=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current <= right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator>=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current >= right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
+ return !bool(left.current_match);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(regex_end_iterator, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return !bool(right.current_match);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
+ return bool(left.current_match);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(regex_end_iterator, const regex_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return bool(right.current_match);
+ }
+};
+
+template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_split_iterator {
+ using value_type = decltype(RE::template exec_with_result_iterator<ResultIterator>(std::declval<BeginIterator>(), std::declval<EndIterator>()));
+ using iterator_category = std::forward_iterator_tag;
+ using pointer = void;
+ using reference = const value_type &;
+ using difference_type = int;
+
+ BeginIterator orig_begin{};
+ BeginIterator current{};
+ EndIterator end{};
+ value_type current_match{};
+ bool last_match{false};
+
+ constexpr CTRE_FORCE_INLINE void modify_match() {
+ auto tmp = current_match.template get<0>().end();
+ current_match.set_end_mark(current_match.template get<0>().begin());
+ current_match.set_start_mark(current);
+ current = tmp;
+ }
+
+ constexpr CTRE_FORCE_INLINE void match_rest() {
+ // the end is there set by search_method
+ current_match.set_start_mark(current);
+ current_match.matched();
+ current = current_match.template get<0>().end();
+ last_match = true;
+ }
+
+ constexpr CTRE_FORCE_INLINE regex_split_iterator() noexcept = default;
+ constexpr CTRE_FORCE_INLINE regex_split_iterator(const regex_split_iterator &) noexcept = default;
+ constexpr CTRE_FORCE_INLINE regex_split_iterator(regex_split_iterator &&) noexcept = default;
+
+ constexpr CTRE_FORCE_INLINE regex_split_iterator(BeginIterator begin, EndIterator last) noexcept: orig_begin{begin}, current{begin}, end{last}, current_match{RE::template exec_with_result_iterator<ResultIterator>(current, last)} {
+ if (current_match) {
+ modify_match();
+ } else {
+ match_rest();
+ }
+ }
+
+ constexpr CTRE_FORCE_INLINE regex_split_iterator & operator=(const regex_split_iterator &) noexcept = default;
+ constexpr CTRE_FORCE_INLINE regex_split_iterator & operator=(regex_split_iterator &&) noexcept = default;
+
+ constexpr CTRE_FORCE_INLINE const value_type & operator*() const noexcept {
+ return current_match;
+ }
+ constexpr CTRE_FORCE_INLINE regex_split_iterator & operator++() noexcept {
+ if (current == end && last_match) {
+ current_match = decltype(current_match){};
+ return *this;
+ }
+
+ current_match = RE::template exec_with_result_iterator<ResultIterator>(orig_begin, current, end);
+
+ if (current_match) {
+ modify_match();
+ } else {
+ match_rest();
+ }
+ return *this;
+ }
+ constexpr CTRE_FORCE_INLINE regex_split_iterator operator++(int) noexcept {
+ auto previous = *this;
+ this->operator++();
+ return previous;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current == right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return !(left.current == right.current);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator<(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current < right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator>(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current > right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator<=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current <= right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator>=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return left.current >= right.current;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
+ return !bool(left.current_match);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(regex_end_iterator, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return !bool(right.current_match);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & left, regex_end_iterator) noexcept {
+ return bool(left.current_match);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(regex_end_iterator, const regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator> & right) noexcept {
+ return bool(right.current_match);
+ }
+};
+
+} // ctre
+
+#endif
+
+namespace ctre {
+
+template <typename> constexpr bool is_range = false;
+
+template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_range {
+ BeginIterator _begin;
+ EndIterator _end;
+
+ constexpr CTRE_FORCE_INLINE regex_range(BeginIterator begin, EndIterator end) noexcept: _begin{begin}, _end{end} { }
+
+ constexpr CTRE_FORCE_INLINE auto begin() const noexcept {
+ return regex_iterator<BeginIterator, EndIterator, RE, ResultIterator>(_begin, _end);
+ }
+ constexpr CTRE_FORCE_INLINE auto end() const noexcept {
+ return regex_end_iterator{};
+ }
+};
+
+template <typename... Ts> constexpr bool is_range<regex_range<Ts...>> = true;
+
+template <typename BeginIterator, typename EndIterator, typename RE, typename ResultIterator = BeginIterator> struct regex_split_range {
+ BeginIterator _begin;
+ EndIterator _end;
+
+ constexpr CTRE_FORCE_INLINE regex_split_range(BeginIterator begin, EndIterator end) noexcept: _begin{begin}, _end{end} { }
+
+ constexpr CTRE_FORCE_INLINE auto begin() const noexcept {
+ return regex_split_iterator<BeginIterator, EndIterator, RE, ResultIterator>(_begin, _end);
+ }
+ constexpr CTRE_FORCE_INLINE auto end() const noexcept {
+ return regex_end_iterator{};
+ }
+};
+
+template <typename... Ts> constexpr bool is_range<regex_split_range<Ts...>> = true;
+
+template <typename Range, typename RE> struct multi_subject_range {
+ struct end_iterator { };
+
+ using first_type = decltype(std::declval<Range>().begin());
+ using last_type = decltype(std::declval<Range>().end());
+
+ struct iterator {
+ using value_type = decltype(RE::exec(std::declval<typename std::iterator_traits<first_type>::value_type>()));
+ using iterator_category = std::forward_iterator_tag;
+ using reference = const value_type &;
+ using pointer = const value_type *;
+ using difference_type = int;
+
+ first_type first{};
+ last_type last{};
+ value_type current_result{};
+
+ constexpr CTRE_FORCE_INLINE iterator() noexcept = default;
+ constexpr CTRE_FORCE_INLINE iterator(first_type f, last_type l) noexcept: first{f}, last{l}, current_result{find_first()} { }
+
+ constexpr CTRE_FORCE_INLINE value_type find_first() noexcept {
+ while (first != last) {
+ if (auto res = RE::exec(*first)) return res;
+ else ++first;
+ }
+ return {};
+ }
+
+ constexpr CTRE_FORCE_INLINE reference operator*() const noexcept {
+ return current_result;
+ }
+
+ constexpr CTRE_FORCE_INLINE pointer operator->() const noexcept {
+ return ¤t_result;
+ }
+
+ constexpr CTRE_FORCE_INLINE iterator & operator++() noexcept {
+ ++first;
+ current_result = find_first();
+ return *this;
+ }
+ constexpr CTRE_FORCE_INLINE iterator operator++(int) noexcept {
+ auto previous = *this;
+ this->operator++();
+ return previous;
+ }
+
+ friend constexpr CTRE_FORCE_INLINE bool operator==(const iterator & left, const iterator & right) noexcept {
+ return left.first == right.first;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(const iterator & left, const iterator & right) noexcept {
+ return !(left.first == right.first);
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator<(const iterator & left, const iterator & right) noexcept {
+ return left.first < right.first;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator>(const iterator & left, const iterator & right) noexcept {
+ return left.first > right.first;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator<=(const iterator & left, const iterator & right) noexcept {
+ return left.first <= right.first;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator>=(const iterator & left, const iterator & right) noexcept {
+ return left.first >= right.first;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(const iterator & left, end_iterator) noexcept {
+ return left.first == left.last;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator==(end_iterator, const iterator & right) noexcept {
+ return right.first == right.last;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(const iterator & left, end_iterator) noexcept {
+ return left.first != left.last;
+ }
+ friend constexpr CTRE_FORCE_INLINE bool operator!=(end_iterator, const iterator & right) noexcept {
+ return right.first == right.last;
+ }
+ };
+
+ Range range{};
+
+ constexpr CTRE_FORCE_INLINE multi_subject_range() noexcept = default;
+ constexpr CTRE_FORCE_INLINE multi_subject_range(Range r) noexcept: range{r} { }
+
+ constexpr CTRE_FORCE_INLINE auto begin() const noexcept {
+ return iterator{range.begin(), range.end()};
+ }
+ constexpr CTRE_FORCE_INLINE auto end() const noexcept {
+ return end_iterator{};
+ }
+};
+
+// this is not regex range!
+template <typename... Ts> constexpr bool is_range<multi_subject_range<Ts...>> = true;
+
+}
+
+#if defined __cpp_lib_ranges && __cpp_lib_ranges >= 201911
+namespace std::ranges {
+
+ template <typename... Ts> inline constexpr bool enable_borrowed_range<::ctre::regex_range<Ts...>> = true;
+ template <typename... Ts> inline constexpr bool enable_borrowed_range<::ctre::regex_split_range<Ts...>> = true;
+ template <typename Range, typename RE> inline constexpr bool enable_borrowed_range<::ctre::multi_subject_range<Range, RE>> = enable_borrowed_range<Range>;
+ template <typename Range, typename RE> inline constexpr bool enable_view<::ctre::multi_subject_range<Range, RE>> = true;
+
+}
+#endif
+
+#endif
+
+#ifndef CTRE_IN_A_MODULE
+#include <string_view>
+#endif
+
+namespace ctre {
+
+CTRE_EXPORT template <typename RE, typename Method = void, typename Modifier = singleline> struct regular_expression;
+
+struct zero_terminated_string_end_iterator {
+ // this is here only because I want to support std::make_reverse_iterator
+ using self_type = zero_terminated_string_end_iterator;
+ using value_type = char;
+ using reference = char &;
+ using pointer = const char *;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = int;
+
+ // it's just sentinel it won't be ever called
+ auto operator++() noexcept -> self_type &;
+ auto operator++(int) noexcept -> self_type;
+ auto operator--() noexcept -> self_type &;
+ auto operator--(int) noexcept -> self_type;
+ friend auto operator==(self_type, self_type) noexcept -> bool;
+ auto operator*() noexcept -> reference;
+
+ constexpr CTRE_FORCE_INLINE friend bool operator==(const char * ptr, zero_terminated_string_end_iterator) noexcept {
+ return *ptr == '\0';
+ }
+ constexpr CTRE_FORCE_INLINE friend bool operator==(const wchar_t * ptr, zero_terminated_string_end_iterator) noexcept {
+ return *ptr == 0;
+ }
+ constexpr CTRE_FORCE_INLINE friend bool operator!=(const char * ptr, zero_terminated_string_end_iterator) noexcept {
+ return *ptr != '\0';
+ }
+ constexpr CTRE_FORCE_INLINE friend bool operator!=(const wchar_t * ptr, zero_terminated_string_end_iterator) noexcept {
+ return *ptr != 0;
+ }
+ constexpr CTRE_FORCE_INLINE friend bool operator==(zero_terminated_string_end_iterator, const char * ptr) noexcept {
+ return *ptr == '\0';
+ }
+ constexpr CTRE_FORCE_INLINE friend bool operator==(zero_terminated_string_end_iterator, const wchar_t * ptr) noexcept {
+ return *ptr == 0;
+ }
+ constexpr CTRE_FORCE_INLINE friend bool operator!=(zero_terminated_string_end_iterator, const char * ptr) noexcept {
+ return *ptr != '\0';
+ }
+ constexpr CTRE_FORCE_INLINE friend bool operator!=(zero_terminated_string_end_iterator, const wchar_t * ptr) 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 constexpr bool value = decltype(test<std::remove_reference_t<std::remove_const_t<T>>>(nullptr))::value;
+};
+
+struct match_method {
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin orig_begin, IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ using result_iterator = std::conditional_t<std::is_same_v<ResultIterator, void>, IteratorBegin, ResultIterator>;
+
+ return evaluate(orig_begin, begin, end, Modifier{}, return_type<result_iterator, RE>{}, ctll::list<start_mark, RE, assert_subject_end, end_mark, accept>());
+ }
+
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ return exec<Modifier, ResultIterator>(begin, begin, end, RE{});
+ }
+};
+
+struct search_method {
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin orig_begin, IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ using result_iterator = std::conditional_t<std::is_same_v<ResultIterator, void>, IteratorBegin, ResultIterator>;
+
+ constexpr bool fixed = starts_with_anchor(Modifier{}, ctll::list<RE>{});
+
+ auto it = begin;
+
+ for (; end != it && !fixed; ++it) {
+ if (auto out = evaluate(orig_begin, it, end, Modifier{}, return_type<result_iterator, RE>{}, ctll::list<start_mark, RE, end_mark, accept>())) {
+ return out;
+ }
+ }
+
+ // in case the RE is empty or fixed
+ auto out = evaluate(orig_begin, it, end, Modifier{}, return_type<result_iterator, RE>{}, ctll::list<start_mark, RE, end_mark, accept>());
+
+ // ALERT: ugly hack
+ // propagate end even if it didn't match (this is needed for split function)
+ if (!out) out.set_end_mark(it);
+ return out;
+ }
+
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ return exec<Modifier, ResultIterator>(begin, begin, end, RE{});
+ }
+};
+
+struct starts_with_method {
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin orig_begin, IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ using result_iterator = std::conditional_t<std::is_same_v<ResultIterator, void>, IteratorBegin, ResultIterator>;
+ return evaluate(orig_begin, begin, end, Modifier{}, return_type<result_iterator, RE>{}, ctll::list<start_mark, RE, end_mark, accept>());
+ }
+
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ return exec<Modifier, ResultIterator>(begin, begin, end, RE{});
+ }
+};
+
+// wrapper which calls search on input
+struct range_method {
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ using result_iterator = std::conditional_t<std::is_same_v<ResultIterator, void>, IteratorBegin, ResultIterator>;
+ using wrapped_regex = regular_expression<RE, search_method, Modifier>;
+
+ return regex_range<IteratorBegin, IteratorEnd, wrapped_regex, result_iterator>(begin, end);
+ }
+};
+
+struct tokenize_method {
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ using result_iterator = std::conditional_t<std::is_same_v<ResultIterator, void>, IteratorBegin, ResultIterator>;
+ using wrapped_regex = regular_expression<RE, starts_with_method, Modifier>;
+
+ return regex_range<IteratorBegin, IteratorEnd, wrapped_regex, result_iterator>(begin, end);
+ }
+};
+
+struct split_method {
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ using result_iterator = std::conditional_t<std::is_same_v<ResultIterator, void>, IteratorBegin, ResultIterator>;
+ using wrapped_regex = regular_expression<RE, search_method, Modifier>;
+
+ return regex_split_range<IteratorBegin, IteratorEnd, wrapped_regex, result_iterator>(begin, end);
+ }
+};
+
+struct iterator_method {
+ template <typename Modifier = singleline, typename ResultIterator = void, typename RE, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end, RE) noexcept {
+ using result_iterator = std::conditional_t<std::is_same_v<ResultIterator, void>, IteratorBegin, ResultIterator>;
+ using wrapped_regex = regular_expression<RE, search_method, Modifier>;
+
+ return regex_iterator<IteratorBegin, IteratorEnd, wrapped_regex, result_iterator>(begin, end);
+ }
+ constexpr CTRE_FORCE_INLINE static auto exec() noexcept {
+ return regex_end_iterator{};
+ }
+};
+
+CTRE_EXPORT template <typename RE, typename Method, typename Modifier> struct regular_expression {
+ constexpr CTRE_FORCE_INLINE regular_expression() noexcept { }
+ constexpr CTRE_FORCE_INLINE regular_expression(RE) noexcept { }
+
+ template <typename ResultIterator, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec_with_result_iterator(IteratorBegin orig_begin, IteratorBegin begin, IteratorEnd end) noexcept {
+ return Method::template exec<Modifier, ResultIterator>(orig_begin, begin, end, RE{});
+ }
+ template <typename ResultIterator, typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec_with_result_iterator(IteratorBegin begin, IteratorEnd end) noexcept {
+ return Method::template exec<Modifier, ResultIterator>(begin, end, RE{});
+ }
+ template <typename Range> constexpr CTRE_FORCE_INLINE static auto multi_exec(Range && range) noexcept {
+ return multi_subject_range<Range, regular_expression>{std::forward<Range>(range)};
+ }
+ constexpr CTRE_FORCE_INLINE static auto exec() noexcept {
+ return Method::exec();
+ }
+ template <typename IteratorBegin, typename IteratorEnd> constexpr CTRE_FORCE_INLINE static auto exec(IteratorBegin begin, IteratorEnd end) noexcept {
+ return Method::template exec<Modifier>(begin, end, RE{});
+ }
+ static constexpr CTRE_FORCE_INLINE auto exec(const char * s) noexcept {
+ return Method::template exec<Modifier>(s, zero_terminated_string_end_iterator(), RE{});
+ }
+ static constexpr CTRE_FORCE_INLINE auto exec(const wchar_t * s) noexcept {
+ return Method::template exec<Modifier>(s, zero_terminated_string_end_iterator(), RE{});
+ }
+ static constexpr CTRE_FORCE_INLINE auto exec(std::string_view sv) noexcept {
+ return exec(sv.begin(), sv.end());
+ }
+ static constexpr CTRE_FORCE_INLINE auto exec(std::wstring_view sv) noexcept {
+ return exec(sv.begin(), sv.end());
+ }
+#ifdef CTRE_ENABLE_UTF8_RANGE
+ static constexpr CTRE_FORCE_INLINE auto exec(std::u8string_view sv) noexcept {
+ return exec_with_result_iterator<const char8_t *>(utf8_range(sv).begin(), utf8_range(sv).end());
+ }
+#endif
+ static constexpr CTRE_FORCE_INLINE auto exec(std::u16string_view sv) noexcept {
+ return exec(sv.begin(), sv.end());
+ }
+ static constexpr CTRE_FORCE_INLINE auto exec(std::u32string_view sv) noexcept {
+ return exec(sv.begin(), sv.end());
+ }
+ template <typename Range, typename = typename std::enable_if<RangeLikeType<Range>::value>::type> static constexpr CTRE_FORCE_INLINE auto exec(Range && range) noexcept {
+ return exec(std::begin(range), std::end(range));
+ }
+
+ // another api
+ template <typename... Args> CTRE_FORCE_INLINE constexpr auto operator()(Args &&... args) const noexcept {
+ return exec(std::forward<Args>(args)...);
+ }
+ // api for pattern matching
+ template <typename... Args> CTRE_FORCE_INLINE constexpr auto try_extract(Args &&... args) const noexcept {
+ return exec(std::forward<Args>(args)...);
+ }
+
+ // for compatibility with _ctre literal
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto match(Args &&... args) noexcept {
+ return regular_expression<RE, match_method, singleline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto search(Args &&... args) noexcept {
+ return regular_expression<RE, search_method, singleline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto starts_with(Args &&... args) noexcept {
+ return regular_expression<RE, starts_with_method, singleline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto range(Args &&... args) noexcept {
+ return regular_expression<RE, range_method, singleline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto split(Args &&... args) noexcept {
+ return regular_expression<RE, split_method, singleline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto tokenize(Args &&... args) noexcept {
+ return regular_expression<RE, tokenize_method, singleline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto iterator(Args &&... args) noexcept {
+ return regular_expression<RE, iterator_method, singleline>::exec(std::forward<Args>(args)...);
+ }
+
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto multiline_match(Args &&... args) noexcept {
+ return regular_expression<RE, match_method, multiline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto multiline_search(Args &&... args) noexcept {
+ return regular_expression<RE, search_method, multiline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto multiline_starts_with(Args &&... args) noexcept {
+ return regular_expression<RE, starts_with_method, multiline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto multiline_range(Args &&... args) noexcept {
+ return regular_expression<RE, range_method, multiline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto multiline_split(Args &&... args) noexcept {
+ return regular_expression<RE, split_method, multiline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto multiline_tokenize(Args &&... args) noexcept {
+ return regular_expression<RE, tokenize_method, multiline>::exec(std::forward<Args>(args)...);
+ }
+ template <typename... Args> static constexpr CTRE_FORCE_INLINE auto multiline_iterator(Args &&... args) noexcept {
+ return regular_expression<RE, iterator_method, multiline>::exec(std::forward<Args>(args)...);
+ }
+};
+
+// range style API support for tokenize/range/split operations
+template <typename Range, typename RE, typename Modifier> constexpr auto operator|(Range && range, regular_expression<RE, range_method, Modifier> re) noexcept {
+ return re.exec(std::forward<Range>(range));
+}
+
+template <typename Range, typename RE, typename Modifier> constexpr auto operator|(Range && range, regular_expression<RE, tokenize_method, Modifier> re) noexcept {
+ return re.exec(std::forward<Range>(range));
+}
+
+template <typename Range, typename RE, typename Modifier> constexpr auto operator|(Range && range, regular_expression<RE, split_method, Modifier> re) noexcept {
+ return re.exec(std::forward<Range>(range));
+}
+
+template <typename Range, typename RE, typename Modifier> constexpr auto operator|(Range && range, regular_expression<RE, iterator_method, Modifier> re) noexcept = delete;
+
+template <typename Range, typename RE, typename Method, typename Modifier> constexpr auto operator|(Range && range, regular_expression<RE, Method, Modifier> re) noexcept {
+ return re.multi_exec(std::forward<Range>(range));
+}
+
+// error reporting of problematic position in a regex
+template <size_t> struct problem_at_position; // do not define!
+
+template <> struct problem_at_position<~static_cast<size_t>(0)> {
+ constexpr operator bool() const noexcept {
+ return true;
+ }
+};
+
+#if CTRE_CNTTP_COMPILER_CHECK
+#define CTRE_REGEX_INPUT_TYPE ctll::fixed_string
+#define CTRE_REGEX_TEMPLATE_COPY_TYPE auto
+#else
+#define CTRE_REGEX_INPUT_TYPE const auto &
+#define CTRE_REGEX_TEMPLATE_COPY_TYPE const auto &
+#endif
+
+template <CTRE_REGEX_TEMPLATE_COPY_TYPE input> struct regex_builder {
+ static constexpr auto _input = input;
+ using result = typename ctll::parser<ctre::pcre, _input, ctre::pcre_actions>::template output<pcre_context<>>;
+
+ static constexpr auto n = result::is_correct ? ~static_cast<size_t>(0) : result::position;
+
+ static_assert(result::is_correct && problem_at_position<n>{}, "Regular Expression contains syntax error.");
+
+ using type = ctll::conditional<result::is_correct, decltype(ctll::front(typename result::output_type::stack_type())), ctll::list<reject>>;
+};
+
+// case-sensitive
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto match = regular_expression<typename regex_builder<input>::type, match_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto search = regular_expression<typename regex_builder<input>::type, search_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto starts_with = regular_expression<typename regex_builder<input>::type, starts_with_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto search_all = regular_expression<typename regex_builder<input>::type, range_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> [[deprecated("use search_all")]] constexpr auto range = regular_expression<typename regex_builder<input>::type, range_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto split = regular_expression<typename regex_builder<input>::type, split_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto tokenize = regular_expression<typename regex_builder<input>::type, tokenize_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto iterator = regular_expression<typename regex_builder<input>::type, iterator_method, ctll::list<singleline, Modifiers...>>();
+
+CTRE_EXPORT constexpr auto sentinel = regex_end_iterator();
+
+// multiline
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto multiline_match = regular_expression<typename regex_builder<input>::type, match_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto multiline_search = regular_expression<typename regex_builder<input>::type, search_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto multiline_starts_with = regular_expression<typename regex_builder<input>::type, starts_with_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto multiline_search_all = regular_expression<typename regex_builder<input>::type, range_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> [[deprecated("use multiline_search_all")]] constexpr auto multiline_range = regular_expression<typename regex_builder<input>::type, range_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto multiline_split = regular_expression<typename regex_builder<input>::type, split_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto multiline_tokenize = regular_expression<typename regex_builder<input>::type, tokenize_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT template <CTRE_REGEX_INPUT_TYPE input, typename... Modifiers> constexpr auto multiline_iterator = regular_expression<typename regex_builder<input>::type, iterator_method, ctll::list<multiline, Modifiers...>>();
+
+CTRE_EXPORT constexpr auto multiline_sentinel = regex_end_iterator();
+
+} // namespace ctre
+
+#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 !CTRE_CNTTP_COMPILER_CHECK
+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 _MSC_VER
+#ifdef _MSVC_LANG
+#if _MSVC_LANG >= 202002L
+#define CTRE_ENABLE_LITERALS
+#endif
+#else
+#define CTRE_ENABLE_LITERALS
+#endif
+#endif
+
+#ifdef __INTEL_COMPILER
+// not enable literals
+#elif defined __GNUC__
+#if __GNUC__ < 9
+#define CTRE_ENABLE_LITERALS
+#elif __GNUC__ >= 10
+#if !CTRE_CNTTP_COMPILER_CHECK
+// newer versions of GCC will give error when trying to use GNU extension
+#else
+#define CTRE_ENABLE_LITERALS
+#endif
+#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 !CTRE_CNTTP_COMPILER_CHECK
+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 !CTRE_CNTTP_COMPILER_CHECK
+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 !CTRE_CNTTP_COMPILER_CHECK
+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 !CTRE_CNTTP_COMPILER_CHECK
+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 !CTRE_CNTTP_COMPILER_CHECK
+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 !CTRE_CNTTP_COMPILER_CHECK
+// 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 CTRE_CNTTP_COMPILER_CHECK
+template <ctll::fixed_string input, typename Modifier = void> CTRE_FLATTEN constexpr CTRE_FORCE_INLINE auto re() noexcept {
+constexpr auto _input = input; // workaround for GCC 9 bug 88092
+#else
+template <auto & input, typename Modifier = void> 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 regex = decltype(front(typename tmp::output_type::stack_type()));
+ return ctre::regular_expression<regex, Modifier, singleline>();
+}
+
+}
+
+#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
commit 96dac7bb38b88abd8321ea2f33b3bba100ef21e3
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Sat May 16 18:27:08 2026 +0800
[gnc-filepath-utils.cpp] null check char* arguments
diff --git a/libgnucash/core-utils/gnc-filepath-utils.cpp b/libgnucash/core-utils/gnc-filepath-utils.cpp
index 4f4080b2db..fe3e31e5ee 100644
--- a/libgnucash/core-utils/gnc-filepath-utils.cpp
+++ b/libgnucash/core-utils/gnc-filepath-utils.cpp
@@ -1326,6 +1326,7 @@ backup_regex (".*[.](?:xac|gnucash)[.][0-9]{14}[.](?:xac|gnucash)$");
gboolean gnc_filename_is_backup (const char *filename)
{
+ g_return_val_if_fail (filename, FALSE);
return std::regex_match (filename, backup_regex);
}
@@ -1334,6 +1335,7 @@ datafile_regex (".*[.](?:xac|gnucash)$");
gboolean gnc_filename_is_datafile (const char *filename)
{
+ g_return_val_if_fail (filename, FALSE);
return !gnc_filename_is_backup (filename) &&
std::regex_match (filename, datafile_regex);
}
diff --git a/libgnucash/core-utils/test/gtest-path-utilities.cpp b/libgnucash/core-utils/test/gtest-path-utilities.cpp
index 017252293b..873fecd531 100644
--- a/libgnucash/core-utils/test/gtest-path-utilities.cpp
+++ b/libgnucash/core-utils/test/gtest-path-utilities.cpp
@@ -141,10 +141,12 @@ TEST_F(PathTest, gnc_path_get_sysconfdir)
TEST_F (PathTest, gnc_filename_is_backup)
{
+ EXPECT_EQ (gnc_filename_is_backup (nullptr), false);
EXPECT_EQ (gnc_filename_is_backup (""), false);
EXPECT_EQ (gnc_filename_is_backup ("a.gnucash"), false);
EXPECT_EQ (gnc_filename_is_backup ("a.gnucash.20201131010203.gnucash"), true);
+ EXPECT_EQ (gnc_filename_is_datafile (nullptr), false);
EXPECT_EQ (gnc_filename_is_datafile (""), false);
EXPECT_EQ (gnc_filename_is_datafile ("a.gnucash"), true);
EXPECT_EQ (gnc_filename_is_datafile ("a.gnucash.20201131010203.gnucash"), false);
Summary of changes:
CMakeLists.txt | 1 +
borrowed/CMakeLists.txt | 2 +
borrowed/ctre/CMakeLists.txt | 13 +
borrowed/ctre/LICENSE | 218 +
borrowed/ctre/ctre.hpp | 5993 ++++++++++++++++++++
libgnucash/core-utils/CMakeLists.txt | 1 +
libgnucash/core-utils/gnc-filepath-utils.cpp | 13 +-
libgnucash/core-utils/test/CMakeLists.txt | 1 +
.../core-utils/test/gtest-path-utilities.cpp | 2 +
9 files changed, 6238 insertions(+), 6 deletions(-)
create mode 100644 borrowed/ctre/CMakeLists.txt
create mode 100644 borrowed/ctre/LICENSE
create mode 100644 borrowed/ctre/ctre.hpp
More information about the gnucash-changes
mailing list