mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 22:14:24 +08:00
Compare commits
427 Commits
new-docs
...
new-item-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdb694d4a6 | ||
|
|
60f80673e3 | ||
|
|
a0f4eada6f | ||
|
|
64e6b3cd2d | ||
|
|
f19c6d078e | ||
|
|
73f18a4da2 | ||
|
|
7a9d94bc57 | ||
|
|
a3ba760ab5 | ||
|
|
913abcd1b3 | ||
|
|
510e336306 | ||
|
|
ffff2479d2 | ||
|
|
b550e9b027 | ||
|
|
452bb83ce7 | ||
|
|
6eda9aaf36 | ||
|
|
251fb55d6a | ||
|
|
f94e9aece9 | ||
|
|
c565bb96be | ||
|
|
e51f31dc4c | ||
|
|
4e128885d6 | ||
|
|
b37054228d | ||
|
|
815b33fee0 | ||
|
|
97f55c1639 | ||
|
|
89de73eb6f | ||
|
|
75f2ec3792 | ||
|
|
f4d29e8da9 | ||
|
|
b97b2638b8 | ||
|
|
bc0222dc0e | ||
|
|
10a6b5649b | ||
|
|
743e2800f8 | ||
|
|
32ac884127 | ||
|
|
bec69f7d07 | ||
|
|
a99215ad6a | ||
|
|
e3d2cbd044 | ||
|
|
5fc965789d | ||
|
|
b4596902aa | ||
|
|
cbf8b52f62 | ||
|
|
4e0fa1c916 | ||
|
|
95b007d38f | ||
|
|
b66f7a30ce | ||
|
|
ec7287c503 | ||
|
|
a41c591f0c | ||
|
|
3a6527cdd5 | ||
|
|
5f21a094c0 | ||
|
|
2203a1855d | ||
|
|
7edd2ecc18 | ||
|
|
1d2953c850 | ||
|
|
dbf59ce622 | ||
|
|
1596db8499 | ||
|
|
bd1fb5c5cd | ||
|
|
da500025c3 | ||
|
|
60eeea9a93 | ||
|
|
1220f01f1e | ||
|
|
ad0a34fe98 | ||
|
|
a7425ff1a0 | ||
|
|
1ce25f86ae | ||
|
|
cd93f72b96 | ||
|
|
23500bd303 | ||
|
|
14b4753b4f | ||
|
|
4c37d5db5f | ||
|
|
fc2c4b4172 | ||
|
|
3ac64de16b | ||
|
|
45eecd72b0 | ||
|
|
d1dd558cda | ||
|
|
d19e2c2196 | ||
|
|
72c7aca074 | ||
|
|
683a1087d0 | ||
|
|
35bc139deb | ||
|
|
45ece2fa0d | ||
|
|
11c98f553f | ||
|
|
28aa9b1036 | ||
|
|
d7b5c0a748 | ||
|
|
065e7f5f18 | ||
|
|
4b1623cfdc | ||
|
|
1de973ddcb | ||
|
|
eecc801203 | ||
|
|
5c50154ea4 | ||
|
|
0fa3d6aa94 | ||
|
|
01f5242bfb | ||
|
|
af6d8d4f71 | ||
|
|
fa8285fc0f | ||
|
|
2e7f6b8337 | ||
|
|
a6a55020eb | ||
|
|
0e84ea454d | ||
|
|
f3bf211d45 | ||
|
|
f5ef44836c | ||
|
|
070124b6e1 | ||
|
|
c8a46fcdd9 | ||
|
|
5306b59fd8 | ||
|
|
90c5df832a | ||
|
|
2aa439d51f | ||
|
|
ac2b68517c | ||
|
|
e56b568c42 | ||
|
|
63c49b2e04 | ||
|
|
559fd18a20 | ||
|
|
beb7585261 | ||
|
|
8b0f92aa9a | ||
|
|
0d8beeae5b | ||
|
|
e3da654e67 | ||
|
|
dc9e151d89 | ||
|
|
7cfaf051ba | ||
|
|
7920491309 | ||
|
|
0ee493a3fb | ||
|
|
7e23bc0c0b | ||
|
|
579f859562 | ||
|
|
752938ca44 | ||
|
|
fce58c02fe | ||
|
|
924f7c1505 | ||
|
|
8944906fd2 | ||
|
|
cb02969604 | ||
|
|
31090c6ec5 | ||
|
|
9e30d2bc1a | ||
|
|
93d703f7a1 | ||
|
|
3c241048a5 | ||
|
|
2788536799 | ||
|
|
314d435a18 | ||
|
|
37edcd8666 | ||
|
|
10e290fbdf | ||
|
|
58cda1241e | ||
|
|
3659aaabff | ||
|
|
727a39cc54 | ||
|
|
fd9ccdfff9 | ||
|
|
aabee270b3 | ||
|
|
647c58f8ec | ||
|
|
0b8024d19c | ||
|
|
d59b0bf27f | ||
|
|
398c16eac2 | ||
|
|
fa869bdc7d | ||
|
|
c20d0d2a30 | ||
|
|
000f2736c2 | ||
|
|
cfcc81bb62 | ||
|
|
82eae05868 | ||
|
|
e8fb53c49b | ||
|
|
604c97afe1 | ||
|
|
7e60cdf272 | ||
|
|
9ea7cfcc80 | ||
|
|
a7a4a16f79 | ||
|
|
6717059934 | ||
|
|
714747c280 | ||
|
|
81cd305c80 | ||
|
|
5de872bbb3 | ||
|
|
ce6a75a920 | ||
|
|
874a5cb2f2 | ||
|
|
6e2202d4f1 | ||
|
|
bcf33df701 | ||
|
|
3bdcf21c69 | ||
|
|
4b36bdc58c | ||
|
|
6d9008ee8c | ||
|
|
ee93692707 | ||
|
|
2bcc368bce | ||
|
|
6cc4467d53 | ||
|
|
425f98dc07 | ||
|
|
cf34a9f3ad | ||
|
|
3b2f347428 | ||
|
|
bd82c3cc4f | ||
|
|
af319866c7 | ||
|
|
b6ab29398e | ||
|
|
a5bb1797c0 | ||
|
|
a9647671c4 | ||
|
|
63f784e7da | ||
|
|
5da3379e0b | ||
|
|
2f3514689d | ||
|
|
89a3ea4e24 | ||
|
|
467e9555f4 | ||
|
|
5b32ca15f7 | ||
|
|
92402817d2 | ||
|
|
60ad3031d5 | ||
|
|
724cddb481 | ||
|
|
41c0521480 | ||
|
|
85ac2b1f63 | ||
|
|
13a97353aa | ||
|
|
f49c166b9b | ||
|
|
fffa326f80 | ||
|
|
da446adbb2 | ||
|
|
617fec5c69 | ||
|
|
cfefa69c9c | ||
|
|
00638a9e23 | ||
|
|
e241e03a15 | ||
|
|
b1faa3bd48 | ||
|
|
6d28f487ec | ||
|
|
b231f92f76 | ||
|
|
7d33d56c0e | ||
|
|
f86f34e5e1 | ||
|
|
5e7b52b7de | ||
|
|
0459d344e9 | ||
|
|
71e525cd76 | ||
|
|
1480706d8b | ||
|
|
96655b6d80 | ||
|
|
eed2aa0d0d | ||
|
|
de0c078a23 | ||
|
|
321e995a54 | ||
|
|
da9f1f81d7 | ||
|
|
c6d4477a24 | ||
|
|
523b073cdc | ||
|
|
2591bee21b | ||
|
|
d881ca00c9 | ||
|
|
329dbff474 | ||
|
|
d84a9fe6dc | ||
|
|
dcd812a996 | ||
|
|
6750194d9b | ||
|
|
05865c3d9b | ||
|
|
21e224bf00 | ||
|
|
f401d3fd0c | ||
|
|
fd436871f1 | ||
|
|
fcf7864a4b | ||
|
|
c4003956d9 | ||
|
|
de622b6162 | ||
|
|
41b4bdb90e | ||
|
|
af73cb3ad3 | ||
|
|
240b631963 | ||
|
|
c2a747af8c | ||
|
|
5959647826 | ||
|
|
9542e211bc | ||
|
|
d07890db7f | ||
|
|
ca241bd8f2 | ||
|
|
e444092711 | ||
|
|
a96b1e07f4 | ||
|
|
f48c31bcb5 | ||
|
|
d85ab93a35 | ||
|
|
a6804b5aca | ||
|
|
e4dcb211ee | ||
|
|
a5a5f47f7a | ||
|
|
25c900c387 | ||
|
|
4e95f7b83e | ||
|
|
66ad3b0cee | ||
|
|
e853cd1ca0 | ||
|
|
b9544033c6 | ||
|
|
17840cb8cc | ||
|
|
f85b6d94b8 | ||
|
|
6c32a9f198 | ||
|
|
cefeebbfb8 | ||
|
|
941a015b43 | ||
|
|
ae0e9fbe77 | ||
|
|
3484c3dd2e | ||
|
|
5be8f749bd | ||
|
|
cf484707a0 | ||
|
|
f12e529c0b | ||
|
|
01b90a2ba5 | ||
|
|
cd1e952812 | ||
|
|
996f1e4277 | ||
|
|
2d84694f86 | ||
|
|
65718c64cc | ||
|
|
6e30365f55 | ||
|
|
c0555b6d86 | ||
|
|
1ff9b6c071 | ||
|
|
c1a51a1dfa | ||
|
|
bfbbeb90e7 | ||
|
|
588e075325 | ||
|
|
66717fee68 | ||
|
|
844f52c955 | ||
|
|
e679cd05c1 | ||
|
|
1e72ce4830 | ||
|
|
3bb21c5403 | ||
|
|
6d1be23ad0 | ||
|
|
0472b9a4a4 | ||
|
|
c9acff49f9 | ||
|
|
7cab560595 | ||
|
|
ac98531a2f | ||
|
|
917e0ba79c | ||
|
|
3ebceb7522 | ||
|
|
92bd52da12 | ||
|
|
fb56a9cd6e | ||
|
|
a4680f7d38 | ||
|
|
da8a72a8aa | ||
|
|
ac497932b5 | ||
|
|
9927b5061a | ||
|
|
cedaab9642 | ||
|
|
50bf2145ec | ||
|
|
dc77729f50 | ||
|
|
e3330d667a | ||
|
|
9822f397a1 | ||
|
|
a3b5ce9959 | ||
|
|
9eb06e929a | ||
|
|
629e06d647 | ||
|
|
51ccb92184 | ||
|
|
3cd27f13fd | ||
|
|
ae668530c0 | ||
|
|
4a8b1c056c | ||
|
|
d7a5e598bc | ||
|
|
3f1ee32cc6 | ||
|
|
725d6ead98 | ||
|
|
baf70579de | ||
|
|
cd28ab58a3 | ||
|
|
a78fa0a81d | ||
|
|
82130be5f5 | ||
|
|
510ce62dfb | ||
|
|
93375a5087 | ||
|
|
be738e7fb1 | ||
|
|
9c78131df3 | ||
|
|
d94f6f4d19 | ||
|
|
9a3eced350 | ||
|
|
2fed7a76fb | ||
|
|
f02e59df1b | ||
|
|
04147a2fe9 | ||
|
|
0e83bc31dc | ||
|
|
75a5f7960f | ||
|
|
3f93c27b07 | ||
|
|
ab781d4516 | ||
|
|
446438bf8c | ||
|
|
4e012cbd48 | ||
|
|
12ee4a792c | ||
|
|
e59750386f | ||
|
|
4e19d54867 | ||
|
|
db603e5438 | ||
|
|
5320cb123a | ||
|
|
30a2ebdbb4 | ||
|
|
a5d43998a3 | ||
|
|
2792caec70 | ||
|
|
fb2b1e984c | ||
|
|
13ab1caf95 | ||
|
|
5d4534fac4 | ||
|
|
f450643861 | ||
|
|
fc14a65511 | ||
|
|
bbd1e27c5e | ||
|
|
369a83b718 | ||
|
|
afc541b956 | ||
|
|
7e4d2ffb4d | ||
|
|
e09913a94f | ||
|
|
b4d1c4cc04 | ||
|
|
22537c0e7e | ||
|
|
39c0db8d6a | ||
|
|
9db12761f7 | ||
|
|
0f8a7c4817 | ||
|
|
47e59a55c5 | ||
|
|
b3496f4e5d | ||
|
|
e866228afd | ||
|
|
4aeaa5251e | ||
|
|
b36988e64a | ||
|
|
393aefce8f | ||
|
|
227ff1b8be | ||
|
|
82086a93b0 | ||
|
|
abd97cc1c9 | ||
|
|
3315fae83e | ||
|
|
d8c3c3f7f0 | ||
|
|
23459879f8 | ||
|
|
f1ca916d58 | ||
|
|
6aae012ae5 | ||
|
|
516983427a | ||
|
|
05d78c92f9 | ||
|
|
dc57144472 | ||
|
|
dd260ca45e | ||
|
|
3bc2fc4151 | ||
|
|
6c58eaa7e8 | ||
|
|
e1a1c11a01 | ||
|
|
95a6b4264d | ||
|
|
4782a4e07d | ||
|
|
dbc14206dc | ||
|
|
f4296d8858 | ||
|
|
75c4c2286d | ||
|
|
b14237e8e6 | ||
|
|
df3263e4bd | ||
|
|
ff7b413abf | ||
|
|
07224779e6 | ||
|
|
c031a3c24e | ||
|
|
1e74f7912c | ||
|
|
d91f8d0876 | ||
|
|
43d4644fba | ||
|
|
61a924d208 | ||
|
|
2692f2c1bf | ||
|
|
88b3c87bae | ||
|
|
7fd7dfd937 | ||
|
|
9a76f02709 | ||
|
|
81cc1c73c1 | ||
|
|
eabda8f0f7 | ||
|
|
cb3917457b | ||
|
|
2c4f36a8f9 | ||
|
|
d458be99bc | ||
|
|
a7f4531767 | ||
|
|
08f5a1ad06 | ||
|
|
f2de24c851 | ||
|
|
ed1eca8fb5 | ||
|
|
f792e6f13d | ||
|
|
b1782b7a97 | ||
|
|
f3c3966e00 | ||
|
|
8a9f72c96b | ||
|
|
402d3a16ae | ||
|
|
458e228b91 | ||
|
|
a817f09441 | ||
|
|
413ba85538 | ||
|
|
c1807bf1c3 | ||
|
|
09dd65499a | ||
|
|
640552abad | ||
|
|
faee1848e5 | ||
|
|
c7a217fea7 | ||
|
|
e4ae19a625 | ||
|
|
24fe6ee583 | ||
|
|
9cba754eb6 | ||
|
|
9e6bb5e844 | ||
|
|
a74ee255fb | ||
|
|
b9fc0c0365 | ||
|
|
2ce16c74f7 | ||
|
|
6d0ea5c6f9 | ||
|
|
b83ef112a9 | ||
|
|
dd9110a3a8 | ||
|
|
88c23e1b0f | ||
|
|
dbe40e3ad6 | ||
|
|
958d3b05c8 | ||
|
|
4e7b0baafb | ||
|
|
b3dc38f2d8 | ||
|
|
6044d3dce3 | ||
|
|
29446f2122 | ||
|
|
abb8673549 | ||
|
|
ffc8f9dcdf | ||
|
|
288b2bb720 | ||
|
|
fb3b7bda68 | ||
|
|
6d5efe1cbd | ||
|
|
1ceec22184 | ||
|
|
951ff9b953 | ||
|
|
641f06a7e7 | ||
|
|
915ba4ac21 | ||
|
|
824637d83f | ||
|
|
0871406fe3 | ||
|
|
1ad7e47b2e | ||
|
|
f72a2c69d0 | ||
|
|
84d9275cb8 | ||
|
|
1b7c387c8b | ||
|
|
2f1adbd22c | ||
|
|
65031523a6 | ||
|
|
02cc0fa0f6 | ||
|
|
1e1afa023f | ||
|
|
41f343c2cd | ||
|
|
a73c4deaca | ||
|
|
01a21aebc4 | ||
|
|
49434043f2 | ||
|
|
2e23877912 | ||
|
|
b737dd7df4 | ||
|
|
137ffaf768 | ||
|
|
747c6d30d2 |
22
.clang-format
Normal file
22
.clang-format
Normal file
@@ -0,0 +1,22 @@
|
||||
BasedOnStyle: LLVM
|
||||
UseTab: AlignWithSpaces
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
BreakBeforeBraces: Allman
|
||||
ColumnLimit: 0
|
||||
NamespaceIndentation: Inner
|
||||
FixNamespaceComments: true
|
||||
AccessModifierOffset: -2
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
IndentCaseLabels: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BraceWrapping:
|
||||
BeforeLambdaBody: false
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
Cpp11BracedListStyle: false
|
||||
IncludeBlocks: Regroup
|
||||
LambdaBodyIndentation: Signature
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
IndentPPDirectives: AfterHash
|
||||
PPIndentWidth: 1
|
||||
65
.github/workflows/build-documentation.yml
vendored
Normal file
65
.github/workflows/build-documentation.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
|
||||
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
|
||||
name: publish docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "trunk" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set reusable strings
|
||||
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
|
||||
id: strings
|
||||
shell: bash
|
||||
run: |
|
||||
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install dependencies Ubuntu
|
||||
run: sudo apt-get update && sudo apt-get install cmake doxygen
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
cache: 'pip' # caching pip dependencies
|
||||
- run: pip install -r docs/requirements.txt
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake -S . -B ${{ steps.strings.outputs.build-output-dir }} -DBUILD_DOCUMENTATION=ON -DBUILD_TESTING=OFF
|
||||
|
||||
- name: Run Sphinx
|
||||
run: |
|
||||
cmake --build ${{ steps.strings.outputs.build-output-dir }} --target Sphinx-libcifpp
|
||||
ls -l ${{ steps.strings.outputs.build-output-dir }}
|
||||
ls -l ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
needs: docs
|
||||
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
64
.github/workflows/cmake-multi-platform.yml
vendored
Normal file
64
.github/workflows/cmake-multi-platform.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: multi platform test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "trunk", "develop" ]
|
||||
pull_request:
|
||||
branches: [ "trunk" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
cpp_compiler: cl
|
||||
- os: ubuntu-latest
|
||||
cpp_compiler: g++
|
||||
- os: macos-latest
|
||||
cpp_compiler: clang++
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set reusable strings
|
||||
id: strings
|
||||
shell: bash
|
||||
run: echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install dependencies Ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update && sudo apt-get install mrc catch2
|
||||
|
||||
- name: Install dependencies Window
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: ./tools/depends.cmd
|
||||
shell: cmd
|
||||
|
||||
- name: Install Catch2 macOS
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: >
|
||||
brew install catch2
|
||||
|
||||
- name: Configure CMake
|
||||
run: >
|
||||
cmake -B ${{ steps.strings.outputs.build-output-dir }}
|
||||
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-S ${{ github.workspace }}
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config Release
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{ steps.strings.outputs.build-output-dir }}
|
||||
run: ctest --build-config Release --output-on-failure
|
||||
|
||||
- name: Install
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: sudo cmake --install ${{ steps.strings.outputs.build-output-dir }} --config Release
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -2,7 +2,7 @@ build/
|
||||
.vscode/
|
||||
.vs/
|
||||
tools/update-libcifpp-data
|
||||
data/components.cif*
|
||||
rsrc/components.cif*
|
||||
CMakeSettings.json
|
||||
msvc/
|
||||
src/revision.hpp
|
||||
@@ -10,4 +10,9 @@ test/test-create_sugar_?.cif
|
||||
Testing/
|
||||
include/cif++/exports.hpp
|
||||
docs/api
|
||||
docs/conf.py
|
||||
docs/conf.py
|
||||
build_ci/
|
||||
data/components.cif
|
||||
perf.data*
|
||||
.cache/
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: "ubuntu-22.04"
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
apt_packages:
|
||||
- "doxygen"
|
||||
- "cmake"
|
||||
- doxygen
|
||||
- cmake
|
||||
jobs:
|
||||
pre_build:
|
||||
- "cmake -S . -B build -DBUILD_DOCUMENTATION=ON"
|
||||
- "cmake --build build --target Doxygen"
|
||||
- cmake -S . -B build -DBUILD_DOCUMENTATION=ON
|
||||
- cmake --build build --target Doxygen
|
||||
|
||||
# Build from the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
|
||||
716
CMakeLists.txt
716
CMakeLists.txt
@@ -11,88 +11,92 @@
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
# set the project name
|
||||
project(libcifpp VERSION 5.2.0 LANGUAGES CXX)
|
||||
project(
|
||||
libcifpp
|
||||
VERSION 9.0.5
|
||||
LANGUAGES CXX C)
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckLibraryExists)
|
||||
include(FindAtomic)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(GenerateExportHeader)
|
||||
include(CTest)
|
||||
include(ExternalProject)
|
||||
include(FetchContent)
|
||||
include(VersionString)
|
||||
|
||||
set(CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
# When building with ninja-multiconfig, build both debug and release by default
|
||||
if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
|
||||
set(CMAKE_CROSS_CONFIGS "Debug;Release")
|
||||
set(CMAKE_DEFAULT_CONFIGS "Debug;Release")
|
||||
endif()
|
||||
|
||||
# set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
# set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers"
|
||||
)
|
||||
elseif(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
|
||||
# Building shared libraries?
|
||||
option(BUILD_SHARED_LIBS "Build a shared library instead of a static one" OFF)
|
||||
|
||||
# Build documentation?
|
||||
option(BUILD_DOC "Build the documentation" OFF)
|
||||
|
||||
# We do not want to write an export file for all our symbols...
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(BUILD_DOCUMENTATION OFF CACHE BOOL "Build the documentation")
|
||||
|
||||
# Optionally build a version to be installed inside CCP4
|
||||
option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4" OFF)
|
||||
set(BUILD_FOR_CCP4 OFF CACHE BOOL "Build a version to be installed in CCP4")
|
||||
|
||||
# Lots of code depend on the availability of the components.cif file
|
||||
option(CIFPP_DOWNLOAD_CCD "Download the CCD file components.cif during installation" ON)
|
||||
|
||||
# An optional cron script can be installed to keep the data files up-to-date
|
||||
if(UNIX)
|
||||
option(CIFPP_INSTALL_UPDATE_SCRIPT "Install the script to update CCD and dictionary files" ON)
|
||||
# Building shared libraries?
|
||||
if(NOT(BUILD_FOR_CCP4 AND WIN32))
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build a shared library instead of a static one")
|
||||
endif()
|
||||
|
||||
# When CCP4 is sourced in the environment, we can recreate the symmetry operations table
|
||||
if(EXISTS "$ENV{CCP4}")
|
||||
if(EXISTS "$ENV{CLIBD}/syminfo.lib")
|
||||
option(CIFPP_RECREATE_SYMOP_DATA "Recreate SymOp data table in case it is out of date" ON)
|
||||
else()
|
||||
set(CIFPP_RECREATE_SYMOP_DATA OFF)
|
||||
message(WARNING "Symop data table recreation requested, but file syminfo.lib was not found in $ENV{CLIBD}")
|
||||
if(PROJECT_IS_TOP_LEVEL AND NOT BUILD_FOR_CCP4)
|
||||
# Lots of code depend on the availability of the components.cif file
|
||||
set(CIFPP_DOWNLOAD_CCD ON CACHE BOOL "Download the CCD file components.cif during installation")
|
||||
|
||||
# An optional cron script can be installed to keep the data files up-to-date
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(CIFPP_INSTALL_UPDATE_SCRIPT ON CACHE BOOL "Install the script to update CCD and dictionary files")
|
||||
endif()
|
||||
else()
|
||||
set(CIFPP_RECREATE_SYMOP_DATA OFF)
|
||||
message("Not trying to recreate symop_table_data.hpp since CCP4 is not defined")
|
||||
unset(CIFPP_DOWNLOAD_CCD)
|
||||
unset(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
endif()
|
||||
|
||||
# Unit tests
|
||||
option(ENABLE_TESTING "Build test exectuables" OFF)
|
||||
# When CCP4 is sourced in the environment, we can recreate the symmetry
|
||||
# operations table
|
||||
if(EXISTS "$ENV{CCP4}/lib/data/syminfo.lib")
|
||||
set(CIFPP_RECREATE_SYMOP_DATA ON CACHE BOOL "Recreate SymOp data table in case it is out of date")
|
||||
endif()
|
||||
|
||||
# CCP4 build
|
||||
if(BUILD_FOR_CCP4)
|
||||
if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
|
||||
message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced")
|
||||
message(FATAL_ERROR "cifpp: A CCP4 built was requested but CCP4 was not sourced")
|
||||
else()
|
||||
list(APPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
list(PREPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(PREPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_FULL_DATADIR "${CMAKE_INSTALL_PREFIX}/share/libcifpp")
|
||||
|
||||
if(WIN32)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
@@ -100,28 +104,34 @@ if(BUILD_FOR_CCP4)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(${CMAKE_SYSTEM_VERSION} GREATER_EQUAL 10) # Windows 10
|
||||
add_definitions(-D _WIN32_WINNT=0x0A00)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.3) # Windows 8.1
|
||||
add_definitions(-D _WIN32_WINNT=0x0603)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.2) # Windows 8
|
||||
add_definitions(-D _WIN32_WINNT=0x0602)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.1) # Windows 7
|
||||
add_definitions(-D _WIN32_WINNT=0x0601)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.0) # Windows Vista
|
||||
add_definitions(-D _WIN32_WINNT=0x0600)
|
||||
else() # Windows XP (5.1)
|
||||
add_definitions(-D _WIN32_WINNT=0x0501)
|
||||
endif()
|
||||
# Now include the GNUInstallDirs module
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_definitions(-DNOMINMAX)
|
||||
if(WIN32)
|
||||
if(${CMAKE_SYSTEM_VERSION} GREATER_EQUAL 10) # Windows 10
|
||||
add_definitions(-D _WIN32_WINNT=0x0A00)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.3) # Windows 8.1
|
||||
add_definitions(-D _WIN32_WINNT=0x0603)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.2) # Windows 8
|
||||
add_definitions(-D _WIN32_WINNT=0x0602)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.1) # Windows 7
|
||||
add_definitions(-D _WIN32_WINNT=0x0601)
|
||||
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.0) # Windows Vista
|
||||
add_definitions(-D _WIN32_WINNT=0x0600)
|
||||
else() # Windows XP (5.1)
|
||||
add_definitions(-D _WIN32_WINNT=0x0501)
|
||||
endif()
|
||||
|
||||
# We do not want to write an export file for all our symbols...
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# make msvc standards compliant...
|
||||
add_compile_options(/permissive-)
|
||||
# make msvc standards compliant...
|
||||
add_compile_options(/permissive- /bigobj)
|
||||
add_link_options(/NODEFAULTLIB:library)
|
||||
|
||||
# This is dubious...
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
else()
|
||||
@@ -131,37 +141,9 @@ endif()
|
||||
|
||||
# Libraries
|
||||
|
||||
# Start by finding out if std:regex is usable. Note that the current
|
||||
# implementation in GCC is not acceptable, it crashes on long lines.
|
||||
# The implementation in libc++ (clang) and MSVC seem to be OK.
|
||||
check_cxx_source_compiles("
|
||||
#include <iostream>
|
||||
#ifndef __GLIBCXX__
|
||||
#error
|
||||
#endif
|
||||
int main(int argc, char *argv[]) { return 0; }" GXX_LIBSTDCPP)
|
||||
|
||||
if(GXX_LIBSTDCPP)
|
||||
message(STATUS "Testing for known regex bug, since you're using GNU libstdc++")
|
||||
|
||||
try_run(STD_REGEX_RUNNING STD_REGEX_COMPILING
|
||||
${CMAKE_CURRENT_BINARY_DIR}/test ${PROJECT_SOURCE_DIR}/cmake/test-rx.cpp)
|
||||
|
||||
if(STD_REGEX_RUNNING STREQUAL FAILED_TO_RUN)
|
||||
message(STATUS "You are probably trying to compile using the g++ standard library which contains a crashing std::regex implementation. Will use boost::regex instead")
|
||||
|
||||
add_subdirectory(regex EXCLUDE_FROM_ALL)
|
||||
set(BOOST_REGEX ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG)
|
||||
find_package(Threads)
|
||||
|
||||
if(MSVC)
|
||||
# Avoid linking the shared library of zlib
|
||||
# Search ZLIB_ROOT first if it is set.
|
||||
# Avoid linking the shared library of zlib. Search ZLIB_ROOT first if it is
|
||||
# set.
|
||||
if(ZLIB_ROOT)
|
||||
set(_ZLIB_SEARCH_ROOT PATHS ${ZLIB_ROOT} NO_DEFAULT_PATH)
|
||||
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_ROOT)
|
||||
@@ -171,132 +153,204 @@ if(MSVC)
|
||||
set(_ZLIB_x86 "(x86)")
|
||||
set(_ZLIB_SEARCH_NORMAL
|
||||
PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]"
|
||||
"$ENV{ProgramFiles}/zlib"
|
||||
"$ENV{ProgramFiles${_ZLIB_x86}}/zlib")
|
||||
"$ENV{ProgramFiles}/zlib" "$ENV{ProgramFiles${_ZLIB_x86}}/zlib")
|
||||
unset(_ZLIB_x86)
|
||||
list(APPEND _ZLIB_SEARCHES _ZLIB_SEARCH_NORMAL)
|
||||
|
||||
if(BUILD_FOR_CCP4)
|
||||
list(PREPEND _ZLIB_SEARCHES "$ENV{CCP4}/lib")
|
||||
endif()
|
||||
|
||||
foreach(search ${_ZLIB_SEARCHES})
|
||||
find_library(ZLIB_LIBRARY NAMES zlibstatic NAMES_PER_DIR ${${search}} PATH_SUFFIXES lib)
|
||||
find_library(
|
||||
ZLIB_LIBRARY
|
||||
NAMES zlibstatic NAMES_PER_DIR ${${search}}
|
||||
PATH_SUFFIXES lib)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
find_package(Eigen3 REQUIRED)
|
||||
# Using fast_float for float parsing, but only if needed
|
||||
try_compile(STD_CHARCONV_COMPILING
|
||||
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-charconv.cpp)
|
||||
|
||||
include(FindFilesystem)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY})
|
||||
|
||||
include(FindAtomic)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPATOMIC_LIBRARY})
|
||||
|
||||
if(MSVC)
|
||||
# this dependency can go once MSVC supports std::experimental::is_detected
|
||||
find_package(zeep 5.1.8 REQUIRED)
|
||||
list(APPEND CIFPP_REQUIRED_LIBRARIES zeep::zeep)
|
||||
if(NOT STD_CHARCONV_COMPILING)
|
||||
message(NOTICE "libcifpp: Using fast_float for std::from_chars")
|
||||
FetchContent_Declare(fastfloat
|
||||
GIT_REPOSITORY "https://github.com/fastfloat/fast_float"
|
||||
GIT_TAG v8.0.2
|
||||
EXCLUDE_FROM_ALL)
|
||||
FetchContent_MakeAvailable(fastfloat)
|
||||
endif()
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
include(VersionString)
|
||||
write_version_header(${PROJECT_SOURCE_DIR}/src/ LIB_NAME "LibCIFPP")
|
||||
find_package(Threads)
|
||||
find_package(ZLIB QUIET)
|
||||
|
||||
if(NOT ZLIB_FOUND)
|
||||
message(FATAL_ERROR "cifpp: The zlib development files were not found you this system, please install them and try again (hint: on debian/ubuntu use apt-get install zlib1g-dev)")
|
||||
endif()
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PCRE2 IMPORTED_TARGET libpcre2-8)
|
||||
endif()
|
||||
|
||||
if(NOT PCRE2_FOUND)
|
||||
add_subdirectory(pcre2-simple)
|
||||
endif()
|
||||
|
||||
# Using Eigen3 is a bit of a thing. We don't want to build it completely since
|
||||
# we only need a couple of header files. Nothing special. But often, eigen3 is
|
||||
# already installed and then we prefer that.
|
||||
find_package(Eigen3 3.4 QUIET)
|
||||
|
||||
if(Eigen3_FOUND AND TARGET Eigen3::Eigen)
|
||||
get_target_property(EIGEN_INCLUDE_DIR Eigen3::Eigen
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
# Use ExternalProject since FetchContent always tries to install the result...
|
||||
ExternalProject_Add(my-eigen3
|
||||
URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.zip
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
ExternalProject_Get_Property(my-eigen3 SOURCE_DIR)
|
||||
set(EIGEN_INCLUDE_DIR ${SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# SymOp data table
|
||||
if(CIFPP_RECREATE_SYMOP_DATA)
|
||||
# The tool to create the table
|
||||
add_executable(symop-map-generator "${PROJECT_SOURCE_DIR}/src/symop-map-generator.cpp")
|
||||
add_executable(symop-map-generator
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/symop-map-generator.cpp")
|
||||
|
||||
target_compile_features(symop-map-generator PUBLIC cxx_std_20)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
COMMAND $<TARGET_FILE:symop-map-generator> $ENV{CLIBD}/syminfo.lib $ENV{CLIBD}/symop.lib ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
)
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
COMMAND
|
||||
$<TARGET_FILE:symop-map-generator> $ENV{CLIBD}/syminfo.lib
|
||||
$ENV{CLIBD}/symop.lib ${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
|
||||
add_custom_target(
|
||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib" "$ENV{CLIBD}/symop.lib"
|
||||
)
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib"
|
||||
"$ENV{CLIBD}/symop.lib")
|
||||
endif()
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
write_version_header("${CMAKE_CURRENT_SOURCE_DIR}/src/" LIB_NAME "LibCIFPP")
|
||||
|
||||
# Sources
|
||||
set(project_sources
|
||||
${PROJECT_SOURCE_DIR}/src/category.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/condition.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/datablock.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/file.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/item.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/parser.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/row.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/validate.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/text.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/utilities.cpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/src/atom_type.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/compound.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/point.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/symmetry.cpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/src/model.cpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/category.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/condition.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/datablock.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/file.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/item.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/row.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/validate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/text.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utilities.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/atom_type.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/compound.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/point.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/symmetry.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/model.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/reconstruct.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/validate-pdbx.cpp
|
||||
)
|
||||
|
||||
set(project_headers
|
||||
${PROJECT_SOURCE_DIR}/include/cif++.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/utilities.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/item.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/datablock.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/file.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/validate.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/iterator.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/parser.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/forward_decl.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/dictionary_parser.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/condition.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/category.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/row.hpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/atom_type.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/compound.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/point.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/symmetry.hpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/model.hpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb.hpp
|
||||
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/cif2pdb.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/io.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/pdb2cif.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/cif++/pdb/tls.hpp
|
||||
include/cif++.hpp
|
||||
include/cif++/atom_type.hpp
|
||||
include/cif++/category.hpp
|
||||
include/cif++/compound.hpp
|
||||
include/cif++/condition.hpp
|
||||
include/cif++/datablock.hpp
|
||||
include/cif++/dictionary_parser.hpp
|
||||
include/cif++/exports.hpp
|
||||
include/cif++/file.hpp
|
||||
include/cif++/format.hpp
|
||||
include/cif++/forward_decl.hpp
|
||||
include/cif++/gzio.hpp
|
||||
include/cif++/item.hpp
|
||||
include/cif++/iterator.hpp
|
||||
include/cif++/matrix.hpp
|
||||
include/cif++/model.hpp
|
||||
include/cif++/parser.hpp
|
||||
include/cif++/pdb/cif2pdb.hpp
|
||||
include/cif++/pdb.hpp
|
||||
include/cif++/pdb/io.hpp
|
||||
include/cif++/pdb/pdb2cif.hpp
|
||||
include/cif++/pdb/tls.hpp
|
||||
include/cif++/point.hpp
|
||||
include/cif++/row.hpp
|
||||
include/cif++/symmetry.hpp
|
||||
include/cif++/text.hpp
|
||||
include/cif++/utilities.hpp
|
||||
include/cif++/validate.hpp
|
||||
)
|
||||
|
||||
add_library(cifpp ${project_sources} ${project_headers} ${PROJECT_SOURCE_DIR}/src/symop_table_data.hpp)
|
||||
add_library(cifpp)
|
||||
add_library(cifpp::cifpp ALIAS cifpp)
|
||||
generate_export_header(cifpp EXPORT_FILE_NAME ${PROJECT_SOURCE_DIR}/include/cif++/exports.hpp)
|
||||
|
||||
if(BOOST_REGEX)
|
||||
target_compile_definitions(cifpp PRIVATE USE_BOOST_REGEX=1 BOOST_REGEX_STANDALONE=1)
|
||||
target_include_directories(cifpp PRIVATE regex/include)
|
||||
if(TARGET my-eigen3)
|
||||
add_dependencies(cifpp my-eigen3)
|
||||
endif()
|
||||
|
||||
target_sources(cifpp
|
||||
PRIVATE ${project_sources}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
PUBLIC
|
||||
FILE_SET cifpp_headers TYPE HEADERS
|
||||
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
FILES ${project_headers}
|
||||
)
|
||||
|
||||
# The code now really requires C++20
|
||||
target_compile_features(cifpp PUBLIC cxx_std_20)
|
||||
|
||||
generate_export_header(cifpp EXPORT_FILE_NAME
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/cif++/exports.hpp)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_definitions(cifpp PUBLIC NOMINMAX=1)
|
||||
endif()
|
||||
|
||||
set_target_properties(cifpp PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(cifpp
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include;${PROJECT_BINARY_DIR};${EIGEN3_INCLUDE_DIR}>"
|
||||
target_include_directories(
|
||||
cifpp
|
||||
PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
PRIVATE "${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB Eigen3::Eigen ${CIFPP_REQUIRED_LIBRARIES})
|
||||
target_link_libraries(cifpp
|
||||
PUBLIC Threads::Threads ZLIB::ZLIB $<$<TARGET_EXISTS:std::atomic>:std::atomic>)
|
||||
|
||||
if(PCRE2_FOUND)
|
||||
target_include_directories(cifpp PRIVATE ${PCRE2_INCLUDE_DIRS})
|
||||
target_link_libraries(cifpp PRIVATE ${PCRE2_LINK_LIBRARIES})
|
||||
else()
|
||||
target_link_libraries(cifpp PRIVATE $<BUILD_INTERFACE:pcre2s>)
|
||||
endif()
|
||||
|
||||
if(NOT STD_CHARCONV_COMPILING)
|
||||
target_link_libraries(cifpp PRIVATE FastFloat::fast_float)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
@@ -304,192 +358,204 @@ endif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
|
||||
if(CIFPP_DOWNLOAD_CCD)
|
||||
# download the components.cif file from CCD
|
||||
set(COMPONENTS_CIF ${PROJECT_SOURCE_DIR}/data/components.cif)
|
||||
set(COMPONENTS_CIF ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/components.cif)
|
||||
|
||||
if(NOT EXISTS ${COMPONENTS_CIF})
|
||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/data)
|
||||
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/data/)
|
||||
if(EXISTS ${COMPONENTS_CIF})
|
||||
file(SIZE ${COMPONENTS_CIF} CCD_FILE_SIZE)
|
||||
|
||||
if(CCD_FILE_SIZE EQUAL 0)
|
||||
message(STATUS "cifpp: Removing empty ${COMPONENTS_CIF} file")
|
||||
file(REMOVE "${COMPONENTS_CIF}")
|
||||
endif()
|
||||
|
||||
file(DOWNLOAD https://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif ${COMPONENTS_CIF} SHOW_PROGRESS)
|
||||
endif()
|
||||
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
if(NOT EXISTS ${COMPONENTS_CIF})
|
||||
# Since the file(DOWNLOAD) command in cmake does not use compression, we try
|
||||
# to download the gzipped version and decompress it ourselves.
|
||||
find_program(GUNZIP gunzip)
|
||||
|
||||
if(WIN32 OR GUNZIP STREQUAL "GUNZIP-NOTFOUND")
|
||||
file(
|
||||
DOWNLOAD https://files.wwpdb.org/pub/pdb/data/monomers/components.cif
|
||||
${COMPONENTS_CIF}
|
||||
SHOW_PROGRESS
|
||||
STATUS CCD_FETCH_STATUS)
|
||||
else()
|
||||
if(NOT EXISTS "${COMPONENTS_CIF}.gz")
|
||||
file(
|
||||
DOWNLOAD
|
||||
https://files.wwpdb.org/pub/pdb/data/monomers/components.cif.gz
|
||||
${COMPONENTS_CIF}.gz
|
||||
SHOW_PROGRESS
|
||||
STATUS CCD_FETCH_STATUS)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${COMPONENTS_CIF}
|
||||
COMMAND "${GUNZIP}" ${COMPONENTS_CIF}.gz
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/)
|
||||
|
||||
add_custom_target(COMPONENTS ALL DEPENDS ${COMPONENTS_CIF})
|
||||
endif()
|
||||
|
||||
# Do not continue if downloading went wrong
|
||||
list(POP_FRONT CCD_FETCH_STATUS CCD_FETCH_STATUS_CODE)
|
||||
|
||||
if(CCD_FETCH_STATUS_CODE)
|
||||
message(
|
||||
FATAL_ERROR "cifpp: Error trying to download CCD file: ${CCD_FETCH_STATUS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Installation directories
|
||||
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/libcifpp")
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
if(BUILD_FOR_CCP4)
|
||||
set(CIFPP_DATA_DIR
|
||||
"$ENV{CCP4}/share/libcifpp"
|
||||
CACHE PATH "Directory where dictionary and other static data is stored")
|
||||
else()
|
||||
set(CIFPP_DATA_DIR
|
||||
"${CMAKE_INSTALL_FULL_DATADIR}/libcifpp"
|
||||
CACHE PATH "Directory where dictionary and other static data is stored")
|
||||
endif()
|
||||
|
||||
if(CIFPP_DATA_DIR)
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
set_target_properties(cifpp PROPERTIES CIFPP_DATA_DIR ${CIFPP_DATA_DIR})
|
||||
endif()
|
||||
|
||||
if(NOT PROJECT_IS_TOP_LEVEL)
|
||||
set(CIFPP_SHARE_DIR ${CIFPP_DATA_DIR} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT BUILD_FOR_CCP4)
|
||||
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local")
|
||||
set(CIFPP_CACHE_DIR
|
||||
"/var/cache/libcifpp"
|
||||
CACHE PATH "The directory where downloaded data files are stored")
|
||||
else()
|
||||
set(CIFPP_CACHE_DIR
|
||||
"${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp"
|
||||
CACHE PATH "The directory where downloaded data files are stored")
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
set(CIFPP_CACHE_DIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
|
||||
set(CIFPP_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
|
||||
set(CIFPP_ETC_DIR
|
||||
"${CMAKE_INSTALL_FULL_SYSCONFDIR}"
|
||||
CACHE PATH "The directory where the update configuration file is stored")
|
||||
else()
|
||||
unset(CIFPP_CACHE_DIR)
|
||||
endif()
|
||||
|
||||
# Install rules
|
||||
install(TARGETS cifpp
|
||||
EXPORT cifppTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
EXPORT cifpp
|
||||
FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:${PROJECT_NAME}>
|
||||
FILES $<TARGET_PDB_FILE:cifpp>
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OPTIONAL)
|
||||
endif()
|
||||
|
||||
install(EXPORT cifppTargets
|
||||
FILE "cifppTargets.cmake"
|
||||
NAMESPACE cifpp::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
|
||||
)
|
||||
# Clean up old config files (with old names)
|
||||
file(GLOB OLD_CONFIG_FILES
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppConfig*.cmake
|
||||
${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cifpp/cifppTargets*.cmake)
|
||||
|
||||
install(
|
||||
DIRECTORY include/cif++
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
install(
|
||||
FILES include/cif++.hpp
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${PROJECT_BINARY_DIR}/cif++/exports.hpp
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cif++
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ma.dic
|
||||
${COMPONENTS_CIF}
|
||||
DESTINATION ${CIFPP_DATA_DIR}
|
||||
)
|
||||
|
||||
if(${CIFPP_CACHE_DIR})
|
||||
install(FILES
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${PROJECT_SOURCE_DIR}/rsrc/mmcif_ma.dic
|
||||
${COMPONENTS_CIF}
|
||||
DESTINATION ${CIFPP_CACHE_DIR}
|
||||
)
|
||||
if(OLD_CONFIG_FILES)
|
||||
message(
|
||||
STATUS "cifpp: Installation will remove old config files: ${OLD_CONFIG_FILES}")
|
||||
install(CODE "file(REMOVE ${OLD_CONFIG_FILES})")
|
||||
endif()
|
||||
|
||||
set(CONFIG_TEMPLATE_FILE ${PROJECT_SOURCE_DIR}/cmake/cifppConfig.cmake.in)
|
||||
install(EXPORT cifpp
|
||||
NAMESPACE cifpp::
|
||||
FILE "cifpp-targets.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ma.dic
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
|
||||
if(CIFPP_DATA_DIR AND CIFPP_DOWNLOAD_CCD)
|
||||
install(FILES ${COMPONENTS_CIF}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
endif()
|
||||
|
||||
set(CONFIG_TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cifpp-config.cmake.in)
|
||||
|
||||
configure_package_config_file(
|
||||
${CONFIG_TEMPLATE_FILE}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfig.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
|
||||
PATH_VARS CIFPP_DATA_DIR
|
||||
)
|
||||
${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake
|
||||
INSTALL_DESTINATION lib/cmake/cifpp
|
||||
PATH_VARS CIFPP_DATA_DIR)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfigVersion.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
|
||||
COMPONENT Devel
|
||||
)
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
set(cifpp_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR})
|
||||
set_target_properties(cifpp PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${cifpp_MAJOR_VERSION}.${cifpp_MINOR_VERSION}"
|
||||
INTERFACE_cifpp_MAJOR_VERSION ${cifpp_MAJOR_VERSION})
|
||||
set_target_properties(
|
||||
cifpp
|
||||
PROPERTIES VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
INTERFACE_cifpp_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
|
||||
|
||||
set_property(TARGET cifpp APPEND PROPERTY
|
||||
COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION
|
||||
)
|
||||
set_property(
|
||||
TARGET cifpp
|
||||
APPEND
|
||||
PROPERTY COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfigVersion.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
if(ENABLE_TESTING)
|
||||
enable_testing()
|
||||
|
||||
find_package(Boost REQUIRED)
|
||||
|
||||
list(APPEND CIFPP_tests unit-v2 unit-3d format model rename-compound sugar spinner)
|
||||
|
||||
foreach(CIFPP_TEST IN LISTS CIFPP_tests)
|
||||
set(CIFPP_TEST "${CIFPP_TEST}-test")
|
||||
set(CIFPP_TEST_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/test/${CIFPP_TEST}.cpp")
|
||||
|
||||
add_executable(${CIFPP_TEST} ${CIFPP_TEST_SOURCE})
|
||||
|
||||
target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp::cifpp Boost::boost)
|
||||
|
||||
if(MSVC)
|
||||
# Specify unwind semantics so that MSVC knowns how to handle exceptions
|
||||
target_compile_options(${CIFPP_TEST} PRIVATE /EHsc)
|
||||
endif()
|
||||
|
||||
add_custom_target("run-${CIFPP_TEST}" DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch ${CIFPP_TEST})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Run${CIFPP_TEST}.touch
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||
|
||||
add_test(NAME ${CIFPP_TEST}
|
||||
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||
endforeach()
|
||||
if(BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# Optionally install the update scripts for CCD and dictionary files
|
||||
if(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "GNU")
|
||||
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/cron.weekly")
|
||||
elseif(UNIX) # assume all others are like FreeBSD...
|
||||
set(CIFPP_CRON_DIR "${CIFPP_ETC_DIR}/periodic/weekly")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tools/update-libcifpp-data.in
|
||||
update-libcifpp-data @ONLY)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "GNU" OR
|
||||
${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-libcifpp-data
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cron.weekly
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE
|
||||
WORLD_READ)
|
||||
else()
|
||||
message(FATAL_ERROR "Don't know where to install the update script")
|
||||
message(FATAL_ERROR "cifpp: Don't know where to install the update script")
|
||||
endif()
|
||||
|
||||
configure_file(${PROJECT_SOURCE_DIR}/tools/update-libcifpp-data.in update-libcifpp-data @ONLY)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/update-libcifpp-data
|
||||
DESTINATION ${CIFPP_CRON_DIR}
|
||||
PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
|
||||
)
|
||||
|
||||
install(DIRECTORY DESTINATION ${CIFPP_CACHE_DIR})
|
||||
install(DIRECTORY DESTINATION "${CIFPP_ETC_DIR}/libcifpp/cache-update.d")
|
||||
|
||||
# a config to, to make it complete
|
||||
if(NOT EXISTS "${CIFPP_ETC_DIR}/libcifpp.conf")
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf [[# Uncomment the next line to enable automatic updates
|
||||
# a config file, to make it complete
|
||||
# install(DIRECTORY DESTINATION "${CMAKE_INSTALL_LOCALSTATEDIR}/libcifpp")
|
||||
if(NOT EXISTS "${CMAKE_INSTALL_SYSCONFDIR}/libcifpp.conf")
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
[[# Uncomment the next line to enable automatic updates
|
||||
# update=true
|
||||
]])
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf DESTINATION "${CIFPP_ETC_DIR}")
|
||||
install(CODE "message(\"A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")")
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.conf
|
||||
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR})
|
||||
install(
|
||||
CODE "message(\"cifpp: A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")"
|
||||
)
|
||||
|
||||
install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/libcifpp/cache-update.d)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
endif()
|
||||
|
||||
if(BUILD_DOC)
|
||||
if(BUILD_DOCUMENTATION)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_SOURCE_TGZ ON)
|
||||
set(CPACK_SOURCE_TBZ2 OFF)
|
||||
set(CPACK_SOURCE_TXZ OFF)
|
||||
set(CPACK_SOURCE_TZ OFF)
|
||||
set(CPACK_SOURCE_IGNORE_FILES "/data/components.cif;/build;/.vscode;/.git")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME})
|
||||
include(CPack)
|
||||
|
||||
196
README.md
196
README.md
@@ -1,12 +1,38 @@
|
||||
libcifpp
|
||||
========
|
||||
[](https://github.com/pdb-redo/libcifpp/actions)
|
||||
[](https://github.com/pdb-redo/libcifpp/LICENSE)
|
||||
|
||||
This library contains code to work with mmCIF and legacy PDB files.
|
||||
# libcifpp
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
As the name implies, this library was originally written to work with mmCIF files
|
||||
using C++ as programming language. The design of this library leanes heavily on
|
||||
the structure of CIF files. These files can be thought of as a text dump of a
|
||||
relational databank with, often but not always, a very strict schema describing
|
||||
the data. These schema's are called dictionaries.
|
||||
|
||||
```c++
|
||||
Using information from the content of a mmCIF file and an optional schema,
|
||||
libcifpp allows you to access the data in the file as a collection of datablock
|
||||
each containing a collection of categories with rows of data. The categories can
|
||||
be searched for data using queries written in regular C++ syntax. When a dictionary
|
||||
was specified, inserted data is checked for validity. Likewise removal of data
|
||||
may result in cascaded removal of linked data in other categories using
|
||||
parent/child relationship information.
|
||||
|
||||
Since there were still many programs using the legacy PDB format at the time
|
||||
development started, a layer was added that converts data to and from PDB format
|
||||
into mmCIF format. This means you can manipulate PDB files as if they were
|
||||
normal mmCIF files.
|
||||
|
||||
Apart from this basic functionality, libcifpp also offers code to help with
|
||||
symmetry calculations, 3d manipulations and obtaining information from the CCD
|
||||
[Chemical Component Dictionary](https://www.wwpdb.org/data/ccd).
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation can be found at [github.io](https://pdb-redo.github.io/libcifpp/)
|
||||
|
||||
## Synopsis
|
||||
|
||||
```cpp
|
||||
// A simple program counting residues with an OXT atom
|
||||
|
||||
#include <filesystem>
|
||||
@@ -26,7 +52,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file" << std::endl;
|
||||
std::cerr << "Empty file\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -40,8 +66,8 @@ int main(int argc, char *argv[])
|
||||
auto n = atom_site.count(cif::key("label_atom_id") == "OXT");
|
||||
|
||||
std::cout << "File contains " << atom_site.size() << " atoms of which "
|
||||
<< n << (n == 1 ? " is" : " are") << " OXT" << std::endl
|
||||
<< "residues with an OXT are:" << std::endl;
|
||||
<< n << (n == 1 ? " is" : " are") << " OXT\n"
|
||||
<< "residues with an OXT are:\n";
|
||||
|
||||
// Loop over all atoms with atom-id "OXT" and print out some info.
|
||||
// That info is extracted using structured binding in C++
|
||||
@@ -50,58 +76,146 @@ int main(int argc, char *argv[])
|
||||
cif::key("label_atom_id") == "OXT",
|
||||
"label_asym_id", "label_comp_id", "label_seq_id"))
|
||||
{
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << std::endl;
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Requirements
|
||||
------------
|
||||
## Installation
|
||||
|
||||
You might be able to use libcifpp from a package manager used by your
|
||||
OS distribution. But most likely this package will be out-of-date.
|
||||
Therefore it is recommended to build *libcifpp* from code. It is not
|
||||
hard to do. But it is recommended to read the following instructions
|
||||
carefully.
|
||||
|
||||
### Requirements
|
||||
|
||||
The code for this library was written in C++17. You therefore need a
|
||||
recent compiler to build it. For the development gcc 9.4 and clang 9.0
|
||||
recent compiler to build it. For the development gcc >= 9.4 and clang >= 9.0
|
||||
have been used as well as MSVC version 2019.
|
||||
|
||||
Other requirements are:
|
||||
The other requirement you really need to have installed on your computer
|
||||
is a version of [CMake](https://cmake.org). For now the minimum version
|
||||
is 3.16 but that may soon change into a higher version. You should also
|
||||
install the gui version of CMake to set build options easily, on Debian
|
||||
I prefer to use the curses version installed with `cmake-curses-gui`.
|
||||
|
||||
It is very useful to have [mrc](https://github.com/mhekkel/mrc) available.
|
||||
However, this is only an option if you use Windows or an operating system
|
||||
using the ELF executable format (i.e. Linux or FreeBSD). MRC is a resource
|
||||
compiler that allows including data files into the executable making them
|
||||
easier to install.
|
||||
|
||||
Other libraries you might want to install beforehand are:
|
||||
|
||||
- [mrc](https://github.com/mhekkel/mrc), a resource compiler that
|
||||
allows including data files into the executable making them easier to
|
||||
install. Strictly speaking this is optional, but at the expense of
|
||||
functionality.
|
||||
- [libeigen](https://eigen.tuxfamily.org/index.php?title=Main_Page), a
|
||||
library to do amongst others matrix calculations. This usually can be
|
||||
installed using your package manager, in Debian/Ubuntu it is called
|
||||
`libeigen3-dev`
|
||||
- zlib, the development version of this library. On Debian/Ubuntu this
|
||||
is the package `zlib1g-dev`.
|
||||
- [boost](https://www.boost.org). The boost libraries are only needed if
|
||||
you want to build the testing code.
|
||||
- [zlib](https://github.com/madler/zlib), the development version of this
|
||||
library. On Debian/Ubuntu this is the package `zlib1g-dev`.
|
||||
- [pcre2](https://www.pcre.org/), the Perl Compatible Regular Expression
|
||||
library. On Debian/Ubuntu this is the package `libpcre2-dev`.
|
||||
|
||||
When building using MS Visual Studio, you will also need [libzeep](https://github.com/mhekkel/libzeep)
|
||||
since MSVC does not yet provide a C++ template required by libcifpp.
|
||||
### Building
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
This library uses [cmake](https://cmake.org). The usual way of building
|
||||
and installing is to create a `build` directory and run cmake there.
|
||||
|
||||
On linux e.g. you would issue the following commands to build and install
|
||||
libcifpp in your `$HOME/.local` folder:
|
||||
First you need to download the code:
|
||||
|
||||
```console
|
||||
git clone https://github.com/PDB-REDO/libcifpp.git --recurse-submodules
|
||||
git clone https://github.com/PDB-REDO/libcifpp.git
|
||||
cd libcifpp
|
||||
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$HOME/.local -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
This checks out the source code from github, creates a new directory
|
||||
where cmake stores its files. Run a configure, build the code and then
|
||||
it installs the library and auxiliary files.
|
||||
You should start by considering where to install libcifpp. If you have
|
||||
sufficient permissions on your computer you perhaps should use the
|
||||
default but libcifpp can be configured to be installed anywhere
|
||||
including e.g. *$HOME/.local*.
|
||||
|
||||
If you want to run the tests before installing, you should add `-DENABLE_TESTING=ON`
|
||||
to the first cmake command.
|
||||
Next step is to configure, for this use the CMake gui application. If you
|
||||
installed the curses version of cmake you can type `ccmake`. On Windows
|
||||
you can use `cmake-gui.exe`.
|
||||
|
||||
To install in the default location:
|
||||
|
||||
```console
|
||||
ccmake -S . -B build
|
||||
```
|
||||
|
||||
To install elsewhere, e.g. *$HOME/.local*:
|
||||
|
||||
```console
|
||||
ccmake -S . -B build -DCMAKE_INSTALL_PREFIX=$HOME/.local
|
||||
```
|
||||
|
||||
In the cmake window, start the configure command (use button or press 'c').
|
||||
After the first configure step you will see a list of settable options.
|
||||
Alter these to match your preferences. Most options are self explaining
|
||||
and contain a description. Some may need a bit more explanation:
|
||||
|
||||
- CIFPP_DATA_DIR, this directory will be used to store initial versions
|
||||
of the mmcif_pdbx dictionary as well as the optional CCD file.
|
||||
|
||||
- CIFPP_DOWNLOAD_CCD
|
||||
|
||||
The CCD file is huge and perhaps you think you don't
|
||||
need it. In that case you can leave this OFF. But that will limit the
|
||||
use cases.
|
||||
|
||||
- CIFPP_INSTALL_UPDATE_SCRIPT
|
||||
|
||||
The files in CIFPP_DATA_DIR are quickly becoming out of date. On
|
||||
FreeBSD and Linux you can install a script that updates these files
|
||||
on a weekly basis.
|
||||
|
||||
- CIFPP_CRON_DIR
|
||||
|
||||
The directory where the update script is to be installed.
|
||||
|
||||
- CIFPP_ETC_DIR
|
||||
|
||||
The update script will only work if the file called *libcifpp.conf*
|
||||
in this *etc* directory will contain an uncommented line with
|
||||
|
||||
```console
|
||||
update=true
|
||||
```
|
||||
|
||||
- CIFPP_CACHE_DIR
|
||||
|
||||
When you installed and enabled the update script, new files are
|
||||
written to this directory.
|
||||
|
||||
- CIFPP_RECREATE_SYMOP_DATA
|
||||
|
||||
If you had CCP4 sourced into your environment, this option allows
|
||||
you to recreate the symop data file.
|
||||
|
||||
- BUILD_FOR_CCP4
|
||||
|
||||
Build a special version of libcifpp to be installed in the CCP4
|
||||
environment.
|
||||
|
||||
After setting these options you can run the configure step again and
|
||||
then use generate to create the makefiles.
|
||||
|
||||
Building and installing is then as simple as:
|
||||
|
||||
```console
|
||||
cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
If this fails due to lack of permissions, you can try:
|
||||
|
||||
```console
|
||||
sudo cmake --install build
|
||||
```
|
||||
|
||||
Tests are created by default, and to test the code you can run:
|
||||
|
||||
```console
|
||||
ctest --test-dir build
|
||||
```
|
||||
|
||||
127
changelog
127
changelog
@@ -1,3 +1,130 @@
|
||||
Version 9.0.5
|
||||
- Added exists to compound_factory
|
||||
- Added sub_matrix, fix and extend determinant calculation
|
||||
- Added yet another structure::create_non_poly
|
||||
- Remove revision.hpp file in make clean (new VersionString.cmake)
|
||||
|
||||
Version 9.0.4
|
||||
- Fix various stopping and reconstruction errors
|
||||
|
||||
Version 9.0.3
|
||||
- Reconstruction fixed when some entity ids are missing
|
||||
|
||||
Version 9.0.2
|
||||
- Fix code that reconstructs sequences, could throw a map::at
|
||||
- Many optimisations in validation and reconstruction code.
|
||||
|
||||
Version 9.0.1
|
||||
- Use pcre2 from pkg-config if available, if not
|
||||
build a version from the original code.
|
||||
|
||||
Version 9.0.0
|
||||
- Rename fields of cif::mm::polymer to match the naming
|
||||
in mmcif_pdbx.dic. Also, related, fix building mm::structure
|
||||
using the correct mapping between atom_site and residues.
|
||||
- _atom_site.auth_alt_id does not exist, it should be
|
||||
_atom_site.pdbx_auth_alt_id of course.
|
||||
- Added a more lightweight fixup for mmcif_pdbx files
|
||||
that lack certain categories.
|
||||
|
||||
Version 8.0.1
|
||||
- Fix cif::mm::structure::cleanup_empty_categories, removed too much
|
||||
- Add default value for B_iso_or_equiv in residue::create_new_atom
|
||||
- Reconstruct some branch records in bare pdbx files
|
||||
- Fix parsing PDB files (bug due to missing validator in dest. cat.)
|
||||
- Do not fail conversion of PDB files when compound info is missing
|
||||
|
||||
Version 8.0.0
|
||||
- A dictionary is for a datablock and a file can have
|
||||
datablocks with differing dictionaries.
|
||||
|
||||
Version 7.0.10
|
||||
- Deal with missing _entity.type in reconstructing mmCIF files
|
||||
- Replace code creating quaternions from rotation matrices
|
||||
that might sometimes give incorrect results. Or at least,
|
||||
the test code failed on this particular kind of code. Sometimes.
|
||||
- Fix reconstruction to build pdbx_nonpoly_scheme
|
||||
|
||||
Version 7.0.9
|
||||
- Using cif::file::load_dictionary it is now possible to
|
||||
load a dictionary along with its extensions in one go.
|
||||
E.g. file.load_dictionary("mmcif_pdbx;dssp-extension")
|
||||
- Fix in compound factory to avoid errors with lower case
|
||||
compound id's
|
||||
- Fix sac_parser's index to be case insensitive
|
||||
|
||||
Version 7.0.8
|
||||
- Fix PDB Remark 3 parser
|
||||
- Added three way comparison for point
|
||||
|
||||
Version 7.0.7
|
||||
- Set CIFPP_DATA_DIR on target cifpp for use in projects that include
|
||||
libcifpp directly
|
||||
|
||||
Version 7.0.6
|
||||
- Fix linking to std::atomic
|
||||
|
||||
Version 7.0.5
|
||||
- Fix case where category index was not updated for updated value
|
||||
|
||||
Version 7.0.4
|
||||
- Do not install headers and library in case we're not the top project
|
||||
|
||||
Version 7.0.3
|
||||
- Fix installation, write exports.hpp again
|
||||
|
||||
Version 7.0.2
|
||||
- Fix in testing error_code results.
|
||||
|
||||
Version 7.0.1
|
||||
- Various reconstruction fixes
|
||||
- category order in output fixed
|
||||
- better implementation of constructors for file, datablock and category
|
||||
- small optimisation in iterator
|
||||
|
||||
Version 7.0.0
|
||||
- Renaming many methods and parameters to be more
|
||||
consistent with the mmCIF dictionaries.
|
||||
(Most notably, item used to be called column or
|
||||
tag sometimes).
|
||||
- validation_error is now a std::system_error error
|
||||
value. The exception is gone.
|
||||
- Added repairSequenceInfo to repair invalid files
|
||||
|
||||
Version 6.1.0
|
||||
- Add formula weight to entity in pdb2cif
|
||||
- Change order of categories inside a datablock to match order in file
|
||||
- Change default order to write out categories in a file based on
|
||||
parent/child relationship
|
||||
- Added validate_pdbx and recover_pdbx
|
||||
- Fixed a serious bug in category_index when moving categories
|
||||
|
||||
Version 6.0.0
|
||||
- Drop the use of CCP4's monomer library for compound information
|
||||
|
||||
Version 5.2.5
|
||||
- Correctly import the Eigen3 library
|
||||
|
||||
Version 5.2.4
|
||||
- Changes required to build on Windows
|
||||
|
||||
Version 5.2.3
|
||||
- New constructors for cif::item, one taking std::optional values
|
||||
and another taking only a name resulting in a value '.' (i.e. inapplicable).
|
||||
- added cif::cell::get_volume
|
||||
|
||||
Version 5.2.2
|
||||
- Remove dependency on Eigen3 for users of libcifpp
|
||||
- Fix typos in documentation
|
||||
- Do not build latex files in documentation
|
||||
- Fixed conversion from string to integer, would fail on +2 e.g.
|
||||
- sqrt is not constexpr, thus kGoldenRatio should be const, not constexpr
|
||||
|
||||
Version 5.2.1
|
||||
- New versionstring module
|
||||
- small fixes for generating documentation
|
||||
- correctly setting SONAME
|
||||
|
||||
Version 5.2.0
|
||||
- With lots of documentation
|
||||
- Refactored coloured text output
|
||||
|
||||
@@ -56,6 +56,7 @@ endif()
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(Atomic_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::atomic" FORCE)
|
||||
mark_as_advanced(Atomic_FOUND)
|
||||
|
||||
if(Atomic_FIND_REQUIRED AND NOT Atomic_FOUND)
|
||||
message(FATAL_ERROR "Cannot run simple program using std::atomic")
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# Simplistic reimplementation of https://github.com/vector-of-bool/CMakeCM/blob/master/modules/FindFilesystem.cmake
|
||||
|
||||
if(TARGET std::filesystem)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckIncludeFileCXX)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
cmake_push_check_state()
|
||||
|
||||
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
|
||||
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
|
||||
|
||||
set(code [[
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
|
||||
int main() {
|
||||
auto cwd = std::filesystem::current_path();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
]])
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 8.4.0)
|
||||
# >> https://stackoverflow.com/questions/63902528/program-crashes-when-filesystempath-is-destroyed
|
||||
set(CXX_FILESYSTEM_NO_LINK_NEEDED 0)
|
||||
else()
|
||||
# Check a simple filesystem program without any linker flags
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
endif()
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
set(_found 1)
|
||||
else()
|
||||
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
|
||||
# Add the libstdc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set(_found ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
|
||||
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
# Try the libc++ flag
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
|
||||
check_cxx_source_compiles("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set(_found ${CXX_FILESYSTEM_CPPFS_NEEDED})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_found)
|
||||
add_library(std::filesystem INTERFACE IMPORTED)
|
||||
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
|
||||
|
||||
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
|
||||
# Nothing to add...
|
||||
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
|
||||
set_target_properties(std::filesystem PROPERTIES IMPORTED_LIBNAME stdc++fs)
|
||||
set(STDCPPFS_LIBRARY stdc++fs)
|
||||
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
|
||||
set_target_properties(std::filesystem PROPERTIES IMPORTED_LIBNAME c++fs)
|
||||
set(STDCPPFS_LIBRARY c++fs)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
|
||||
|
||||
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
|
||||
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
|
||||
endif()
|
||||
|
||||
12
cmake/FindPCRE2.cmake
Normal file
12
cmake/FindPCRE2.cmake
Normal file
@@ -0,0 +1,12 @@
|
||||
# The problem is, find_package(PCRE2) does not work
|
||||
# and using pkg-config results in linking to a shared library
|
||||
# causing all kinds of trouble later on
|
||||
|
||||
find_path(PCRE2_INCLUDEDIR NAMES pcre2.h HINTS "C:/Program Files (x86)/PCRE2/include" REQUIRED)
|
||||
find_library(PCRE2_LIBRARY NAMES pcre2-8-static libpcre2-8.a HINTS "C:/Program Files (x86)/PCRE2/lib" REQUIRED)
|
||||
|
||||
add_library(pcre2-8 IMPORTED STATIC)
|
||||
target_include_directories(pcre2-8 INTERFACE ${PCRE2_INCLUDEDIR})
|
||||
target_compile_definitions(pcre2-8 INTERFACE PCRE2_STATIC)
|
||||
set_target_properties(pcre2-8 PROPERTIES IMPORTED_LOCATION ${PCRE2_LIBRARY})
|
||||
set_target_properties(pcre2-8 PROPERTIES IMPORTED_IMPLIB ${PCRE2_LIBRARY})
|
||||
@@ -54,6 +54,10 @@ cmake_minimum_required(VERSION 3.15)
|
||||
variables contained in the revision file.
|
||||
#]=======================================================================]
|
||||
|
||||
# Record the location of this module now, not at the time the CMakeLists.txt
|
||||
# is being processed
|
||||
get_filename_component(_current_cmake_module_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
# First locate a .git file or directory.
|
||||
function(_get_git_dir _start_dir _variable)
|
||||
|
||||
@@ -233,7 +237,11 @@ function(write_version_header dir)
|
||||
|
||||
if(res EQUAL 0)
|
||||
set(REVISION_STRING "${out}")
|
||||
else()
|
||||
message(STATUS "Git hash not found, does this project have a 'build' tag?")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Git hash not found")
|
||||
endif()
|
||||
|
||||
# Check the revision string, if it matches we fill in the required info
|
||||
@@ -255,141 +263,13 @@ function(write_version_header dir)
|
||||
if(VERSION_STRING_OPTION_LIB_NAME)
|
||||
set(VAR_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}")
|
||||
set(IDENT_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}_")
|
||||
set(BOOL_IS_MAIN "false")
|
||||
else()
|
||||
set(VAR_PREFIX "")
|
||||
set(IDENT_PREFIX "")
|
||||
set(BOOL_IS_MAIN "true")
|
||||
endif()
|
||||
|
||||
# And finally, write out the header file
|
||||
file(WRITE "${VERSION_STRING_DATA}/${file_name}.in" [[// This file was generated by VersionString.cmake
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
|
||||
constexpr const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@";
|
||||
constexpr const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@";
|
||||
constexpr int k@VAR_PREFIX@BuildNumber = @BUILD_NUMBER@;
|
||||
constexpr const char k@VAR_PREFIX@RevisionGitTag[] = "@REVISION_GIT_TAGREF@";
|
||||
constexpr const char k@VAR_PREFIX@RevisionDate[] = "@REVISION_DATE_TIME@";
|
||||
|
||||
#ifndef VERSION_INFO_DEFINED
|
||||
#define VERSION_INFO_DEFINED 1
|
||||
|
||||
namespace version_info_v1
|
||||
{
|
||||
|
||||
class version_info_base
|
||||
{
|
||||
public:
|
||||
|
||||
static void write(std::ostream &os, bool verbose)
|
||||
{
|
||||
auto &s_head = head();
|
||||
if (s_head != nullptr)
|
||||
write(s_head, os, verbose);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
version_info_base(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date)
|
||||
: m_name(name)
|
||||
, m_version(version)
|
||||
, m_build_number(build_number)
|
||||
, m_git_tag(git_tag)
|
||||
, m_revision_date(revision_date)
|
||||
{
|
||||
auto &s_head = head();
|
||||
m_next = s_head;
|
||||
s_head = this;
|
||||
}
|
||||
|
||||
static void write(const version_info_base *inst, std::ostream &os, bool verbose)
|
||||
{
|
||||
if (inst->m_next)
|
||||
{
|
||||
write(inst->m_next, os, verbose);
|
||||
|
||||
if (not verbose)
|
||||
return;
|
||||
|
||||
os << '-' << std::endl;
|
||||
}
|
||||
|
||||
os << inst->m_name << " version " << inst->m_version << std::endl;
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
if (inst->m_build_number != 0)
|
||||
{
|
||||
os << "build: " << inst->m_build_number << ' ' << inst->m_revision_date << std::endl;
|
||||
if (inst->m_git_tag[0] != 0)
|
||||
os << "git tag: " << inst->m_git_tag << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using version_info_ptr = version_info_base *;
|
||||
|
||||
static version_info_ptr &head()
|
||||
{
|
||||
static version_info_ptr s_head = nullptr;
|
||||
return s_head;
|
||||
}
|
||||
|
||||
const char *m_name;
|
||||
const char *m_version;
|
||||
int m_build_number;
|
||||
const char *m_git_tag;
|
||||
const char *m_revision_date;
|
||||
version_info_base *m_next = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class version_info : public version_info_base
|
||||
{
|
||||
public:
|
||||
using implementation_type = T;
|
||||
|
||||
version_info(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date)
|
||||
: version_info_base(name, version, build_number, git_tag, revision_date)
|
||||
{
|
||||
}
|
||||
|
||||
struct register_object
|
||||
{
|
||||
register_object()
|
||||
{
|
||||
static implementation_type s_instance;
|
||||
}
|
||||
};
|
||||
|
||||
template<register_object&> struct reference_object;
|
||||
|
||||
static register_object s_registered_object;
|
||||
static reference_object<s_registered_object> s_referenced_object;
|
||||
};
|
||||
|
||||
template<typename T> typename version_info<T>::register_object version_info<T>::s_registered_object;
|
||||
|
||||
}
|
||||
|
||||
inline void write_version_string(std::ostream &os, bool verbose)
|
||||
{
|
||||
version_info_v1::version_info_base::write(os, verbose);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class version_info_@IDENT_PREFIX@impl : public version_info_v1::version_info<version_info_@IDENT_PREFIX@impl>
|
||||
{
|
||||
public:
|
||||
version_info_@IDENT_PREFIX@impl()
|
||||
: version_info(k@VAR_PREFIX@ProjectName, k@VAR_PREFIX@VersionNumber, k@VAR_PREFIX@BuildNumber, k@VAR_PREFIX@RevisionGitTag, k@VAR_PREFIX@RevisionDate)
|
||||
{
|
||||
}
|
||||
};
|
||||
]])
|
||||
configure_file("${VERSION_STRING_DATA}/${file_name}.in" "${dir}/${file_name}" @ONLY)
|
||||
configure_file("${_current_cmake_module_dir}/revision.hpp.in" "${dir}/${file_name}" @ONLY)
|
||||
endfunction()
|
||||
|
||||
|
||||
12
cmake/cifpp-config.cmake.in
Normal file
12
cmake/cifpp-config.cmake.in
Normal file
@@ -0,0 +1,12 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/cifpp-targets.cmake")
|
||||
|
||||
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_CIFPP_DATA_DIR@")
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(Threads)
|
||||
find_dependency(ZLIB REQUIRED)
|
||||
|
||||
check_required_components(cifpp)
|
||||
@@ -1,20 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
|
||||
|
||||
# Note that this set_and_check needs te be executed before
|
||||
# find_dependency of Eigen3, otherwise the path is
|
||||
# not found....
|
||||
set_and_check(CIFPP_SHARE_DIR "@PACKAGE_CIFPP_DATA_DIR@")
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Threads)
|
||||
|
||||
find_dependency(ZLIB REQUIRED)
|
||||
find_dependency(Eigen3 REQUIRED)
|
||||
|
||||
if(MSVC)
|
||||
find_dependency(zeep REQUIRED)
|
||||
endif()
|
||||
|
||||
check_required_components(cifpp)
|
||||
121
cmake/revision.hpp.in
Normal file
121
cmake/revision.hpp.in
Normal file
@@ -0,0 +1,121 @@
|
||||
// This file was generated by VersionString.cmake
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
|
||||
constexpr const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@";
|
||||
constexpr const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@";
|
||||
constexpr int k@VAR_PREFIX@BuildNumber = @BUILD_NUMBER@;
|
||||
constexpr const char k@VAR_PREFIX@RevisionGitTag[] = "@REVISION_GIT_TAGREF@";
|
||||
constexpr const char k@VAR_PREFIX@RevisionDate[] = "@REVISION_DATE_TIME@";
|
||||
|
||||
#ifndef VERSION_INFO_DEFINED
|
||||
#define VERSION_INFO_DEFINED 1
|
||||
|
||||
namespace version_info_v1_1
|
||||
{
|
||||
|
||||
class version_info_base
|
||||
{
|
||||
public:
|
||||
static void write_version_string(std::ostream &os, bool verbose)
|
||||
{
|
||||
auto s_main = registered_main();
|
||||
if (s_main != nullptr)
|
||||
s_main->write(os, verbose);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
for (auto lib = registered_libraries(); lib != nullptr; lib = lib->m_next)
|
||||
{
|
||||
os << "-\n";
|
||||
lib->write(os, verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
version_info_base(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date, bool is_main)
|
||||
: m_name(name)
|
||||
, m_version(version)
|
||||
, m_build_number(build_number)
|
||||
, m_git_tag(git_tag)
|
||||
, m_revision_date(revision_date)
|
||||
{
|
||||
if (is_main)
|
||||
registered_main() = this;
|
||||
else
|
||||
{
|
||||
auto &s_head = registered_libraries();
|
||||
m_next = s_head;
|
||||
s_head = this;
|
||||
}
|
||||
}
|
||||
|
||||
void write(std::ostream &os, bool verbose)
|
||||
{
|
||||
os << m_name << " version " << m_version << '\n';
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
if (m_build_number != 0)
|
||||
{
|
||||
os << "build: " << m_build_number << ' ' << m_revision_date << '\n';
|
||||
if (m_git_tag[0] != 0)
|
||||
os << "git tag: " << m_git_tag << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using version_info_ptr = version_info_base *;
|
||||
|
||||
static version_info_ptr ®istered_main()
|
||||
{
|
||||
static version_info_ptr s_main = nullptr;
|
||||
return s_main;
|
||||
}
|
||||
|
||||
static version_info_ptr ®istered_libraries()
|
||||
{
|
||||
static version_info_ptr s_head = nullptr;
|
||||
return s_head;
|
||||
}
|
||||
|
||||
const char *m_name;
|
||||
const char *m_version;
|
||||
int m_build_number;
|
||||
const char *m_git_tag;
|
||||
const char *m_revision_date;
|
||||
version_info_base *m_next = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class version_info : public version_info_base
|
||||
{
|
||||
public:
|
||||
using implementation_type = T;
|
||||
|
||||
version_info(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date, bool is_main)
|
||||
: version_info_base(name, version, build_number, git_tag, revision_date, is_main)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace version_info_v1_1
|
||||
|
||||
inline void write_version_string(std::ostream &os, bool verbose)
|
||||
{
|
||||
version_info_v1_1::version_info_base::write_version_string(os, verbose);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const class version_info_@IDENT_PREFIX@impl : public version_info_v1_1::version_info<version_info_@IDENT_PREFIX@impl>
|
||||
{
|
||||
public:
|
||||
version_info_@IDENT_PREFIX@impl()
|
||||
: version_info(k@VAR_PREFIX@ProjectName, k@VAR_PREFIX@VersionNumber, k@VAR_PREFIX@BuildNumber, k@VAR_PREFIX@RevisionGitTag, k@VAR_PREFIX@RevisionDate, @BOOL_IS_MAIN@)
|
||||
{
|
||||
}
|
||||
} s_version_info_@IDENT_PREFIX@instance;
|
||||
17
cmake/test-charconv.cpp
Normal file
17
cmake/test-charconv.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <charconv>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
int main()
|
||||
{
|
||||
float v;
|
||||
char s[] = "1.0";
|
||||
|
||||
auto r = std::from_chars(s, s + strlen(s), v);
|
||||
|
||||
assert(r.ec == std::errc{});
|
||||
assert(r.ptr = s + strlen(s));
|
||||
assert(v == 1.0f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
|
||||
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string s(100'000, '*');
|
||||
std::smatch m;
|
||||
std::regex r("^(.*?)$");
|
||||
|
||||
std::regex_search(s, m, r);
|
||||
|
||||
std::cout << s.substr(0, 10) << '\n';
|
||||
std::cout << m.str(1).substr(0, 10) << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -7,37 +7,42 @@ set(CIFPP_PUBLIC_HEADER_DIR ${PROJECT_SOURCE_DIR}/include)
|
||||
file(GLOB_RECURSE CIFPP_PUBLIC_HEADERS ${CIFPP_PUBLIC_HEADER_DIR}/*.hpp)
|
||||
|
||||
set(DOXYGEN_INPUT_DIR ${CIFPP_PUBLIC_HEADER_DIR})
|
||||
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml)
|
||||
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/xml)
|
||||
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/index.xml)
|
||||
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
|
||||
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
|
||||
#Replace variables inside @@ with the current values
|
||||
# Replace variables inside @@ with the current values
|
||||
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
|
||||
|
||||
file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) #Doxygen won't create this for us
|
||||
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
|
||||
BYPRODUCTS ${DOXYGEN_OUTPUT_DIR}/xml
|
||||
DEPENDS ${CIFPP_PUBLIC_HEADERS} ${DOXYFILE_OUT}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
|
||||
MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
|
||||
COMMENT "Generating docs")
|
||||
add_custom_command(
|
||||
OUTPUT ${DOXYGEN_OUTPUT_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR})
|
||||
|
||||
add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})
|
||||
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
|
||||
BYPRODUCTS ${DOXYGEN_OUTPUT_DIR}
|
||||
DEPENDS ${DOXYGEN_OUTPUT_DIR} ${CIFPP_PUBLIC_HEADERS} ${DOXYFILE_OUT}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
|
||||
MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
|
||||
COMMENT "Generating docs")
|
||||
|
||||
add_custom_target("Doxygen-${PROJECT_NAME}" ALL DEPENDS ${DOXYGEN_INDEX_FILE})
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_SOURCE_DIR}/conf.py @ONLY)
|
||||
|
||||
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx)
|
||||
|
||||
add_custom_target(Sphinx ALL
|
||||
COMMAND
|
||||
${SPHINX_EXECUTABLE} -b html
|
||||
-Dbreathe_projects.${PROJECT_NAME}=${DOXYGEN_OUTPUT_DIR}/xml
|
||||
${SPHINX_SOURCE} ${SPHINX_BUILD}
|
||||
DEPENDS ${DOXYGEN_INDEX_FILE}
|
||||
BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/api
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating documentation with Sphinx")
|
||||
add_custom_target("Sphinx-${PROJECT_NAME}" ALL
|
||||
COMMAND ${SPHINX_EXECUTABLE} -b html
|
||||
-Dbreathe_projects.${PROJECT_NAME}=${DOXYGEN_OUTPUT_DIR}
|
||||
${SPHINX_SOURCE} ${SPHINX_BUILD}
|
||||
DEPENDS ${DOXYGEN_INDEX_FILE}
|
||||
BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/api
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating documentation with Sphinx")
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/ DESTINATION ${CMAKE_INSTALL_DOCDIR} PATTERN .doctrees EXCLUDE)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
PATTERN .doctrees EXCLUDE
|
||||
PATTERN .buildinfo EXCLUDE)
|
||||
|
||||
@@ -3,6 +3,7 @@ FILE_PATTERNS = *.hpp
|
||||
STRIP_FROM_PATH = @DOXYGEN_INPUT_DIR@
|
||||
RECURSIVE = YES
|
||||
GENERATE_XML = YES
|
||||
GENERATE_LATEX = NO
|
||||
PREDEFINED += and=&& or=|| not=! CIFPP_EXPORT= HAVE_LIBCLIPPER=1
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
|
||||
@@ -161,6 +161,50 @@ Returning a complete set if often not required, if you only want to have the fir
|
||||
|
||||
There are cases when you really need exactly one result. The :cpp:func:`cif::category::find1` can be used in that case, it will throw an exception if the query does not result in exactly one row.
|
||||
|
||||
NULL and ANY
|
||||
------------
|
||||
|
||||
Sometimes items may be empty. The trouble is a bit that empty comes in two flavors: unknown and null. Null in *CIF* parlance means the item should not contain a value since it makes no sense in this case, the value stored in the file is a single dot character: ``'.'``. E.g. *atom_site* records may have a NULL value for label_seq_id for atoms that are part of a *non-polymer*.
|
||||
|
||||
The other empty value is indicated by a question mark character: ``'?'``. This means the value is simply unknown.
|
||||
|
||||
Both these are NULL in *libcifpp* conditions and can be searched for using :cpp:var:`cif::null`.
|
||||
|
||||
So you can search for:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cif::condition c = "label_seq_id"_key == cif::null;
|
||||
|
||||
You might also want to look for a certain value and don't care in which item it is stored, in that case you can use :cpp:var:`cif::any`.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cif::condition c = cif::any == "foo";
|
||||
|
||||
And in linked record you might have the items that have a value in both parent and child or both should be NULL. For that, you can request the value to return by find to be of type std::optional and then use that value to build the query. An example to explain this, let's find the location of the atom that is referenced as the first atom in a struct_conn record:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// Take references to the two categories we need
|
||||
auto struct_conn = db["struct_conn"];
|
||||
auto atom_site = db["atom_site"];
|
||||
|
||||
// Loop over all rows in struct_conn taking only the values we need
|
||||
// Note that the label_seq_id is returned as a std::optional<int>
|
||||
// That means it may contain an integer or may be empty
|
||||
for (const auto &[asym1, seqid1, authseqid1, atomid1] :
|
||||
struct_conn.rows<std::string,std::optional<int>,std::string,std::string,std::string>(
|
||||
"ptnr1_label_asym_id", "ptnr1_label_seq_id", "ptnr1_auth_seq_id", "ptnr1_label_atom_id"
|
||||
))
|
||||
{
|
||||
// Find the location of the first atom
|
||||
cif::point p1 = atom_site.find1<float,float,float>(
|
||||
"label_asym_id"_key == asym1 and "label_seq_id"_key == seqid1 and "auth_seq_id"_key == authseqid1 and "label_atom_id"_key == atomid1,
|
||||
"cartn_x", "cartn_y", "cartn_z");
|
||||
}
|
||||
|
||||
|
||||
Validation
|
||||
----------
|
||||
|
||||
@@ -173,7 +217,7 @@ A simple case:
|
||||
#include <cif++.hpp>
|
||||
|
||||
cif::file f("1cbs.cif.gz");
|
||||
f.load_dictionary("mmcif_pdbx");
|
||||
f.load_dictionary("mmcif_pdbx.dic");
|
||||
|
||||
if (not f.is_valid())
|
||||
std::cout << "This file is not valid\n";
|
||||
|
||||
49
docs/bitsandpieces.rst
Normal file
49
docs/bitsandpieces.rst
Normal file
@@ -0,0 +1,49 @@
|
||||
Bits & Pieces
|
||||
=============
|
||||
|
||||
The *libcifpp* library offers some extra code that makes the life of developers a bit easier.
|
||||
|
||||
gzio
|
||||
----
|
||||
|
||||
To work with compressed data files a *std::streambuf* implemenation was added based on the code in `gxrio <https://github.com/mhekkel/gxrio>`_. This allows you to read and write compressed data streams transparently.
|
||||
|
||||
When working with files you can use :cpp:class:`cif::gzio::ifstream` and :cpp:class:`cif::gzio::ofstream`. The selection of whether to use compression or not is based on the file extension. If it is ``.gz`` gzip compression is used:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cif::gzio::ifstream file("my-file.txt.gz");
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line))
|
||||
std::cout << line << '\n';
|
||||
|
||||
Writing is equally easy:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cif::gzio::ofstream file("/tmp/output.txt.gz");
|
||||
file << "Hello, world!";
|
||||
file.close();
|
||||
|
||||
You can also use the :cpp:class:`cif::gzio::istream` and feed it a *std::streambuf* object that may or may not contain compressed data. In that case the first bytes of the input are sniffed and if it is gzip compressed data, decompression will be done.
|
||||
|
||||
A progress bar
|
||||
--------------
|
||||
|
||||
Applications based on *libcifpp* may have a longer run time. To give some feedback to the user running your application in a terminal you can use the :cpp:class:`cif::progress_bar`. This class will display an ASCII progress bar along with optional status messages, but only if output is to a real TTY (terminal).
|
||||
|
||||
A progress bar is also shown only if the duration is more than two seconds. To avoid having flashing progress bars for short actions.
|
||||
|
||||
The progress bar uses an internal progress counter that starts at zero and ends when the max value has been reached after which it will be removed from the screen. Updating this internal progress counter can be done by adding a number of steps calling :cpp:func:`cif::progress_bar::consumed` or by setting the exact value for the counter by calling :cpp:func:`cif::progress_bar::progress`.
|
||||
|
||||
Colouring output
|
||||
----------------
|
||||
|
||||
It is also nice to emphasise some output in the terminal by using colours. For this you can create output manipulators using :cpp:func:`cif::coloured`. To write a string in white, and bold letters on a red background you can do:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
using namespace cif::colour;
|
||||
std::cout << cif::coloured("Hello, world!", white, red, bold) << '\n';
|
||||
|
||||
33
docs/compound.rst
Normal file
33
docs/compound.rst
Normal file
@@ -0,0 +1,33 @@
|
||||
Chemical Compounds
|
||||
==================
|
||||
|
||||
The data in *CIF* and *mmCIF* files often describes the structure of some chemical compounds. The structure is recorded in the categories *atom_site* and friends. Records in these categories refer to chemical compounds using a compound ID. This compound ID is the ID field of the *chem_comp* category. For all of the known compounds in the PDB there is an entry in the Chemical Compounds Dictionary or `CCD <https://www.wwpdb.org/data/ccd>`_. If *libcifpp* was properly installed you have a copy of this file somewhere on your disk. And if you have installed the update scripts, a fresh version of this file will be retrieved weekly.
|
||||
|
||||
As an alternative to CCD there are the monomer library files from `CCP4 <https://www.ccp4.ac.uk/>`_. These contain somewhat different data but the overlap is good enough for usage in *libcifpp*.
|
||||
|
||||
Information about compounds is captured in the :cpp:class:`cif::compound`. An instance of a compound object for a certain compound ID can be obtained by using the singleton :cpp:class:`cif::compound_factory`.
|
||||
|
||||
If the compound you want to use is not available in the CCD or in CCP4, you can add that information yourself. For this you can use the method :cpp:func:`cif::compound_factory::push_dictionary`.
|
||||
|
||||
So, given that we have CCD, CCP4 monomer library and used defined compound definitions, what will you get when you try to retrieve such a compound by ID? The answer is, the factory has a stack of compound generators. The first thrown on the stack is the one for a CCD file (*components.cif*) if it can be found. Then, if the *CLIBD_MON* environmental variable is defined, a generator for monomer library files is added to the stack. And then all generators for files you added using *push_dictionary* are added in order. The generators are searched in the reverse order in which they were added to see if it creates a compound object for the ID. If no compound was created at all, nullptr is returned.
|
||||
|
||||
Updating CCD
|
||||
------------
|
||||
|
||||
The CCD data is stored in a single file called *components.cif* and can be downloaded from `CCD <https://www.wwpdb.org/data/ccd>`_.
|
||||
|
||||
As can be read in the section on resources (:doc:`/resources`) files in libcifpp are loaded in a specific order. If the CCD datafile was downloaded during installation, a copy can be found in the directory */usr/share/libcifpp/* (if you installed in */usr*). This is a static file and will not be updated until the next installation of libcifpp.
|
||||
|
||||
When configuring libcifpp, you can specify the *CIFPP_INSTALL_UPDATE_SCRIPT* option, as in:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cmake -S . -B build -DCIFPP_INSTALL_UPDATE_SCRIPT=ON # ... more options?
|
||||
|
||||
This will install a script named *update-libcifpp-data* in */etc/cron.weekly* or */etc/periodic/weekly*. This file uses a config file named */etc/libcifpp.conf* which you then need to edit. In this config file the following line needs to be uncommented:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# update=true
|
||||
|
||||
After that, the update script will weekly download the latest components.cif file to */var/cache/libcifpp*.
|
||||
@@ -27,7 +27,7 @@ Using *libcifpp* is easy, if you are familiar with modern C++:
|
||||
|
||||
.. literalinclude:: ../README.md
|
||||
:language: c++
|
||||
:start-after: ```c++
|
||||
:start-after: ```cpp
|
||||
:end-before: ```
|
||||
|
||||
.. toctree::
|
||||
@@ -36,8 +36,11 @@ Using *libcifpp* is easy, if you are familiar with modern C++:
|
||||
|
||||
self
|
||||
basics.rst
|
||||
compound.rst
|
||||
model.rst
|
||||
resources.rst
|
||||
symmetry.rst
|
||||
bitsandpieces.rst
|
||||
api/library_root.rst
|
||||
genindex.rst
|
||||
|
||||
|
||||
36
docs/model.rst
Normal file
36
docs/model.rst
Normal file
@@ -0,0 +1,36 @@
|
||||
Molecular Model
|
||||
===============
|
||||
|
||||
Theoretically it is possible to get along with only the classes *cif::file*, *cif::datablock* and *cif::category*. But to keep your data complete and valid you then have to update lots of categories for all but the simplest manipulations. For this *libcifpp* comes with a higher level API modelling atoms, residues, monomers, polymers and complete structures in their respective classes.
|
||||
|
||||
Note that these classes only work properly if you are using *mmCIF* files and have an mmcif_pdbx dictionary available, either compiled in using `mrc <https://github.com/mhekkel/mrc.git>`_ or installed in the proper location.
|
||||
|
||||
.. note::
|
||||
|
||||
This part of *libcifpp* is the least developed part. What is available should work but functionality should eventually be extended.
|
||||
|
||||
Atom
|
||||
----
|
||||
|
||||
The :cpp:class:`cif::mm::atom` is a lightweight proxy class giving access to the data stored in *atom_site* and *atom_site_anisotrop*. It only caches the most often used item data and every modification is directly written back into the *mmCIF* categories.
|
||||
|
||||
Atoms can be copied by value with low cost. The atom class only contains a pointer to an implementation that is reference counted.
|
||||
|
||||
Residue, Monomer and Polymer
|
||||
----------------------------
|
||||
|
||||
The :cpp:class:`cif::mm::residue`, :cpp:class:`cif::mm::monomer` and :cpp:class:`cif::mm::polymer` implement what you'd expect. A monomer is a residue that is part of a polymer and thus has a sequence number and siblings.
|
||||
|
||||
Sugars & Branches
|
||||
-----------------
|
||||
|
||||
There are also classes for modelling sugars and sugar branches. You can create sugar branches
|
||||
|
||||
Structure
|
||||
---------
|
||||
|
||||
The :cpp:class:`cif::mm::structure` can be used to load one of the models from an *mmCIF* file. By default the first model is loaded. (Multiple models are often only available files containing structures defined using NMR).
|
||||
|
||||
A structure holds a reference to a *cif::datablock* and retrieves its data from this datablock and writes any modification back into that datablock.
|
||||
|
||||
One of the most useful parts of the structure class is the ability to create and modify residues. This updates related *chem_comp* and *entity* categories as well.
|
||||
@@ -18,7 +18,7 @@ Loading Resources
|
||||
|
||||
No matter where the resource is located, you should always use the single libcifpp API call :cpp:func:`cif::load_resource` to load them. This function returns a *std::istream* wrapped inside a *std::unique_ptr*.
|
||||
|
||||
The order in which resources are search for is:
|
||||
The order in which resources are searched for is:
|
||||
|
||||
* Use the resource that was defined by calling :cpp:func:`cif::add_file_resource`
|
||||
for this name.
|
||||
|
||||
@@ -20,6 +20,20 @@ Matrix
|
||||
|
||||
Although Quaternions are the preferred way of doing rotations, not every manipulation is a rotation and thus we need a matrix class as well. Matrices and their operations are encoded as matrix_expressions in *libcifpp* allowing the compiler to generate very fast code. See the :ref:`file_cif++_matrix.hpp` for what is on offer.
|
||||
|
||||
Crystals
|
||||
--------
|
||||
|
||||
The *CIF* and *mmCIF* were initially developed to store crystallographic information on structures. Apart from coordinates and the chemical information the crystallographic information is important. This information can be split into two parts, a unit cell and a set of :ref:`symmetry-ops` making up a spacegroup. The spacegroup number and name are stored in the *symmetry* category. The corresponding symmetry operations can be obtained in *libcifpp* by using the :cpp:class:`cif::spacegroup`. The cell is stored in the category *cell* and likewise can be loaded using the :cpp:class:`cif::cell`. Together these two classes make up a crystal and so we have a :cpp:class:`cif::crystal` which contains both. You can easily create such a crystal object by passing the datablock containing the data to the constructor. As in:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
// Load the file
|
||||
cif::file f("1cbs.cif.gz");
|
||||
|
||||
auto &db = f.front();
|
||||
cif::crystal c(db);
|
||||
|
||||
.. _symmetry-ops:
|
||||
Symmetry operations
|
||||
-------------------
|
||||
|
||||
@@ -31,21 +45,28 @@ To give an idea how this works, here's a piece of code copied from one of the un
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
using namespace cif::literals;
|
||||
|
||||
// Load the file
|
||||
cif::file f(gTestDir / "2bi3.cif.gz");
|
||||
|
||||
// Simply assume we can use the first datablock
|
||||
auto &db = f.front();
|
||||
cif::mm::structure s(db);
|
||||
|
||||
// Load the crystal information
|
||||
cif::crystal c(db);
|
||||
|
||||
// Take references to the two categories we need
|
||||
auto struct_conn = db["struct_conn"];
|
||||
auto atom_site = db["atom_site"];
|
||||
|
||||
// Loop over all rows in struct_conn taking only the values we need
|
||||
for (const auto &[
|
||||
asym1, seqid1, authseqid1, atomid1, symm1,
|
||||
asym2, seqid2, authseqid2, atomid2, symm2,
|
||||
dist] : struct_conn.find<
|
||||
std::string,int,std::string,std::string,std::string,
|
||||
std::string,int,std::string,std::string,std::string,
|
||||
std::string,std::optional<int>,std::string,std::string,std::string,
|
||||
std::string,std::optional<int>,std::string,std::string,std::string,
|
||||
float>(
|
||||
cif::key("ptnr1_symmetry") != "1_555" or cif::key("ptnr2_symmetry") != "1_555",
|
||||
"ptnr1_label_asym_id", "ptnr1_label_seq_id", "ptnr1_auth_seq_id", "ptnr1_label_atom_id", "ptnr1_symmetry",
|
||||
@@ -53,25 +74,35 @@ To give an idea how this works, here's a piece of code copied from one of the un
|
||||
"pdbx_dist_value"
|
||||
))
|
||||
{
|
||||
auto &r1 = s.get_residue(asym1, seqid1, authseqid1);
|
||||
auto &r2 = s.get_residue(asym2, seqid2, authseqid2);
|
||||
// Find the location of the first atom
|
||||
cif::point p1 = atom_site.find1<float,float,float>(
|
||||
"label_asym_id"_key == asym1 and "label_seq_id"_key == seqid1 and "auth_seq_id"_key == authseqid1 and "label_atom_id"_key == atomid1,
|
||||
"cartn_x", "cartn_y", "cartn_z");
|
||||
|
||||
auto a1 = r1.get_atom_by_atom_id(atomid1);
|
||||
auto a2 = r2.get_atom_by_atom_id(atomid2);
|
||||
// Find the location of the second atom
|
||||
cif::point p2 = atom_site.find1<float,float,float>(
|
||||
"label_asym_id"_key == asym2 and "label_seq_id"_key == seqid2 and "auth_seq_id"_key == authseqid2 and "label_atom_id"_key == atomid2,
|
||||
"cartn_x", "cartn_y", "cartn_z");
|
||||
|
||||
auto sa1 = c.symmetry_copy(a1.get_location(), cif::sym_op(symm1));
|
||||
auto sa2 = c.symmetry_copy(a2.get_location(), cif::sym_op(symm2));
|
||||
// Calculate the position of the first atom using the symmetry operator defined in struct_conn
|
||||
auto sa1 = c.symmetry_copy(p1, cif::sym_op(symm1));
|
||||
|
||||
BOOST_TEST(cif::distance(sa1, sa2) == dist);
|
||||
// Calculate the position of the second atom using the symmetry operator defined in struct_conn
|
||||
auto sa2 = c.symmetry_copy(p2, cif::sym_op(symm2));
|
||||
|
||||
auto pa1 = a1.get_location();
|
||||
// The distance between these symmetry atoms should be equal to the distance in the struct_conn record
|
||||
assert(cif::distance(sa1, sa2) == dist);
|
||||
|
||||
const auto &[d, p, so] = c.closest_symmetry_copy(pa1, a2.get_location());
|
||||
// And to show how you can obtain the closest symmetry copy of an atom near another one:
|
||||
// here we request the symmetry copy of p2 that lies closest to p1
|
||||
const auto &[d, p, so] = c.closest_symmetry_copy(p1, p2);
|
||||
|
||||
BOOST_TEST(p.m_x == sa2.m_x);
|
||||
BOOST_TEST(p.m_y == sa2.m_y);
|
||||
BOOST_TEST(p.m_z == sa2.m_z);
|
||||
// And that should of course be equal to the location in struct_conn for p2
|
||||
assert(p.m_x == sa2.m_x);
|
||||
assert(p.m_y == sa2.m_y);
|
||||
assert(p.m_z == sa2.m_z);
|
||||
|
||||
BOOST_TEST(d == dist);
|
||||
BOOST_TEST(so.string() == symm2);
|
||||
// Distance and symmetry operator string should also be the same
|
||||
assert(d == dist);
|
||||
assert(so.string() == symm2);
|
||||
}
|
||||
@@ -13,7 +13,7 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cif::file file = cif::pdb::read(argv[1]);
|
||||
cif::file file(argv[1]);
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
|
||||
@@ -200,7 +200,7 @@ enum class radius_type
|
||||
};
|
||||
|
||||
/// @brief The number of radii per element which can be requested from atom_type_info
|
||||
constexpr size_t kRadiusTypeCount = static_cast<size_t>(radius_type::type_count);
|
||||
constexpr std::size_t kRadiusTypeCount = static_cast<std::size_t>(radius_type::type_count);
|
||||
|
||||
/// An enum used to select either the effective or the crystal radius of an ion.
|
||||
/// See explanation on Wikipedia: https://en.wikipedia.org/wiki/Ionic_radius
|
||||
@@ -276,7 +276,7 @@ class atom_type_traits
|
||||
{
|
||||
if (type >= radius_type::type_count)
|
||||
throw std::invalid_argument("invalid radius requested");
|
||||
return m_info->radii[static_cast<size_t>(type)] / 100.f;
|
||||
return m_info->radii[static_cast<std::size_t>(type)] / 100.f;
|
||||
}
|
||||
|
||||
/// \brief Return the radius for a charged version of this atom in a solid crystal
|
||||
|
||||
@@ -28,29 +28,35 @@
|
||||
|
||||
#include "cif++/forward_decl.hpp"
|
||||
|
||||
#include "cif++/condition.hpp"
|
||||
// #include "cif++/condition.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/iterator.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <array>
|
||||
// #include <array>
|
||||
#include <functional>
|
||||
|
||||
/** \file category.hpp
|
||||
* Documentation for the cif::category class
|
||||
*
|
||||
* The category class should meet the requirements of Container and
|
||||
* SequenceContainer.
|
||||
*
|
||||
* TODO: implement all of:
|
||||
* https://en.cppreference.com/w/cpp/named_req/Container
|
||||
* https://en.cppreference.com/w/cpp/named_req/SequenceContainer
|
||||
* and more?
|
||||
*/
|
||||
* Documentation for the cif::category class
|
||||
*
|
||||
* The category class should meet the requirements of Container and
|
||||
* SequenceContainer.
|
||||
*
|
||||
* TODO: implement all of:
|
||||
* https://en.cppreference.com/w/cpp/named_req/Container
|
||||
* https://en.cppreference.com/w/cpp/named_req/SequenceContainer
|
||||
* and more?
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class validator;
|
||||
struct category_validator;
|
||||
struct item_validator;
|
||||
struct link_validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// special exceptions
|
||||
|
||||
@@ -61,39 +67,49 @@ namespace cif
|
||||
class duplicate_key_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new duplicate key error object
|
||||
*/
|
||||
/**
|
||||
* @brief Construct a new duplicate key error object
|
||||
*/
|
||||
duplicate_key_error(const std::string &msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief A missing_key_error is thrown when an attempt is made
|
||||
/// to create an index when one of the key items is missing.
|
||||
class missing_key_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new duplicate key error object
|
||||
*/
|
||||
missing_key_error(const std::string &msg, const std::string &key)
|
||||
: std::runtime_error(msg)
|
||||
, m_key(key)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string &get_key() const noexcept { return m_key; }
|
||||
|
||||
private:
|
||||
std::string m_key;
|
||||
};
|
||||
|
||||
/// @brief A multiple_results_error is throw when you request a single
|
||||
/// row using a query but the query contains more than exactly one row.
|
||||
class multiple_results_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new multiple results error object
|
||||
*/
|
||||
/**
|
||||
* @brief Construct a new multiple results error object
|
||||
*/
|
||||
multiple_results_error()
|
||||
: std::runtime_error("query should have returned exactly one row")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// These should be moved elsewhere, one day.
|
||||
|
||||
/// \cond
|
||||
template <typename _Tp>
|
||||
inline constexpr bool is_optional_v = false;
|
||||
template <typename _Tp>
|
||||
inline constexpr bool is_optional_v<std::optional<_Tp>> = true;
|
||||
/// \endcond
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// The class category is a sequence container for rows of data values.
|
||||
@@ -121,23 +137,45 @@ class category
|
||||
|
||||
/// \endcond
|
||||
|
||||
category() = default; ///< Default constructor
|
||||
category(std::string_view name); ///< Constructor taking a \a name
|
||||
category(const category &rhs); ///< Copy constructor
|
||||
category(category &&rhs); ///< Move constructor
|
||||
category &operator=(const category &rhs); ///< Copy assignement operator
|
||||
category &operator=(category &&rhs); ///< Move assignement operator
|
||||
category() = default; ///< Default constructor
|
||||
category(std::string_view name); ///< Constructor taking a \a name
|
||||
|
||||
/// @brief Constructor creating a category named @a name and filled with @a rows
|
||||
/// @param name Name for the new category
|
||||
/// @param rows The data stored in the category
|
||||
category(std::string_view name, row_initializer &&rows)
|
||||
: category(name)
|
||||
{
|
||||
emplace(std::forward<row_initializer>(rows));
|
||||
}
|
||||
|
||||
category(const category &rhs); ///< Copy constructor
|
||||
|
||||
category(category &&rhs) noexcept ///< Move constructor
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
category &operator=(category rhs) ///< assignement operator
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
/// @note Please note that the destructor is not virtual. It is assumed that
|
||||
/// you will not derive from this class.
|
||||
~category();
|
||||
|
||||
friend void swap(category &a, category &b) noexcept;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
const std::string &name() const { return m_name; } ///< Returns the name of the category
|
||||
iset key_fields() const; ///< Returns the cif::iset of key field names. Retrieved from the @ref category_validator for this category
|
||||
std::set<uint16_t> key_field_indices() const; ///< Returns a set of indices for the key fields.
|
||||
|
||||
iset key_items() const; ///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
|
||||
|
||||
std::set<uint16_t> key_item_indices() const; ///< Returns a set of indices for the key items.
|
||||
|
||||
/// @brief Set the validator for this category to @a v
|
||||
/// @param v The category_validator to assign. A nullptr value is allowed.
|
||||
@@ -146,7 +184,7 @@ class category
|
||||
|
||||
/// @brief Update the links in this category
|
||||
/// @param db The enclosing @ref datablock
|
||||
void update_links(datablock &db);
|
||||
void update_links(const datablock &db);
|
||||
|
||||
/// @brief Return the global @ref validator for the data
|
||||
/// @return The @ref validator or nullptr if not assigned
|
||||
@@ -162,7 +200,7 @@ class category
|
||||
|
||||
/// @brief Validate links, that means, values in this category should have an
|
||||
/// accompanying value in parent categories.
|
||||
///
|
||||
///
|
||||
/// @note
|
||||
/// The code makes one exception when validating missing links and that's between
|
||||
/// *atom_site* and a parent *pdbx_poly_seq_scheme* or *entity_poly_seq*.
|
||||
@@ -173,6 +211,11 @@ class category
|
||||
/// @return Returns true is all validations pass
|
||||
bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Strip removes items from this category that are invalid according to the assigned validator
|
||||
*/
|
||||
void strip();
|
||||
|
||||
/// @brief Equality operator, returns true if @a rhs is equal to this
|
||||
/// @param rhs The object to compare with
|
||||
/// @return True if the data contained is equal
|
||||
@@ -257,15 +300,15 @@ class category
|
||||
}
|
||||
|
||||
/// Return a count of the rows in this container
|
||||
size_t size() const
|
||||
std::size_t size() const
|
||||
{
|
||||
return std::distance(cbegin(), cend());
|
||||
}
|
||||
|
||||
/// Return the theoretical maximum number or rows that can be stored
|
||||
size_t max_size() const
|
||||
std::size_t max_size() const
|
||||
{
|
||||
return std::numeric_limits<size_t>::max(); // this is a bit optimistic, I guess
|
||||
return std::numeric_limits<std::size_t>::max(); // this is a bit optimistic, I guess
|
||||
}
|
||||
|
||||
/// Return true if the category is empty
|
||||
@@ -277,16 +320,24 @@ class category
|
||||
// --------------------------------------------------------------------
|
||||
// A category can have a key, as defined by the validator/dictionary
|
||||
|
||||
/// @brief The type of an element of the key_type
|
||||
struct key_element_type
|
||||
{
|
||||
std::string name; ///< Name of the item
|
||||
item_value value; ///< Value to be found
|
||||
bool may_be_null = false; ///< If true, value should be same or empty
|
||||
};
|
||||
|
||||
/// @brief The key type
|
||||
using key_type = row_initializer;
|
||||
using key_type = std::vector<key_element_type>;
|
||||
|
||||
/// @brief Return a row_handle for the row specified by \a key
|
||||
/// @param key The value for the key, fields specified in the dictionary should have a value
|
||||
/// @param key The value for the key, items specified in the dictionary should have a value
|
||||
/// @return The row found in the index, or an undefined row_handle
|
||||
row_handle operator[](const key_type &key);
|
||||
|
||||
/// @brief Return a const row_handle for the row specified by \a key
|
||||
/// @param key The value for the key, fields specified in the dictionary should have a value
|
||||
/// @param key The value for the key, items specified in the dictionary should have a value
|
||||
/// @return The row found in the index, or an undefined row_handle
|
||||
const row_handle operator[](const key_type &key) const
|
||||
{
|
||||
@@ -301,15 +352,15 @@ class category
|
||||
/// @code{.cpp}
|
||||
/// for (const auto &[name, value] : cat.rows<std::string,int>("item_name", "item_value"))
|
||||
/// std::cout << name << ": " << value << '\n';
|
||||
/// @endcode
|
||||
/// @endcode
|
||||
///
|
||||
/// @tparam Ts The types for the columns requested
|
||||
/// @param names The names for the columns requested
|
||||
/// @tparam Ts The types for the items requested
|
||||
/// @param names The names for the items requested
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
iterator_proxy<const category, Ts...> rows(Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return iterator_proxy<const category, Ts...>(*this, begin(), { names... });
|
||||
}
|
||||
|
||||
@@ -320,19 +371,19 @@ class category
|
||||
/// for (const auto &[name, value] : cat.rows<std::string,int>("item_name", "item_value"))
|
||||
/// std::cout << name << ": " << value << '\n';
|
||||
///
|
||||
/// // or in case we only need one column:
|
||||
/// // or in case we only need one item:
|
||||
///
|
||||
/// for (int id : cat.rows<int>("id"))
|
||||
/// std::cout << id << '\n';
|
||||
/// @endcode
|
||||
/// @endcode
|
||||
///
|
||||
/// @tparam Ts The types for the columns requested
|
||||
/// @param names The names for the columns requested
|
||||
/// @tparam Ts The types for the items requested
|
||||
/// @param names The names for the items requested
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
iterator_proxy<category, Ts...> rows(Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return iterator_proxy<category, Ts...>(*this, begin(), { names... });
|
||||
}
|
||||
|
||||
@@ -343,7 +394,7 @@ class category
|
||||
/// @code{.cpp}
|
||||
/// for (row_handle rh : cat.find(cif::key("first_name") == "John" and cif::key("last_name") == "Doe"))
|
||||
/// .. // do something with rh
|
||||
/// @endcode
|
||||
/// @endcode
|
||||
///
|
||||
/// @param cond The condition for the query
|
||||
/// @return A special iterator that loops over all elements that match. The iterator can be dereferenced
|
||||
@@ -397,17 +448,17 @@ class category
|
||||
/// @code{.cpp}
|
||||
/// for (const auto &[name, value] : cat.find<std::string,int>(cif::key("item_value") > 10, "item_name", "item_value"))
|
||||
/// std::cout << name << ": " << value << '\n';
|
||||
/// @endcode
|
||||
/// @endcode
|
||||
///
|
||||
/// @param cond The condition for the query
|
||||
/// @tparam Ts The types for the columns requested
|
||||
/// @param names The names for the columns requested
|
||||
/// @tparam Ts The types for the items requested
|
||||
/// @param names The names for the items requested
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<category, Ts...> find(condition &&cond, Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
|
||||
}
|
||||
|
||||
@@ -415,14 +466,14 @@ class category
|
||||
/// iterator can be used in a structured binding context.
|
||||
///
|
||||
/// @param cond The condition for the query
|
||||
/// @tparam Ts The types for the columns requested
|
||||
/// @param names The names for the columns requested
|
||||
/// @tparam Ts The types for the items requested
|
||||
/// @param names The names for the items requested
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<const category, Ts...> find(condition &&cond, Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return find<Ts...>(cbegin(), std::move(cond), std::forward<Ns>(names)...);
|
||||
}
|
||||
|
||||
@@ -431,14 +482,14 @@ class category
|
||||
///
|
||||
/// @param pos Iterator pointing to the location where to start
|
||||
/// @param cond The condition for the query
|
||||
/// @tparam Ts The types for the columns requested
|
||||
/// @param names The names for the columns requested
|
||||
/// @tparam Ts The types for the items requested
|
||||
/// @param names The names for the items requested
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<category, Ts...> find(const_iterator pos, condition &&cond, Ns... names)
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
|
||||
}
|
||||
|
||||
@@ -447,14 +498,14 @@ class category
|
||||
///
|
||||
/// @param pos Iterator pointing to the location where to start
|
||||
/// @param cond The condition for the query
|
||||
/// @tparam Ts The types for the columns requested
|
||||
/// @param names The names for the columns requested
|
||||
/// @tparam Ts The types for the items requested
|
||||
/// @param names The names for the items requested
|
||||
/// @return A special iterator that loops over all elements that match.
|
||||
|
||||
template <typename... Ts, typename... Ns>
|
||||
conditional_iterator_proxy<const category, Ts...> find(const_iterator pos, condition &&cond, Ns... names) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of item names should be equal to the number of types to return");
|
||||
return { *this, pos, std::move(cond), std::forward<Ns>(names)... };
|
||||
}
|
||||
|
||||
@@ -509,30 +560,30 @@ class category
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
/// @brief Return value for the column named @a column for the single row that
|
||||
/// @brief Return value for the item named @a item for the single row that
|
||||
/// matches @a cond. Throws @a multiple_results_error if there are is not exactly one row
|
||||
/// @tparam The type to use for the result
|
||||
/// @param cond The condition to search for
|
||||
/// @param column The name of the column to return the value for
|
||||
/// @param item The name of the item to return the value for
|
||||
/// @return The value found
|
||||
template <typename T>
|
||||
T find1(condition &&cond, const char *column) const
|
||||
T find1(condition &&cond, std::string_view item) const
|
||||
{
|
||||
return find1<T>(cbegin(), std::move(cond), column);
|
||||
return find1<T>(cbegin(), std::move(cond), item);
|
||||
}
|
||||
|
||||
/// @brief Return value for the column named @a column for the single row that
|
||||
/// @brief Return value for the item named @a item for the single row that
|
||||
/// matches @a cond when starting to search at @a pos.
|
||||
/// Throws @a multiple_results_error if there are is not exactly one row
|
||||
/// @tparam The type to use for the result
|
||||
/// @param pos The location to start the search
|
||||
/// @param cond The condition to search for
|
||||
/// @param column The name of the column to return the value for
|
||||
/// @param item The name of the item to return the value for
|
||||
/// @return The value found
|
||||
template <typename T, std::enable_if_t<not is_optional_v<T>, int> = 0>
|
||||
T find1(const_iterator pos, condition &&cond, const char *column) const
|
||||
T find1(const_iterator pos, condition &&cond, std::string_view item) const
|
||||
{
|
||||
auto h = find<T>(pos, std::move(cond), column);
|
||||
auto h = find<T>(pos, std::move(cond), item);
|
||||
|
||||
if (h.size() != 1)
|
||||
throw multiple_results_error();
|
||||
@@ -540,18 +591,18 @@ class category
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
/// @brief Return a value of type std::optional<T> for the column named @a column for the single row that
|
||||
/// @brief Return a value of type std::optional<T> for the item named @a item for the single row that
|
||||
/// matches @a cond when starting to search at @a pos.
|
||||
/// If the row was not found, an empty value is returned.
|
||||
/// @tparam The type to use for the result
|
||||
/// @param pos The location to start the search
|
||||
/// @param cond The condition to search for
|
||||
/// @param column The name of the column to return the value for
|
||||
/// @param item The name of the item to return the value for
|
||||
/// @return The value found, can be empty if no row matches the condition
|
||||
template <typename T, std::enable_if_t<is_optional_v<T>, int> = 0>
|
||||
T find1(const_iterator pos, condition &&cond, const char *column) const
|
||||
T find1(const_iterator pos, condition &&cond, std::string_view item) const
|
||||
{
|
||||
auto h = find<typename T::value_type>(pos, std::move(cond), column);
|
||||
auto h = find<typename T::value_type>(pos, std::move(cond), item);
|
||||
|
||||
if (h.size() > 1)
|
||||
throw multiple_results_error();
|
||||
@@ -562,34 +613,34 @@ class category
|
||||
return *h.begin();
|
||||
}
|
||||
|
||||
/// @brief Return a std::tuple for the values for the columns named in @a columns
|
||||
/// @brief Return a std::tuple for the values for the items named in @a items
|
||||
/// for the single row that matches @a cond
|
||||
/// Throws @a multiple_results_error if there are is not exactly one row
|
||||
/// @tparam The types to use for the resulting tuple
|
||||
/// @param cond The condition to search for
|
||||
/// @param columns The names of the columns to return the value for
|
||||
/// @param items The names of the items to return the value for
|
||||
/// @return The values found as a single tuple of type std::tuple<Ts...>
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
std::tuple<Ts...> find1(condition &&cond, Cs... columns) const
|
||||
std::tuple<Ts...> find1(condition &&cond, Cs... items) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
|
||||
return find1<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(columns)...);
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of item names should be equal to the number of types to return");
|
||||
// static_assert(std::is_same_v<Cs, const char*>..., "The item names should be const char");
|
||||
return find1<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(items)...);
|
||||
}
|
||||
|
||||
/// @brief Return a std::tuple for the values for the columns named in @a columns
|
||||
/// @brief Return a std::tuple for the values for the items named in @a items
|
||||
/// for the single row that matches @a cond when starting to search at @a pos
|
||||
/// Throws @a multiple_results_error if there are is not exactly one row
|
||||
/// @tparam The types to use for the resulting tuple
|
||||
/// @param pos The location to start the search
|
||||
/// @param cond The condition to search for
|
||||
/// @param columns The names of the columns to return the value for
|
||||
/// @param items The names of the items to return the value for
|
||||
/// @return The values found as a single tuple of type std::tuple<Ts...>
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
std::tuple<Ts...> find1(const_iterator pos, condition &&cond, Cs... columns) const
|
||||
std::tuple<Ts...> find1(const_iterator pos, condition &&cond, Cs... items) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(columns)...);
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of item names should be equal to the number of types to return");
|
||||
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(items)...);
|
||||
|
||||
if (h.size() != 1)
|
||||
throw multiple_results_error();
|
||||
@@ -638,74 +689,74 @@ class category
|
||||
return h.empty() ? row_handle{} : *h.begin();
|
||||
}
|
||||
|
||||
/// @brief Return the value for column @a column for the first row that matches condition @a cond
|
||||
/// @brief Return the value for item @a item for the first row that matches condition @a cond
|
||||
/// @tparam The type of the value to return
|
||||
/// @param cond The condition to search for
|
||||
/// @param column The column for which the value should be returned
|
||||
/// @param item The item for which the value should be returned
|
||||
/// @return The value found or a default constructed value if not found
|
||||
template <typename T>
|
||||
T find_first(condition &&cond, const char *column) const
|
||||
T find_first(condition &&cond, std::string_view item) const
|
||||
{
|
||||
return find_first<T>(cbegin(), std::move(cond), column);
|
||||
return find_first<T>(cbegin(), std::move(cond), item);
|
||||
}
|
||||
|
||||
/// @brief Return the value for column @a column for the first row that matches condition @a cond
|
||||
/// @brief Return the value for item @a item for the first row that matches condition @a cond
|
||||
/// when starting the search at @a pos
|
||||
/// @tparam The type of the value to return
|
||||
/// @param pos The location to start searching
|
||||
/// @param cond The condition to search for
|
||||
/// @param column The column for which the value should be returned
|
||||
/// @param item The item for which the value should be returned
|
||||
/// @return The value found or a default constructed value if not found
|
||||
template <typename T>
|
||||
T find_first(const_iterator pos, condition &&cond, const char *column) const
|
||||
T find_first(const_iterator pos, condition &&cond, std::string_view item) const
|
||||
{
|
||||
auto h = find<T>(pos, std::move(cond), column);
|
||||
auto h = find<T>(pos, std::move(cond), item);
|
||||
|
||||
return h.empty() ? T{} : *h.begin();
|
||||
}
|
||||
|
||||
/// @brief Return a tuple containing the values for the columns @a columns for the first row that matches condition @a cond
|
||||
/// @brief Return a tuple containing the values for the items @a items for the first row that matches condition @a cond
|
||||
/// @tparam The types of the values to return
|
||||
/// @param cond The condition to search for
|
||||
/// @param columns The columns for which the values should be returned
|
||||
/// @param items The items for which the values should be returned
|
||||
/// @return The values found or default constructed values if not found
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
std::tuple<Ts...> find_first(condition &&cond, Cs... columns) const
|
||||
std::tuple<Ts...> find_first(condition &&cond, Cs... items) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
|
||||
return find_first<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(columns)...);
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of item names should be equal to the number of types to return");
|
||||
// static_assert(std::is_same_v<Cs, const char*>..., "The item names should be const char");
|
||||
return find_first<Ts...>(cbegin(), std::move(cond), std::forward<Cs>(items)...);
|
||||
}
|
||||
|
||||
/// @brief Return a tuple containing the values for the columns @a columns for the first row that matches condition @a cond
|
||||
/// @brief Return a tuple containing the values for the items @a items for the first row that matches condition @a cond
|
||||
/// when starting the search at @a pos
|
||||
/// @tparam The types of the values to return
|
||||
/// @param pos The location to start searching
|
||||
/// @param cond The condition to search for
|
||||
/// @param columns The columns for which the values should be returned
|
||||
/// @param items The items for which the values should be returned
|
||||
/// @return The values found or default constructed values if not found
|
||||
template <typename... Ts, typename... Cs, typename U = std::enable_if_t<sizeof...(Ts) != 1>>
|
||||
std::tuple<Ts...> find_first(const_iterator pos, condition &&cond, Cs... columns) const
|
||||
std::tuple<Ts...> find_first(const_iterator pos, condition &&cond, Cs... items) const
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of column titles should be equal to the number of types to return");
|
||||
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(columns)...);
|
||||
static_assert(sizeof...(Ts) == sizeof...(Cs), "The number of item names should be equal to the number of types to return");
|
||||
auto h = find<Ts...>(pos, std::move(cond), std::forward<Cs>(items)...);
|
||||
|
||||
return h.empty() ? std::tuple<Ts...>{} : *h.begin();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @brief Return the maximum value for column @a column for all rows that match condition @a cond
|
||||
/// @brief Return the maximum value for item @a item for all rows that match condition @a cond
|
||||
/// @tparam The type of the value to return
|
||||
/// @param column The column to use for the value
|
||||
/// @param item The item to use for the value
|
||||
/// @param cond The condition to search for
|
||||
/// @return The value found or the minimal value for the type
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_max(const char *column, condition &&cond) const
|
||||
T find_max(std::string_view item, condition &&cond) const
|
||||
{
|
||||
T result = std::numeric_limits<T>::min();
|
||||
|
||||
for (auto v : find<T>(std::move(cond), column))
|
||||
for (auto v : find<T>(std::move(cond), item))
|
||||
{
|
||||
if (result < v)
|
||||
result = v;
|
||||
@@ -714,27 +765,27 @@ class category
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Return the maximum value for column @a column for all rows
|
||||
/// @brief Return the maximum value for item @a item for all rows
|
||||
/// @tparam The type of the value to return
|
||||
/// @param column The column to use for the value
|
||||
/// @param item The item to use for the value
|
||||
/// @return The value found or the minimal value for the type
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_max(const char *column) const
|
||||
T find_max(std::string_view item) const
|
||||
{
|
||||
return find_max<T>(column, all());
|
||||
return find_max<T>(item, all());
|
||||
}
|
||||
|
||||
/// @brief Return the minimum value for column @a column for all rows that match condition @a cond
|
||||
/// @brief Return the minimum value for item @a item for all rows that match condition @a cond
|
||||
/// @tparam The type of the value to return
|
||||
/// @param column The column to use for the value
|
||||
/// @param item The item to use for the value
|
||||
/// @param cond The condition to search for
|
||||
/// @return The value found or the maximum value for the type
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_min(const char *column, condition &&cond) const
|
||||
T find_min(std::string_view item, condition &&cond) const
|
||||
{
|
||||
T result = std::numeric_limits<T>::max();
|
||||
|
||||
for (auto v : find<T>(std::move(cond), column))
|
||||
for (auto v : find<T>(std::move(cond), item))
|
||||
{
|
||||
if (result > v)
|
||||
result = v;
|
||||
@@ -743,20 +794,28 @@ class category
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Return the maximum value for column @a column for all rows
|
||||
/// @brief Return the maximum value for item @a item for all rows
|
||||
/// @tparam The type of the value to return
|
||||
/// @param column The column to use for the value
|
||||
/// @param item The item to use for the value
|
||||
/// @return The value found or the maximum value for the type
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
T find_min(const char *column) const
|
||||
T find_min(std::string_view item) const
|
||||
{
|
||||
return find_min<T>(column, all());
|
||||
return find_min<T>(item, all());
|
||||
}
|
||||
|
||||
/// @brief Return whether a row exists that matches condition @a cond
|
||||
/// @param cond The condition to match
|
||||
/// @return True if a row exists
|
||||
bool exists(condition &&cond) const
|
||||
[[deprecated("Use contains instead")]] bool exists(condition &&cond) const
|
||||
{
|
||||
return contains(std::move(cond));
|
||||
}
|
||||
|
||||
/// @brief Return whether a row exists that matches condition @a cond
|
||||
/// @param cond The condition to match
|
||||
/// @return True if a row exists
|
||||
bool contains(condition &&cond) const
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
@@ -787,9 +846,9 @@ class category
|
||||
/// @brief Return the total number of rows that match condition @a cond
|
||||
/// @param cond The condition to match
|
||||
/// @return The count
|
||||
size_t count(condition &&cond) const
|
||||
std::size_t count(condition &&cond) const
|
||||
{
|
||||
size_t result = 0;
|
||||
std::size_t result = 0;
|
||||
|
||||
if (cond)
|
||||
{
|
||||
@@ -846,7 +905,7 @@ class category
|
||||
// insert_impl(pos, std::move(row));
|
||||
// }
|
||||
|
||||
/// Erase the row pointed to by @a pos and return the iterator to the
|
||||
/// Erase the row pointed to by @a pos and return the iterator to the
|
||||
/// row following pos.
|
||||
iterator erase(iterator pos);
|
||||
|
||||
@@ -859,14 +918,14 @@ class category
|
||||
/// @brief Erase all rows that match condition @a cond
|
||||
/// @param cond The condition
|
||||
/// @return The number of rows that have been erased
|
||||
size_t erase(condition &&cond);
|
||||
std::size_t erase(condition &&cond);
|
||||
|
||||
/// @brief Erase all rows that match condition @a cond calling
|
||||
/// the visitor function @a visit for each before actually erasing it.
|
||||
/// @param cond The condition
|
||||
/// @param visit The visitor function
|
||||
/// @return The number of rows that have been erased
|
||||
size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);
|
||||
std::size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);
|
||||
|
||||
/// @brief Emplace the values in @a ri in a new row
|
||||
/// @param ri An object containing the values to insert
|
||||
@@ -890,7 +949,7 @@ class category
|
||||
for (auto i = b; i != e; ++i)
|
||||
{
|
||||
// item_value *new_item = this->create_item(*i);
|
||||
r->append(add_column(i->name()), { i->value() });
|
||||
r->append(add_item(i->name()), i->value());
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -903,6 +962,12 @@ class category
|
||||
return insert_impl(cend(), r);
|
||||
}
|
||||
|
||||
void emplace(const_iterator b, const_iterator e)
|
||||
{
|
||||
while (b != e)
|
||||
emplace(*b++);
|
||||
}
|
||||
|
||||
/// @brief Completely erase all rows contained in this category
|
||||
void clear();
|
||||
|
||||
@@ -912,7 +977,6 @@ class category
|
||||
/// result is unique in the context of this category
|
||||
std::string get_unique_id(std::function<std::string(int)> generator = cif::cif_id_for_number);
|
||||
|
||||
|
||||
/// @brief Generate a new, unique ID based on a string prefix followed by a number
|
||||
/// @param prefix The string prefix
|
||||
/// @return a new unique ID
|
||||
@@ -922,98 +986,102 @@ class category
|
||||
{ return prefix + std::to_string(nr + 1); });
|
||||
}
|
||||
|
||||
/// @brief Generate a new, unique value for a item named @a item_name
|
||||
/// @param item_name The name of the item
|
||||
/// @return a new unique value
|
||||
std::string get_unique_value(std::string_view item_name);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief Update a single column named @a tag in the rows that match \a cond to value \a value
|
||||
using value_provider_type = std::function<item_value(const item_value &)>;
|
||||
|
||||
/// \brief Update a single item named @a item_name in the rows that match
|
||||
/// \a cond to values provided by a callback function \a value_provider
|
||||
/// making sure the linked categories are updated according to the link.
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(condition &&cond, std::string_view tag, std::string_view value)
|
||||
void update_value(condition &&cond, std::string_view item_name,
|
||||
value_provider_type &&value_provider)
|
||||
{
|
||||
auto rs = find(std::move(cond));
|
||||
std::vector<row_handle> rows;
|
||||
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
|
||||
update_value(rows, tag, value);
|
||||
update_value(rows, item_name, std::move(value_provider));
|
||||
}
|
||||
|
||||
/// \brief Update a single column named @a tag in @a rows to value \a value
|
||||
/// \brief Update a single item named @a item_name in the rows \a rows
|
||||
/// to values provided by a callback function \a value_provider
|
||||
/// making sure the linked categories are updated according to the link.
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view tag, std::string_view value);
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view item_name,
|
||||
value_provider_type &&value_provider);
|
||||
|
||||
/// \brief Update a single item named @a item_name in the rows that match \a cond to value \a value
|
||||
/// making sure the linked categories are updated according to the link.
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(condition &&cond, std::string_view item_name, item_value value)
|
||||
{
|
||||
auto rs = find(std::move(cond));
|
||||
std::vector<row_handle> rows;
|
||||
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
|
||||
update_value(rows, item_name, value);
|
||||
}
|
||||
|
||||
/// \brief Update a single item named @a item_name in @a rows to value \a value
|
||||
/// making sure the linked categories are updated according to the link.
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, item_value value)
|
||||
{
|
||||
update_value(rows, item_name, [value](const item_value &v)
|
||||
{ return value; });
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief Return the index number for \a column_name
|
||||
/// \brief Return the index number for \a item_name
|
||||
|
||||
uint16_t get_column_ix(std::string_view column_name) const
|
||||
{
|
||||
uint16_t result;
|
||||
uint16_t get_item_ix(std::string_view item_name) const;
|
||||
|
||||
for (result = 0; result < m_columns.size(); ++result)
|
||||
{
|
||||
if (iequals(column_name, m_columns[result].m_name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (VERBOSE > 0 and result == m_columns.size() and m_cat_validator != nullptr) // validate the name, if it is known at all (since it was not found)
|
||||
{
|
||||
auto iv = m_cat_validator->get_validator_for_item(column_name);
|
||||
if (iv == nullptr)
|
||||
std::cerr << "Invalid name used '" << column_name << "' is not a known column in " + m_name << '\n';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Return the name for column with index @a ix
|
||||
/// @brief Return the name for item with index @a ix
|
||||
/// @param ix The index number
|
||||
/// @return The name of the column
|
||||
std::string_view get_column_name(uint16_t ix) const
|
||||
/// @return The name of the item
|
||||
const std::string &get_item_name(uint16_t ix) const
|
||||
{
|
||||
if (ix >= m_columns.size())
|
||||
throw std::out_of_range("column index is out of range");
|
||||
if (ix >= m_items.size())
|
||||
throw std::out_of_range("item index is out of range");
|
||||
|
||||
return m_columns[ix].m_name;
|
||||
return m_items[ix].m_name;
|
||||
}
|
||||
|
||||
/// @brief Make sure a column with name @a column_name is known and return its index number
|
||||
/// @param column_name The name of the column
|
||||
/// @return The index number of the column
|
||||
uint16_t add_column(std::string_view column_name)
|
||||
/// @brief Make sure a item with name @a item_name is known and return its index number
|
||||
/// @param item_name The name of the item
|
||||
/// @return The index number of the item
|
||||
uint16_t add_item(std::string_view item_name);
|
||||
|
||||
/** @brief Remove item name @a colum_name
|
||||
* @param item_name The item to be removed
|
||||
*/
|
||||
void remove_item(std::string_view item_name);
|
||||
|
||||
/** @brief Rename item @a from_name to @a to_name */
|
||||
void rename_item(std::string_view from_name, std::string_view to_name);
|
||||
|
||||
/// @brief Return whether a item with name @a name exists in this category
|
||||
/// @param name The name of the item
|
||||
/// @return True if the item exists
|
||||
bool has_item(std::string_view name) const
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
uint16_t result = get_column_ix(column_name);
|
||||
|
||||
if (result == m_columns.size())
|
||||
{
|
||||
const item_validator *item_validator = nullptr;
|
||||
|
||||
if (m_cat_validator != nullptr)
|
||||
{
|
||||
item_validator = m_cat_validator->get_validator_for_item(column_name);
|
||||
if (item_validator == nullptr)
|
||||
m_validator->report_error("tag " + std::string(column_name) + " not allowed in category " + m_name, false);
|
||||
}
|
||||
|
||||
m_columns.emplace_back(column_name, item_validator);
|
||||
}
|
||||
|
||||
return result;
|
||||
return get_item_ix(name) < m_items.size();
|
||||
}
|
||||
|
||||
/// @brief Return whether a column with name @a name exists in this category
|
||||
/// @param name The name of the column
|
||||
/// @return True if the column exists
|
||||
bool has_column(std::string_view name) const
|
||||
{
|
||||
return get_column_ix(name) < m_columns.size();
|
||||
}
|
||||
|
||||
/// @brief Return the cif::iset of columns in this category
|
||||
iset get_columns() const;
|
||||
/// @brief Return the cif::iset of items in this category
|
||||
iset get_items() const;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -1029,30 +1097,36 @@ class category
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// This function returns effectively the list of fully qualified column
|
||||
/// names, that is category_name + '.' + column_name for each column
|
||||
std::vector<std::string> get_tag_order() const;
|
||||
/// This function returns effectively the list of fully qualified item
|
||||
/// names, that is category_name + '.' + item_name for each item
|
||||
[[deprecated("use get_item_order instead")]] std::vector<std::string> get_tag_order() const
|
||||
{
|
||||
return get_item_order();
|
||||
}
|
||||
|
||||
/// This function returns effectively the list of fully qualified item
|
||||
/// names, that is category_name + '.' + item_name for each item
|
||||
std::vector<std::string> get_item_order() const;
|
||||
|
||||
/// Write the contents of the category to the std::ostream @a os
|
||||
void write(std::ostream &os) const;
|
||||
|
||||
/// @brief Write the contents of the category to the std::ostream @a os and
|
||||
/// use @a order as the order of the columns. If @a addMissingColumns is
|
||||
/// false, columns that do not contain any value will be suppressed
|
||||
/// use @a order as the order of the items. If @a addMissingItems is
|
||||
/// false, items that do not contain any value will be suppressed
|
||||
/// @param os The std::ostream to write to
|
||||
/// @param order The order in which the columns should appear
|
||||
/// @param addMissingColumns When false, empty columns are suppressed from the output
|
||||
void write(std::ostream &os, const std::vector<std::string> &order, bool addMissingColumns = true);
|
||||
/// @param order The order in which the items should appear
|
||||
/// @param addMissingItems When false, empty items are suppressed from the output
|
||||
void write(std::ostream &os, const std::vector<std::string> &order, bool addMissingItems = true);
|
||||
|
||||
private:
|
||||
void write(std::ostream &os, const std::vector<uint16_t> &order, bool includeEmptyColumns) const;
|
||||
void write(std::ostream &os, const std::vector<uint16_t> &order, bool includeEmptyItems) const;
|
||||
|
||||
public:
|
||||
|
||||
/// friend function to make it possible to do:
|
||||
/// @code {.cpp}
|
||||
/// std::cout << my_category;
|
||||
/// @endcode
|
||||
/// @endcode
|
||||
friend std::ostream &operator<<(std::ostream &os, const category &cat)
|
||||
{
|
||||
cat.write(os);
|
||||
@@ -1060,7 +1134,7 @@ class category
|
||||
}
|
||||
|
||||
private:
|
||||
void update_value(row *row, uint16_t column, std::string_view value, bool updateLinked, bool validate = true);
|
||||
void update_value(row *row, uint16_t item, item_value value, bool updateLinked, bool validate = true);
|
||||
|
||||
void erase_orphans(condition &&cond, category &parent);
|
||||
|
||||
@@ -1097,12 +1171,12 @@ class category
|
||||
|
||||
row_handle create_copy(row_handle r);
|
||||
|
||||
struct item_column
|
||||
struct item_entry
|
||||
{
|
||||
std::string m_name;
|
||||
const item_validator *m_validator;
|
||||
|
||||
item_column(std::string_view name, const item_validator *validator)
|
||||
item_entry(std::string_view name, const item_validator *validator)
|
||||
: m_name(name)
|
||||
, m_validator(validator)
|
||||
{
|
||||
@@ -1117,6 +1191,7 @@ class category
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: NEED TO FIX THIS!
|
||||
category *linked;
|
||||
const link_validator *v;
|
||||
};
|
||||
@@ -1132,12 +1207,12 @@ class category
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void swap_item(uint16_t column_ix, row_handle &a, row_handle &b);
|
||||
void swap_item(uint16_t item_ix, row_handle &a, row_handle &b);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::string m_name;
|
||||
std::vector<item_column> m_columns;
|
||||
std::vector<item_entry> m_items;
|
||||
const validator *m_validator = nullptr;
|
||||
const category_validator *m_cat_validator = nullptr;
|
||||
std::vector<link> m_parent_links, m_child_links;
|
||||
|
||||
@@ -44,10 +44,9 @@
|
||||
/// The data is loaded by default from a file called `components.cif`. This file
|
||||
/// is located using load_resource. (See documentation on cif::load_resource for more information)
|
||||
///
|
||||
/// But if the CCP4 environment is available at runtime, the compound information
|
||||
/// may also be generated from the CCP4 monomer library.
|
||||
///
|
||||
/// Note that the information in CCP4 and CCD is not equal.
|
||||
/// Note that since version 6 the CCP4 monomer library is no longer used.
|
||||
|
||||
/// See also :doc:`/compound` for more information.
|
||||
|
||||
namespace cif
|
||||
{
|
||||
@@ -139,7 +138,7 @@ struct compound_bond
|
||||
/// This information is derived from the CDD by default.
|
||||
///
|
||||
/// To create compounds, you use the factory method. You can add your own
|
||||
/// compound definitions by calling the addExtraComponents function and
|
||||
/// compound definitions by calling the push_dictionary function and
|
||||
/// pass it a valid CCD formatted file.
|
||||
|
||||
class compound
|
||||
@@ -154,10 +153,6 @@ class compound
|
||||
float formula_weight() const { return m_formula_weight; } ///< Return the formula mass of the chemical component in Daltons.
|
||||
int formal_charge() const { return m_formal_charge; } ///< Return the formal charge on the chemical component.
|
||||
|
||||
/// The group record is only available in CCP4 monomer library files.
|
||||
/// For CCD entries this value will always contain 'non-polymer'
|
||||
std::string group() const { return m_group; }
|
||||
|
||||
const std::vector<compound_atom> &atoms() const { return m_atoms; } ///< Return the list of atoms for this compound
|
||||
const std::vector<compound_bond> &bonds() const { return m_bonds; } ///< Return the list of bonds for this compound
|
||||
|
||||
@@ -171,19 +166,27 @@ class compound
|
||||
return m_id == "HOH" or m_id == "H2O" or m_id == "WAT";
|
||||
}
|
||||
|
||||
/** \brief Return whether this compound has a type of either 'peptide linking' or 'L-peptide linking' */
|
||||
bool is_peptide() const;
|
||||
|
||||
/** \brief Return whether this compound has a type of either 'DNA linking' or 'RNA linking' */
|
||||
bool is_base() const;
|
||||
|
||||
char one_letter_code() const { return m_one_letter_code; }; ///< Return the one letter code to use in a canonical sequence. If unknown the value '\0' is returned
|
||||
std::string parent_id() const { return m_parent_id; }; ///< Return the parent id code in case a parent is specified (e.g. MET for MSE)
|
||||
|
||||
private:
|
||||
friend class compound_factory_impl;
|
||||
friend class CCD_compound_factory_impl;
|
||||
friend class CCP4_compound_factory_impl;
|
||||
friend class local_compound_factory_impl;
|
||||
|
||||
compound(cif::datablock &db);
|
||||
compound(cif::datablock &db, const std::string &id, const std::string &name, const std::string &type, const std::string &group);
|
||||
compound(datablock &db);
|
||||
|
||||
std::string m_id;
|
||||
std::string m_name;
|
||||
std::string m_type;
|
||||
std::string m_group;
|
||||
std::string m_formula;
|
||||
char m_one_letter_code = 0;
|
||||
std::string m_parent_id;
|
||||
float m_formula_weight = 0;
|
||||
int m_formal_charge = 0;
|
||||
std::vector<compound_atom> m_atoms;
|
||||
@@ -221,28 +224,83 @@ class compound_factory
|
||||
/// Override any previously loaded dictionary with @a inDictFile
|
||||
void push_dictionary(const std::filesystem::path &inDictFile);
|
||||
|
||||
/** @brief Override any previously loaded dictionary with the data in @a file
|
||||
*
|
||||
* @note experimental feature
|
||||
*
|
||||
* Load the file @a file as a source for compound information. This may
|
||||
* be e.g. a regular mmCIF file with extra files containing compound
|
||||
* information.
|
||||
*
|
||||
* Be carefull to remove the block again, best use @ref cif::compound_source
|
||||
* as a stack based object.
|
||||
*/
|
||||
|
||||
void push_dictionary(const file &file);
|
||||
|
||||
/// Remove the last pushed dictionary
|
||||
void pop_dictionary();
|
||||
|
||||
/// Return whether @a res_name is a valid and known peptide
|
||||
[[deprecated("use is_peptide or is_std_peptide instead)")]]
|
||||
bool is_known_peptide(const std::string &res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a valid and known base
|
||||
[[deprecated("use is_base or is_std_base instead)")]]
|
||||
bool is_known_base(const std::string &res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a peptide
|
||||
bool is_peptide(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a base
|
||||
bool is_base(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard peptides
|
||||
bool is_std_peptide(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard bases
|
||||
bool is_std_base(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a monomer (either base or peptide)
|
||||
bool is_monomer(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard bases or peptides
|
||||
bool is_std_monomer(std::string_view res_name) const
|
||||
{
|
||||
return is_std_base(res_name) or is_std_peptide(res_name);
|
||||
}
|
||||
|
||||
/// Return whether @a res_name is water
|
||||
bool is_water(std::string_view res_name) const
|
||||
{
|
||||
return res_name == "HOH" or res_name == "H2O" or res_name == "WAT";
|
||||
}
|
||||
|
||||
/// Return whether @a res_name already exists, without creating it.
|
||||
bool exists(std::string_view res_name) const;
|
||||
|
||||
/// \brief Create the compound object for \a id
|
||||
///
|
||||
/// This will create the compound instance for \a id if it doesn't exist already.
|
||||
/// The result is owned by this factory and should not be deleted by the user.
|
||||
/// \param id The compound ID, a three letter code usually
|
||||
/// \result The compound, or nullptr if it could not be created (missing info)
|
||||
const compound *create(std::string id);
|
||||
const compound *create(std::string_view id);
|
||||
|
||||
~compound_factory();
|
||||
|
||||
CIFPP_EXPORT static const std::map<std::string, char> kAAMap, ///< Globally accessible static list of the default amino acids
|
||||
kBaseMap; ///< Globally accessible static list of the default bases
|
||||
|
||||
void report_missing_compound(std::string_view compound_id);
|
||||
|
||||
bool get_report_missing() const { return m_report_missing; }
|
||||
|
||||
void set_report_missing(bool report)
|
||||
{
|
||||
m_report_missing = report;
|
||||
}
|
||||
|
||||
private:
|
||||
compound_factory();
|
||||
|
||||
@@ -254,6 +312,38 @@ class compound_factory
|
||||
static bool s_use_thread_local_instance;
|
||||
|
||||
std::shared_ptr<compound_factory_impl> m_impl;
|
||||
bool m_report_missing = true;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Stack based source for compound info.
|
||||
*
|
||||
* Use this class to temporarily add a compound source to the
|
||||
* compound_factory.
|
||||
*
|
||||
* @code{.cpp}
|
||||
* cif::file f("1cbs-with-custom-rea.cif");
|
||||
* cif::compound_source cs(f);
|
||||
*
|
||||
* auto &cf = cif::compound_factory::instance();
|
||||
* auto rea_compound = cf.create("REA");
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
class compound_source
|
||||
{
|
||||
public:
|
||||
compound_source(const file &file)
|
||||
{
|
||||
compound_factory::instance().push_dictionary(file);
|
||||
}
|
||||
|
||||
~compound_source()
|
||||
{
|
||||
compound_factory::instance().pop_dictionary();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/format.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
@@ -39,58 +41,58 @@
|
||||
* query you can use to find rows in a @ref cif::category
|
||||
*
|
||||
* Conditions are created as standard C++ expressions. That means
|
||||
* you can use the standard comparison operators to compare field
|
||||
* you can use the standard comparison operators to compare item
|
||||
* contents with a value and boolean operators to chain everything
|
||||
* together.
|
||||
*
|
||||
* To create a query that simply compares one field with one value:
|
||||
* To create a query that simply compares one item with one value:
|
||||
*
|
||||
* @code {.cpp}
|
||||
* cif::condition c = cif::key("id") == 1;
|
||||
* @endcode
|
||||
*
|
||||
* That will find rows where the ID field contains the number 1. If
|
||||
*
|
||||
* That will find rows where the ID item contains the number 1. If
|
||||
* using cif::key is a bit too much typing, you can also write:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* using namespace cif::literals;
|
||||
*
|
||||
*
|
||||
* cif::condition c2 = "id"_key == 1;
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* Now if you want both ID = 1 and ID = 2 in the result:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c3 = "id"_key == 1 or "id"_key == 2;
|
||||
* @endcode
|
||||
*
|
||||
* There are some special values you can use. To find rows with field that
|
||||
*
|
||||
* There are some special values you can use. To find rows with item that
|
||||
* do not have a value:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c4 = "type"_key == cif::null;
|
||||
* @endcode
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* Of if it should not be NULL:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c5 = "type"_key != cif::null;
|
||||
* @endcode
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* There's even a way to find all records:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c6 = cif::all;
|
||||
* @endcode
|
||||
*
|
||||
* And when you want to search for any column containing the value 'foo':
|
||||
*
|
||||
*
|
||||
* And when you want to search for any item containing the value 'foo':
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c7 = cif::any == "foo";
|
||||
* @endcode
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* All these conditions can be chained together again:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto c8 = std::move(c3) and std::move(c5);
|
||||
* @endcode
|
||||
@@ -104,31 +106,40 @@ namespace cif
|
||||
/// we declare a function to access its contents
|
||||
|
||||
/**
|
||||
* @brief Get the fields that can be used as key in conditions for a category
|
||||
*
|
||||
* @param cat The category whose fields to return
|
||||
* @return iset The set of key field names
|
||||
* @brief Get the items that can be used as key in conditions for a category
|
||||
*
|
||||
* @param cat The category whose items to return
|
||||
* @return iset The set of key item names
|
||||
*/
|
||||
[[deprecated("use get_category_items instead")]]
|
||||
iset get_category_fields(const category &cat);
|
||||
|
||||
/**
|
||||
* @brief Get the column index for column @a col in category @a cat
|
||||
*
|
||||
* @param cat The category
|
||||
* @param col The name of the column
|
||||
* @return uint16_t The index
|
||||
* @brief Get the items that can be used as key in conditions for a category
|
||||
*
|
||||
* @param cat The category whose items to return
|
||||
* @return iset The set of key field names
|
||||
*/
|
||||
uint16_t get_column_ix(const category &cat, std::string_view col);
|
||||
iset get_category_items(const category &cat);
|
||||
|
||||
/**
|
||||
* @brief Return whether the column @a col in category @a cat has a primitive type of *uchar*
|
||||
*
|
||||
* @brief Get the item index for item @a col in category @a cat
|
||||
*
|
||||
* @param cat The category
|
||||
* @param col The column name
|
||||
* @param col The name of the item
|
||||
* @return uint16_t The index
|
||||
*/
|
||||
uint16_t get_item_ix(const category &cat, std::string_view col);
|
||||
|
||||
/**
|
||||
* @brief Return whether the item @a col in category @a cat has a primitive type of *uchar*
|
||||
*
|
||||
* @param cat The category
|
||||
* @param col The item name
|
||||
* @return true If the primitive type is of type *uchar*
|
||||
* @return false If the primitive type is not of type *uchar*
|
||||
*/
|
||||
bool is_column_type_uchar(const category &cat, std::string_view col);
|
||||
bool is_item_type_uchar(const category &cat, std::string_view col);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// some more templates to be able to do querying
|
||||
@@ -165,14 +176,13 @@ namespace detail
|
||||
class condition
|
||||
{
|
||||
public:
|
||||
|
||||
/** @cond */
|
||||
using condition_impl = detail::condition_impl;
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Construct a new, empty condition object
|
||||
*
|
||||
*
|
||||
*/
|
||||
condition()
|
||||
: m_impl(nullptr)
|
||||
@@ -181,7 +191,7 @@ class condition
|
||||
|
||||
/**
|
||||
* @brief Construct a new condition object with implementation @a impl
|
||||
*
|
||||
*
|
||||
* @param impl The implementation to use
|
||||
*/
|
||||
explicit condition(condition_impl *impl)
|
||||
@@ -219,16 +229,16 @@ class condition
|
||||
|
||||
/**
|
||||
* @brief Prepare the condition to be used on category @a c. This will
|
||||
* take care of setting the correct indices for fields e.g.
|
||||
*
|
||||
* take care of setting the correct indices for items e.g.
|
||||
*
|
||||
* @param c The category this query should act upon
|
||||
*/
|
||||
void prepare(const category &c);
|
||||
|
||||
/**
|
||||
* @brief This operator returns true if the row referenced by @a r is
|
||||
* @brief This operator returns true if the row referenced by @a r is
|
||||
* a match for this condition.
|
||||
*
|
||||
*
|
||||
* @param r The reference to a row.
|
||||
* @return true If there is a match
|
||||
* @return false If there is no match
|
||||
@@ -253,7 +263,7 @@ class condition
|
||||
/**
|
||||
* @brief If the prepare step found out there is only one hit
|
||||
* this single hit can be returned by this method.
|
||||
*
|
||||
*
|
||||
* @return std::optional<row_handle> The result will contain
|
||||
* a row reference if there is a single hit, it will be empty otherwise
|
||||
*/
|
||||
@@ -282,7 +292,7 @@ class condition
|
||||
|
||||
/**
|
||||
* @brief Operator to use to write out a condition to @a os, for debugging purposes
|
||||
*
|
||||
*
|
||||
* @param os The std::ostream to write to
|
||||
* @param cond The condition to write
|
||||
* @return std::ostream& The same as @a os
|
||||
@@ -305,14 +315,14 @@ namespace detail
|
||||
{
|
||||
struct key_is_empty_condition_impl : public condition_impl
|
||||
{
|
||||
key_is_empty_condition_impl(const std::string &item_tag)
|
||||
: m_item_tag(item_tag)
|
||||
key_is_empty_condition_impl(const std::string &item_name)
|
||||
: m_item_name(item_name)
|
||||
{
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
m_item_ix = get_column_ix(c, m_item_tag);
|
||||
m_item_ix = get_item_ix(c, m_item_name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -323,23 +333,23 @@ namespace detail
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_tag << " IS NULL";
|
||||
os << m_item_name << " IS NULL";
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
};
|
||||
|
||||
struct key_is_not_empty_condition_impl : public condition_impl
|
||||
{
|
||||
key_is_not_empty_condition_impl(const std::string &item_tag)
|
||||
: m_item_tag(item_tag)
|
||||
key_is_not_empty_condition_impl(const std::string &item_name)
|
||||
: m_item_name(item_name)
|
||||
{
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
m_item_ix = get_column_ix(c, m_item_tag);
|
||||
m_item_ix = get_item_ix(c, m_item_name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -350,18 +360,18 @@ namespace detail
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_tag << " IS NOT NULL";
|
||||
os << m_item_name << " IS NOT NULL";
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
};
|
||||
|
||||
struct key_equals_condition_impl : public condition_impl
|
||||
{
|
||||
key_equals_condition_impl(item &&i)
|
||||
: m_item_tag(i.name())
|
||||
, m_value(i.value())
|
||||
: m_item_name(i.name())
|
||||
, m_value(std::forward<item_value>(i.value()))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -374,7 +384,7 @@ namespace detail
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value;
|
||||
os << m_item_name << (m_icase ? "^ " : " ") << " == " << m_value;
|
||||
}
|
||||
|
||||
virtual std::optional<row_handle> single() const override
|
||||
@@ -390,23 +400,23 @@ namespace detail
|
||||
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
|
||||
return m_single_hit == ri->m_single_hit;
|
||||
else
|
||||
// watch out, both m_item_ix might be the same while tags might be diffent (in case they both do not exist in the category)
|
||||
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_tag == ri->m_item_tag;
|
||||
// watch out, both m_item_ix might be the same while item_names might be diffent (in case they both do not exist in the category)
|
||||
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_name == ri->m_item_name;
|
||||
}
|
||||
return this == rhs;
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
bool m_icase = false;
|
||||
std::string m_value;
|
||||
item_value m_value;
|
||||
std::optional<row_handle> m_single_hit;
|
||||
};
|
||||
|
||||
struct key_equals_or_empty_condition_impl : public condition_impl
|
||||
{
|
||||
key_equals_or_empty_condition_impl(key_equals_condition_impl *equals)
|
||||
: m_item_tag(equals->m_item_tag)
|
||||
: m_item_name(equals->m_item_name)
|
||||
, m_value(equals->m_value)
|
||||
, m_icase(equals->m_icase)
|
||||
, m_single_hit(equals->m_single_hit)
|
||||
@@ -415,8 +425,8 @@ namespace detail
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
m_item_ix = get_column_ix(c, m_item_tag);
|
||||
m_icase = is_column_type_uchar(c, m_item_tag);
|
||||
m_item_ix = get_item_ix(c, m_item_name);
|
||||
m_icase = is_item_type_uchar(c, m_item_name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -432,7 +442,7 @@ namespace detail
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << '(' << m_item_tag << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_tag << " IS NULL)";
|
||||
os << '(' << m_item_name << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_name << " IS NULL)";
|
||||
}
|
||||
|
||||
virtual std::optional<row_handle> single() const override
|
||||
@@ -448,15 +458,15 @@ namespace detail
|
||||
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
|
||||
return m_single_hit == ri->m_single_hit;
|
||||
else
|
||||
// watch out, both m_item_ix might be the same while tags might be diffent (in case they both do not exist in the category)
|
||||
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_tag == ri->m_item_tag;
|
||||
// watch out, both m_item_ix might be the same while item_names might be diffent (in case they both do not exist in the category)
|
||||
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_name == ri->m_item_name;
|
||||
}
|
||||
return this == rhs;
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
std::string m_value;
|
||||
item_value &m_value;
|
||||
bool m_icase = false;
|
||||
std::optional<row_handle> m_single_hit;
|
||||
};
|
||||
@@ -464,8 +474,8 @@ namespace detail
|
||||
struct key_compare_condition_impl : public condition_impl
|
||||
{
|
||||
template <typename COMP>
|
||||
key_compare_condition_impl(const std::string &item_tag, COMP &&comp, const std::string &s)
|
||||
: m_item_tag(item_tag)
|
||||
key_compare_condition_impl(const std::string &item_name, COMP &&comp, const std::string &s)
|
||||
: m_item_name(item_name)
|
||||
, m_compare(std::move(comp))
|
||||
, m_str(s)
|
||||
{
|
||||
@@ -473,8 +483,8 @@ namespace detail
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
m_item_ix = get_column_ix(c, m_item_tag);
|
||||
m_icase = is_column_type_uchar(c, m_item_tag);
|
||||
m_item_ix = get_item_ix(c, m_item_name);
|
||||
m_icase = is_item_type_uchar(c, m_item_name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -485,10 +495,10 @@ namespace detail
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_tag << (m_icase ? "^ " : " ") << m_str;
|
||||
os << m_item_name << (m_icase ? "^ " : " ") << m_str;
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
bool m_icase = false;
|
||||
std::function<bool(row_handle, bool)> m_compare;
|
||||
@@ -497,8 +507,8 @@ namespace detail
|
||||
|
||||
struct key_matches_condition_impl : public condition_impl
|
||||
{
|
||||
key_matches_condition_impl(const std::string &item_tag, const std::regex &rx)
|
||||
: m_item_tag(item_tag)
|
||||
key_matches_condition_impl(const std::string &item_name, const std::regex &rx)
|
||||
: m_item_name(item_name)
|
||||
, m_item_ix(0)
|
||||
, mRx(rx)
|
||||
{
|
||||
@@ -506,22 +516,22 @@ namespace detail
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
m_item_ix = get_column_ix(c, m_item_tag);
|
||||
m_item_ix = get_item_ix(c, m_item_name);
|
||||
return this;
|
||||
}
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
std::string_view txt = r[m_item_ix].text();
|
||||
auto txt = r[m_item_ix].get<std::string>();
|
||||
return std::regex_match(txt.begin(), txt.end(), mRx);
|
||||
}
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
os << m_item_tag << " =~ expression";
|
||||
os << m_item_name << " =~ expression";
|
||||
}
|
||||
|
||||
std::string m_item_tag;
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix;
|
||||
std::regex mRx;
|
||||
};
|
||||
@@ -541,7 +551,7 @@ namespace detail
|
||||
auto &c = r.get_category();
|
||||
|
||||
bool result = false;
|
||||
for (auto &f : get_category_fields(c))
|
||||
for (auto &f : get_category_items(c))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -579,11 +589,11 @@ namespace detail
|
||||
auto &c = r.get_category();
|
||||
|
||||
bool result = false;
|
||||
for (auto &f : get_category_fields(c))
|
||||
for (auto &f : get_category_items(c))
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string_view txt = r[f].text();
|
||||
auto txt = r[f].get<std::string>();
|
||||
if (std::regex_match(txt.begin(), txt.end(), mRx))
|
||||
{
|
||||
result = true;
|
||||
@@ -642,28 +652,9 @@ namespace detail
|
||||
delete sub;
|
||||
}
|
||||
|
||||
condition_impl *prepare(const category &c) override
|
||||
{
|
||||
for (auto &sub : m_sub)
|
||||
sub = sub->prepare(c);
|
||||
return this;
|
||||
}
|
||||
condition_impl *prepare(const category &c) override;
|
||||
|
||||
bool test(row_handle r) const override
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
if (sub->test(r))
|
||||
continue;
|
||||
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
bool test(row_handle r) const override;
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
@@ -710,6 +701,7 @@ namespace detail
|
||||
static condition_impl *combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc);
|
||||
|
||||
std::vector<condition_impl *> m_sub;
|
||||
std::optional<row_handle> m_single; // Potential result of index lookup
|
||||
};
|
||||
|
||||
struct or_condition_impl : public condition_impl
|
||||
@@ -864,16 +856,17 @@ inline condition operator or(condition &&a, condition &&b)
|
||||
auto ci = static_cast<detail::key_equals_condition_impl *>(a.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(b.m_impl);
|
||||
|
||||
if (ci->m_item_tag == ce->m_item_tag)
|
||||
if (ci->m_item_name == ce->m_item_name)
|
||||
return condition(new detail::key_equals_or_empty_condition_impl(ci));
|
||||
}
|
||||
else if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and
|
||||
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
|
||||
if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and
|
||||
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
{
|
||||
auto ci = static_cast<detail::key_equals_condition_impl *>(b.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(a.m_impl);
|
||||
|
||||
if (ci->m_item_tag == ce->m_item_tag)
|
||||
if (ci->m_item_name == ce->m_item_name)
|
||||
return condition(new detail::key_equals_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
@@ -887,8 +880,8 @@ inline condition operator or(condition &&a, condition &&b)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A helper class to make it possible to search for empty fields (NULL)
|
||||
*
|
||||
* @brief A helper class to make it possible to search for empty items (NULL)
|
||||
*
|
||||
* @code{.cpp}
|
||||
* "id"_key == cif::empty_type();
|
||||
* @endcode
|
||||
@@ -900,7 +893,7 @@ struct empty_type
|
||||
|
||||
/**
|
||||
* @brief A helper to make it possible to have conditions like
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* "id"_key == cif::null;
|
||||
* @endcode
|
||||
@@ -909,55 +902,59 @@ struct empty_type
|
||||
inline constexpr empty_type null = empty_type();
|
||||
|
||||
/**
|
||||
* @brief Class to use in creating conditions, creates a reference to a field or column
|
||||
*
|
||||
* @brief Class to use in creating conditions, creates a reference to a item or item
|
||||
*
|
||||
*/
|
||||
struct key
|
||||
{
|
||||
/**
|
||||
* @brief Construct a new key object using @a itemTag as name
|
||||
*
|
||||
* @param itemTag
|
||||
* @brief Construct a new key object using @a item_name as name
|
||||
*
|
||||
* @param item_name
|
||||
*/
|
||||
explicit key(const std::string &itemTag)
|
||||
: m_item_tag(itemTag)
|
||||
explicit key(const std::string &item_name)
|
||||
: m_item_name(item_name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new key object using @a itemTag as name
|
||||
*
|
||||
* @param itemTag
|
||||
* @brief Construct a new key object using @a item_name as name
|
||||
*
|
||||
* @param item_name
|
||||
*/
|
||||
explicit key(const char *itemTag)
|
||||
: m_item_tag(itemTag)
|
||||
explicit key(const char *item_name)
|
||||
: m_item_name(item_name)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new key object using @a item_name as name
|
||||
*
|
||||
* @param item_name
|
||||
*/
|
||||
explicit key(std::string_view item_name)
|
||||
: m_item_name(item_name)
|
||||
{
|
||||
}
|
||||
|
||||
key(const key &) = delete;
|
||||
key &operator=(const key &) = delete;
|
||||
|
||||
std::string m_item_tag; ///< The column name
|
||||
std::string m_item_name; ///< The item name
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
condition operator==(const key &key, const T &v)
|
||||
{
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_tag, v }));
|
||||
}
|
||||
concept Numeric = ((std::is_floating_point_v<T> or std::is_integral_v<T>) and not std::is_same_v<T, bool>);
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a value @a value
|
||||
*/
|
||||
inline condition operator==(const key &key, std::string_view value)
|
||||
inline condition operator==(const key &key, item_value value)
|
||||
{
|
||||
if (not value.empty())
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_tag, value }));
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_name, value }));
|
||||
else
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -980,61 +977,93 @@ inline condition operator!=(const key &key, std::string_view value)
|
||||
/**
|
||||
* @brief Operator to create a greater than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator>(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " > " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_tag, [tag = key.m_item_tag, v](row_handle r, bool icase)
|
||||
{ return r[tag].template compare<T>(v, icase) > 0; },
|
||||
s.str()));
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) > 0; },
|
||||
cif::format(" > {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a greater than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator>=(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " >= " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_tag, [tag = key.m_item_tag, v](row_handle r, bool icase)
|
||||
{ return r[tag].template compare<T>(v, icase) >= 0; },
|
||||
s.str()));
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) >= 0; },
|
||||
cif::format(" >= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator<(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " < " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_tag, [tag = key.m_item_tag, v](row_handle r, bool icase)
|
||||
{ return r[tag].template compare<T>(v, icase) < 0; },
|
||||
s.str()));
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) < 0; },
|
||||
cif::format(" < {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
template <Numeric T>
|
||||
condition operator<=(const key &key, const T &v)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << " <= " << v;
|
||||
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_tag, [tag = key.m_item_tag, v](row_handle r, bool icase)
|
||||
{ return r[tag].template compare<T>(v, icase) <= 0; },
|
||||
s.str()));
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) <= 0; },
|
||||
cif::format(" <= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a greater than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator>(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) > 0; },
|
||||
cif::format(" > {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a greater than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator>=(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) >= 0; },
|
||||
cif::format(" >= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator<(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) < 0; },
|
||||
cif::format(" < {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a less than or equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
inline condition operator<=(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) <= 0; },
|
||||
cif::format(" <= {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1042,7 +1071,7 @@ condition operator<=(const key &key, const T &v)
|
||||
*/
|
||||
inline condition operator==(const key &key, const std::regex &rx)
|
||||
{
|
||||
return condition(new detail::key_matches_condition_impl(key.m_item_tag, rx));
|
||||
return condition(new detail::key_matches_condition_impl(key.m_item_name, rx));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1050,7 +1079,7 @@ inline condition operator==(const key &key, const std::regex &rx)
|
||||
*/
|
||||
inline condition operator==(const key &key, const empty_type &)
|
||||
{
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_tag));
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1058,7 +1087,33 @@ inline condition operator==(const key &key, const empty_type &)
|
||||
*/
|
||||
inline condition operator!=(const key &key, const empty_type &)
|
||||
{
|
||||
return condition(new detail::key_is_not_empty_condition_impl(key.m_item_tag));
|
||||
return condition(new detail::key_is_not_empty_condition_impl(key.m_item_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a condition to search any item for a value @a v if @a v contains a value
|
||||
* compare to null if not.
|
||||
*/
|
||||
template <typename T>
|
||||
condition operator==(const key &key, const std::optional<T> &v)
|
||||
{
|
||||
if (v.has_value())
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_name, *v }));
|
||||
else
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a condition to search any item for a value @a v if @a v contains a value
|
||||
* compare to null if not.
|
||||
*/
|
||||
template <typename T>
|
||||
condition operator!=(const key &key, const std::optional<T> &v)
|
||||
{
|
||||
if (v.has_value())
|
||||
return condition(new detail::not_condition_impl(condition(new detail::key_equals_condition_impl({ key.m_item_name, *v }))));
|
||||
else
|
||||
return condition(new detail::not_condition_impl(condition(new detail::key_is_empty_condition_impl(key.m_item_name))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1076,12 +1131,12 @@ struct any_type
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief A helper for any field constructs
|
||||
* @brief A helper for any item constructs
|
||||
*/
|
||||
inline constexpr any_type any = any_type{};
|
||||
|
||||
/**
|
||||
* @brief Create a condition to search any column for a value @a v
|
||||
* @brief Create a condition to search any item for a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
condition operator==(const any_type &, const T &v)
|
||||
@@ -1090,7 +1145,7 @@ condition operator==(const any_type &, const T &v)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a condition to search any column for a regular expression @a rx
|
||||
* @brief Create a condition to search any item for a regular expression @a rx
|
||||
*/
|
||||
inline condition operator==(const any_type &, const std::regex &rx)
|
||||
{
|
||||
@@ -1108,13 +1163,13 @@ inline condition all()
|
||||
namespace literals
|
||||
{
|
||||
/**
|
||||
* @brief Return a cif::key for the column name @a text
|
||||
*
|
||||
* @param text The name of the column
|
||||
* @brief Return a cif::key for the item name @a text
|
||||
*
|
||||
* @param text The name of the item
|
||||
* @param length The length of @a text
|
||||
* @return key The cif::key created
|
||||
*/
|
||||
inline key operator""_key(const char *text, size_t length)
|
||||
inline key operator""_key(const char *text, std::size_t length)
|
||||
{
|
||||
return key(std::string(text, length));
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/forward_decl.hpp"
|
||||
|
||||
#include <list>
|
||||
|
||||
/** \file datablock.hpp
|
||||
* Each valid mmCIF file contains at least one @ref cif::datablock.
|
||||
* A datablock has a name and can contain one or more @ref cif::category "categories"
|
||||
@@ -41,7 +43,7 @@ namespace cif
|
||||
|
||||
/**
|
||||
* @brief A datablock is a list of category objects with some additional features
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class datablock : public std::list<category>
|
||||
@@ -51,7 +53,7 @@ class datablock : public std::list<category>
|
||||
|
||||
/**
|
||||
* @brief Construct a new datablock object with name @a name
|
||||
*
|
||||
*
|
||||
* @param name The name for the new datablock
|
||||
*/
|
||||
datablock(std::string_view name)
|
||||
@@ -61,12 +63,26 @@ class datablock : public std::list<category>
|
||||
|
||||
/** @cond */
|
||||
datablock(const datablock &);
|
||||
datablock(datablock &&) = default;
|
||||
|
||||
datablock &operator=(const datablock &);
|
||||
datablock &operator=(datablock &&) = default;
|
||||
datablock(datablock &&db) noexcept
|
||||
{
|
||||
swap_(*this, db);
|
||||
}
|
||||
|
||||
datablock &operator=(datablock db)
|
||||
{
|
||||
swap_(*this, db);
|
||||
return *this;
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
friend void swap_(datablock &a, datablock &b) noexcept
|
||||
{
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_validator, b.m_validator);
|
||||
std::swap(static_cast<std::list<category> &>(a), static_cast<std::list<category> &>(b));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -76,7 +92,7 @@ class datablock : public std::list<category>
|
||||
|
||||
/**
|
||||
* @brief Set the name of this datablock to @a name
|
||||
*
|
||||
*
|
||||
* @param name The new name
|
||||
*/
|
||||
void set_name(std::string_view name)
|
||||
@@ -84,23 +100,29 @@ class datablock : public std::list<category>
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the dictionary specified in audit_conform category
|
||||
*
|
||||
*/
|
||||
void load_dictionary();
|
||||
|
||||
/**
|
||||
* @brief Set the validator object to @a v
|
||||
*
|
||||
*
|
||||
* @param v The new validator object, may be null
|
||||
*/
|
||||
void set_validator(const validator *v);
|
||||
|
||||
/**
|
||||
* @brief Get the validator object
|
||||
*
|
||||
*
|
||||
* @return const validator* The validator or nullptr if there is none
|
||||
*/
|
||||
const validator *get_validator() const;
|
||||
|
||||
/**
|
||||
* @brief Validates the content of this datablock and all its content
|
||||
*
|
||||
*
|
||||
* @return true If the content is valid
|
||||
* @return false If the content is not valid
|
||||
*/
|
||||
@@ -109,18 +131,26 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Validates all contained data for valid links between parents and children
|
||||
* as defined in the validator
|
||||
*
|
||||
*
|
||||
* @return true If all links are valid
|
||||
* @return false If all links are not valid
|
||||
*/
|
||||
bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Strip removes all categories and items that are invalid according
|
||||
* to the assigned validator. Will also add a valid audit_conform block.
|
||||
*
|
||||
* @return true if the remaining datablock is valid
|
||||
*/
|
||||
bool strip();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Return the category named @a name, will create a new and empty
|
||||
* category named @a name if it does not exist.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category to return
|
||||
* @return category& Reference to the named category
|
||||
*/
|
||||
@@ -129,7 +159,7 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Return the const category named @a name, will return a reference
|
||||
* to a static empty category if it was not found.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category to return
|
||||
* @return category& Reference to the named category
|
||||
*/
|
||||
@@ -138,7 +168,7 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Return a pointer to the category named @a name or nullptr if
|
||||
* it does not exist.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category
|
||||
* @return category* Pointer to the category found or nullptr
|
||||
*/
|
||||
@@ -147,18 +177,26 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Return a pointer to the category named @a name or nullptr if
|
||||
* it does not exist.
|
||||
*
|
||||
*
|
||||
* @param name The name of the category
|
||||
* @return category* Pointer to the category found or nullptr
|
||||
*/
|
||||
const category *get(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* @brief Return true if this datablock contains a non-empty category
|
||||
*/
|
||||
bool contains(std::string_view name) const
|
||||
{
|
||||
return get(name) != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to find a category with name @a name and will create a
|
||||
* new one if it is not found. The result is a tuple of an iterator
|
||||
* pointing to the category and a boolean indicating whether the category
|
||||
* was created or not.
|
||||
*
|
||||
*
|
||||
* @param name The name for the category
|
||||
* @return std::tuple<iterator, bool> A tuple containing an iterator pointing
|
||||
* at the category and a boolean indicating whether the category was newly
|
||||
@@ -169,7 +207,16 @@ class datablock : public std::list<category>
|
||||
/**
|
||||
* @brief Get the preferred order of the categories when writing them
|
||||
*/
|
||||
std::vector<std::string> get_tag_order() const;
|
||||
[[deprecated("use get_item_order instead")]]
|
||||
std::vector<std::string> get_tag_order() const
|
||||
{
|
||||
return get_item_order();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the preferred order of the categories when writing them
|
||||
*/
|
||||
std::vector<std::string> get_item_order() const;
|
||||
|
||||
/**
|
||||
* @brief Write out the contents to @a os
|
||||
@@ -177,9 +224,9 @@ class datablock : public std::list<category>
|
||||
void write(std::ostream &os) const;
|
||||
|
||||
/**
|
||||
* @brief Write out the contents to @a os using the order defined in @a tag_order
|
||||
* @brief Write out the contents to @a os using the order defined in @a item_name_order
|
||||
*/
|
||||
void write(std::ostream &os, const std::vector<std::string> &tag_order);
|
||||
void write(std::ostream &os, const std::vector<std::string> &item_name_order);
|
||||
|
||||
/**
|
||||
* @brief Friend operator<< to write datablock @a db to std::ostream @a os
|
||||
@@ -202,4 +249,4 @@ class datablock : public std::list<category>
|
||||
const validator *m_validator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -38,13 +38,8 @@ namespace cif
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Parse the contents of @a is and create a new validator object with name @a name
|
||||
* @brief Parse the contents of @a is and place content in validator @a v
|
||||
*/
|
||||
validator parse_dictionary(std::string_view name, std::istream &is);
|
||||
|
||||
/**
|
||||
* @brief Extend the definitions in validator @a v with the contents of stream @a is
|
||||
*/
|
||||
void extend_dictionary(validator &v, std::istream &is);
|
||||
void parse_dictionary(validator &v, std::istream &is);
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
|
||||
@@ -86,11 +85,11 @@ class file : public std::list<datablock>
|
||||
* @param data The pointer to the character string with data to load
|
||||
* @param length The length of the data
|
||||
*/
|
||||
explicit file(const char *data, size_t length)
|
||||
explicit file(const char *data, std::size_t length)
|
||||
{
|
||||
struct membuf : public std::streambuf
|
||||
{
|
||||
membuf(char *text, size_t length)
|
||||
membuf(char *text, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
@@ -101,25 +100,24 @@ class file : public std::list<datablock>
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
file(const file &) = default;
|
||||
file(file &&) = default;
|
||||
file &operator=(const file &) = default;
|
||||
file &operator=(file &&) = default;
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Set the validator object to @a v
|
||||
*/
|
||||
void set_validator(const validator *v);
|
||||
|
||||
/**
|
||||
* @brief Get the validator object
|
||||
*/
|
||||
const validator *get_validator() const
|
||||
file(const file &rhs)
|
||||
: std::list<datablock>(rhs)
|
||||
{
|
||||
return m_validator;
|
||||
}
|
||||
|
||||
file(file &&rhs)
|
||||
{
|
||||
this->swap(rhs);
|
||||
}
|
||||
|
||||
file &operator=(file f)
|
||||
{
|
||||
this->swap(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Validate the content and return true if everything was valid.
|
||||
*
|
||||
@@ -154,21 +152,6 @@ class file : public std::list<datablock>
|
||||
*/
|
||||
bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Attempt to load a dictionary (validator) based on
|
||||
* the contents of the *audit_conform* category, if available.
|
||||
*/
|
||||
void load_dictionary();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the named dictionary @a name and
|
||||
* create a validator based on it.
|
||||
*
|
||||
* @param name The name of the dictionary to load
|
||||
*/
|
||||
void load_dictionary(std::string_view name);
|
||||
|
||||
/**
|
||||
* @brief Return true if a datablock with the name @a name is part of this file
|
||||
*/
|
||||
@@ -221,6 +204,12 @@ class file : public std::list<datablock>
|
||||
/** Load the data from @a is */
|
||||
void load(std::istream &is);
|
||||
|
||||
/** Load the data from the file specified by @a p using validator @a v */
|
||||
void load(const std::filesystem::path &p, const validator &v);
|
||||
|
||||
/** Load the data from @a is using validator @a v */
|
||||
void load(std::istream &is, const validator &v);
|
||||
|
||||
/** Save the data to the file specified by @a p */
|
||||
void save(const std::filesystem::path &p) const;
|
||||
|
||||
@@ -235,9 +224,6 @@ class file : public std::list<datablock>
|
||||
f.save(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
const validator *m_validator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,138 +26,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __has_include(<format>)
|
||||
#include <format>
|
||||
#define USE_STD_FORMAT 1
|
||||
#else
|
||||
#include <fmt/format.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
/** \file format.hpp
|
||||
*
|
||||
* File containing a basic reimplementation of boost::format
|
||||
* but then a bit more simplistic. Still this allowed me to move my code
|
||||
* from using boost::format to something without external dependency easily.
|
||||
* Now using cif::format instead of a home grown rip off
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
struct to_varg
|
||||
{
|
||||
using type = T;
|
||||
|
||||
to_varg(const T &v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value; }
|
||||
|
||||
T m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_varg<const char *>
|
||||
{
|
||||
using type = const char *;
|
||||
|
||||
to_varg(const char *v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value.c_str(); }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_varg<std::string>
|
||||
{
|
||||
using type = const char *;
|
||||
|
||||
to_varg(const std::string &v)
|
||||
: m_value(v)
|
||||
{
|
||||
}
|
||||
|
||||
type operator*() { return m_value.c_str(); }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
/** @cond */
|
||||
|
||||
template <typename... Args>
|
||||
class format_plus_arg
|
||||
{
|
||||
public:
|
||||
using args_vector_type = std::tuple<detail::to_varg<Args>...>;
|
||||
using vargs_vector_type = std::tuple<typename detail::to_varg<Args>::type...>;
|
||||
|
||||
format_plus_arg(const format_plus_arg &) = delete;
|
||||
format_plus_arg &operator=(const format_plus_arg &) = delete;
|
||||
|
||||
|
||||
format_plus_arg(std::string_view fmt, Args... args)
|
||||
: m_fmt(fmt)
|
||||
, m_args(std::forward<Args>(args)...)
|
||||
{
|
||||
auto ix = std::make_index_sequence<sizeof...(Args)>();
|
||||
copy_vargs(ix);
|
||||
}
|
||||
|
||||
std::string str()
|
||||
{
|
||||
char buffer[1024];
|
||||
std::string::size_type r = std::apply(snprintf, std::tuple_cat(std::make_tuple(buffer, sizeof(buffer), m_fmt.c_str()), m_vargs));
|
||||
return { buffer, r };
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const format_plus_arg &f)
|
||||
{
|
||||
char buffer[1024];
|
||||
std::string::size_type r = std::apply(snprintf, std::tuple_cat(std::make_tuple(buffer, sizeof(buffer), f.m_fmt.c_str()), f.m_vargs));
|
||||
os.write(buffer, r);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <size_t... I>
|
||||
void copy_vargs(std::index_sequence<I...>)
|
||||
{
|
||||
((std::get<I>(m_vargs) = *std::get<I>(m_args)), ...);
|
||||
}
|
||||
|
||||
std::string m_fmt;
|
||||
args_vector_type m_args;
|
||||
vargs_vector_type m_vargs;
|
||||
};
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief A simplistic reimplementation of boost::format, in fact it is
|
||||
* actually a way to call the C function snprintf to format the arguments
|
||||
* in @a args into the format string @a fmt
|
||||
*
|
||||
* The string in @a fmt should thus be a C style format string.
|
||||
*
|
||||
* TODO: Move to C++23 style of printing.
|
||||
*
|
||||
* @tparam Args The types of the arguments
|
||||
* @param fmt The format string
|
||||
* @param args The arguments
|
||||
* @return An object that can be written out to a std::ostream using operator<<
|
||||
*/
|
||||
|
||||
template <typename... Args>
|
||||
constexpr auto format(std::string_view fmt, Args... args)
|
||||
{
|
||||
return format_plus_arg(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
#if USE_STD_FORMAT
|
||||
using std::format;
|
||||
#else
|
||||
using fmt::format;
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// A streambuf that fills out lines with spaces up until a specified width
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
// Copyright Maarten L. Hekkelman, 2022
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2025 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
Original code comes from libgxrio at https://github.com/mhekkel/gxrio
|
||||
This is a stripped down version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -36,7 +62,7 @@ namespace cif::gzio
|
||||
{
|
||||
|
||||
/** The default buffer size to use */
|
||||
const size_t kDefaultBufferSize = 256;
|
||||
const std::size_t kDefaultBufferSize = 256;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -112,7 +138,7 @@ class basic_streambuf : public std::basic_streambuf<CharT, Traits>
|
||||
/// This implementation of streambuf can decompress (inflate) data compressed
|
||||
/// using zlib.
|
||||
|
||||
template <typename CharT, typename Traits, size_t BufferSize = kDefaultBufferSize>
|
||||
template <typename CharT, typename Traits, std::size_t BufferSize = kDefaultBufferSize>
|
||||
class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
{
|
||||
public:
|
||||
@@ -317,7 +343,7 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
///
|
||||
/// This implementation of streambuf can compress (deflate) data using zlib.
|
||||
|
||||
template <typename CharT, typename Traits, size_t BufferSize = kDefaultBufferSize>
|
||||
template <typename CharT, typename Traits, std::size_t BufferSize = kDefaultBufferSize>
|
||||
class basic_ogzip_streambuf : public basic_streambuf<CharT, Traits>
|
||||
{
|
||||
public:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <array>
|
||||
@@ -49,7 +50,7 @@ namespace cif
|
||||
/**
|
||||
* @brief Implementation of an iterator that can return
|
||||
* multiple values in a tuple. Of course, that tuple can
|
||||
* then used in structured binding to receive the values
|
||||
* then be used in structured binding to receive the values
|
||||
* in a for loop e.g.
|
||||
*
|
||||
* @tparam Category The category for this iterator
|
||||
@@ -67,7 +68,7 @@ class iterator_impl
|
||||
/** @endcond */
|
||||
|
||||
/** variable that contains the number of elements in the tuple */
|
||||
static constexpr size_t N = sizeof...(Ts);
|
||||
static constexpr std::size_t N = sizeof...(Ts);
|
||||
|
||||
/** @cond */
|
||||
using category_type = std::remove_cv_t<Category>;
|
||||
@@ -84,41 +85,38 @@ class iterator_impl
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <typename C2, typename... T2s>
|
||||
iterator_impl(const iterator_impl<C2, T2s...> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_column_ix(rhs.m_column_ix)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(iterator_impl<IRowType, Ts...> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(const_cast<row_type *>(rhs.m_current))
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_column_ix(rhs.m_column_ix)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, N> &cix)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
, m_column_ix(cix)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_item_ix(cix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
iterator_impl &operator=(const iterator_impl &i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
m_category = i.m_category;
|
||||
m_current = i.m_current;
|
||||
m_column_ix = i.m_column_ix;
|
||||
m_value = i.m_value;
|
||||
std::swap(m_current, i.m_current);
|
||||
std::swap(m_item_ix, i.m_item_ix);
|
||||
std::swap(m_value, i.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -136,18 +134,18 @@ class iterator_impl
|
||||
|
||||
operator const row_handle() const
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
m_current = m_current->m_next;
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
|
||||
@@ -179,22 +177,15 @@ class iterator_impl
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
template <size_t... Is>
|
||||
template <std::size_t... Is>
|
||||
tuple_type get(std::index_sequence<Is...>) const
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
{
|
||||
row_handle rh{ *m_category, *m_current };
|
||||
return tuple_type{ rh[m_column_ix[Is]].template as<Ts>()... };
|
||||
}
|
||||
|
||||
return {};
|
||||
return m_current ? tuple_type{ m_current[m_item_ix[Is]].template get<Ts>()... } : tuple_type{};
|
||||
}
|
||||
|
||||
category_type *m_category = nullptr;
|
||||
row_type *m_current = nullptr;
|
||||
row_handle m_current;
|
||||
value_type m_value;
|
||||
std::array<uint16_t, N> m_column_ix;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -219,37 +210,34 @@ class iterator_impl<Category>
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = row_handle;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = row_handle;
|
||||
using reference = row_handle;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <typename C2>
|
||||
iterator_impl(const iterator_impl<C2> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(const_cast<row_type *>(rhs.m_current))
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl(Category &cat, row *current)
|
||||
: m_category(const_cast<category_type *>(&cat))
|
||||
, m_current(current)
|
||||
: m_current(cat, *current)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 0> &)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl &operator=(const iterator_impl &i)
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
m_category = i.m_category;
|
||||
m_current = i.m_current;
|
||||
std::swap(m_current, i.m_current);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -257,7 +245,7 @@ class iterator_impl<Category>
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
@@ -267,18 +255,18 @@ class iterator_impl<Category>
|
||||
|
||||
operator const row_handle() const
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
m_current = m_current->m_next;
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -308,8 +296,7 @@ class iterator_impl<Category>
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
category_type *m_category = nullptr;
|
||||
row_type *m_current = nullptr;
|
||||
row_handle m_current;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -342,41 +329,38 @@ class iterator_impl<Category, T>
|
||||
iterator_impl() = default;
|
||||
|
||||
iterator_impl(const iterator_impl &rhs) = default;
|
||||
iterator_impl(iterator_impl &&rhs) = default;
|
||||
|
||||
template <typename C2, typename T2>
|
||||
iterator_impl(const iterator_impl<C2, T2> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_column_ix(rhs.m_column_ix)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(iterator_impl<IRowType, T> &rhs)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(const_cast<row_type *>(rhs.m_current))
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_value(rhs.m_value)
|
||||
, m_column_ix(rhs.m_column_ix)
|
||||
{
|
||||
m_value = get(m_current);
|
||||
}
|
||||
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 1> &cix)
|
||||
: m_category(rhs.m_category)
|
||||
, m_current(rhs.m_current)
|
||||
, m_column_ix(cix[0])
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
iterator_impl &operator=(const iterator_impl &i)
|
||||
template <typename IRowType>
|
||||
iterator_impl(const iterator_impl<IRowType> &rhs, const std::array<uint16_t, 1> &cix)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
, m_item_ix(cix[0])
|
||||
{
|
||||
m_category = i.m_category;
|
||||
m_current = i.m_current;
|
||||
m_column_ix = i.m_column_ix;
|
||||
m_value = i.m_value;
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
iterator_impl &operator=(iterator_impl i)
|
||||
{
|
||||
std::swap(m_current, i.m_current);
|
||||
std::swap(m_item_ix, i.m_item_ix);
|
||||
std::swap(m_value, i.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -394,18 +378,18 @@ class iterator_impl<Category, T>
|
||||
|
||||
operator const row_handle() const
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle()
|
||||
{
|
||||
return { *m_category, *m_current };
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl &operator++()
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
m_current = m_current->m_next;
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
m_value = get();
|
||||
|
||||
@@ -439,19 +423,12 @@ class iterator_impl<Category, T>
|
||||
private:
|
||||
value_type get() const
|
||||
{
|
||||
if (m_current != nullptr)
|
||||
{
|
||||
row_handle rh{ *m_category, *m_current };
|
||||
return rh[m_column_ix].template as<T>();
|
||||
}
|
||||
|
||||
return {};
|
||||
return m_current ? m_current[m_item_ix].template get<value_type>() : value_type{};
|
||||
}
|
||||
|
||||
category_type *m_category = nullptr;
|
||||
row_type *m_current = nullptr;
|
||||
row_handle m_current;
|
||||
value_type m_value;
|
||||
uint16_t m_column_ix;
|
||||
uint16_t m_item_ix;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -474,7 +451,7 @@ class iterator_proxy
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const size_t N = sizeof...(Ts);
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = Category;
|
||||
using row_type = std::conditional_t<std::is_const_v<category_type>, const row, row>;
|
||||
@@ -482,8 +459,8 @@ class iterator_proxy
|
||||
using iterator = iterator_impl<category_type, Ts...>;
|
||||
using row_iterator = iterator_impl<category_type>;
|
||||
|
||||
iterator_proxy(category_type &cat, row_iterator pos, char const *const columns[N]);
|
||||
iterator_proxy(category_type &cat, row_iterator pos, std::initializer_list<char const *> columns);
|
||||
iterator_proxy(category_type &cat, row_iterator pos, char const *const items[N]);
|
||||
iterator_proxy(category_type &cat, row_iterator pos, std::initializer_list<char const *> items);
|
||||
|
||||
iterator_proxy(iterator_proxy &&p);
|
||||
iterator_proxy &operator=(iterator_proxy &&p);
|
||||
@@ -492,12 +469,12 @@ class iterator_proxy
|
||||
iterator_proxy &operator=(const iterator_proxy &) = delete;
|
||||
/** @endcond */
|
||||
|
||||
iterator begin() const { return iterator(m_begin, m_column_ix); } ///< Return the iterator pointing to the first row
|
||||
iterator end() const { return iterator(m_end, m_column_ix); } ///< Return the iterator pointing past the last row
|
||||
iterator begin() const { return iterator(m_begin, m_item_ix); } ///< Return the iterator pointing to the first row
|
||||
iterator end() const { return iterator(m_end, m_item_ix); } ///< Return the iterator pointing past the last row
|
||||
|
||||
bool empty() const { return m_begin == m_end; } ///< Return true if the range is empty
|
||||
explicit operator bool() const { return not empty(); } ///< Easy way to detect if the range is empty
|
||||
size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
|
||||
// row front() { return *begin(); }
|
||||
// row back() { return *(std::prev(end())); }
|
||||
@@ -510,13 +487,13 @@ class iterator_proxy
|
||||
std::swap(m_category, rhs.m_category);
|
||||
std::swap(m_begin, rhs.m_begin);
|
||||
std::swap(m_end, rhs.m_end);
|
||||
std::swap(m_column_ix, rhs.m_column_ix);
|
||||
std::swap(m_item_ix, rhs.m_item_ix);
|
||||
}
|
||||
|
||||
private:
|
||||
category_type *m_category;
|
||||
row_iterator m_begin, m_end;
|
||||
std::array<uint16_t, N> m_column_ix;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -536,7 +513,7 @@ class conditional_iterator_proxy
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const size_t N = sizeof...(Ts);
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = std::remove_cv_t<CategoryType>;
|
||||
|
||||
@@ -562,22 +539,23 @@ class conditional_iterator_proxy
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return *mBegin;
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
{
|
||||
return &*mBegin;
|
||||
m_current = *m_begin;
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
conditional_iterator_impl &operator++()
|
||||
{
|
||||
while (mBegin != mEnd)
|
||||
while (m_begin != m_end)
|
||||
{
|
||||
if (++mBegin == mEnd)
|
||||
if (++m_begin == m_end)
|
||||
break;
|
||||
|
||||
if (m_condition->operator()(mBegin))
|
||||
if (m_condition->operator()(m_begin))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -591,18 +569,22 @@ class conditional_iterator_proxy
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const conditional_iterator_impl &rhs) const { return mBegin == rhs.mBegin; }
|
||||
bool operator!=(const conditional_iterator_impl &rhs) const { return mBegin != rhs.mBegin; }
|
||||
bool operator==(const conditional_iterator_impl &rhs) const { return m_begin == rhs.m_begin; }
|
||||
bool operator!=(const conditional_iterator_impl &rhs) const { return m_begin != rhs.m_begin; }
|
||||
|
||||
bool operator==(const row_iterator &rhs) const { return m_begin == rhs; }
|
||||
bool operator!=(const row_iterator &rhs) const { return m_begin != rhs; }
|
||||
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin == rhs; }
|
||||
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const { return m_begin == rhs; }
|
||||
|
||||
template <typename IRowType, typename... ITs>
|
||||
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin != rhs; }
|
||||
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return m_begin != rhs; }
|
||||
|
||||
private:
|
||||
CategoryType *mCat;
|
||||
base_iterator mBegin, mEnd;
|
||||
CategoryType *m_cat;
|
||||
base_iterator m_begin, m_end;
|
||||
value_type m_current;
|
||||
const condition *m_condition;
|
||||
};
|
||||
|
||||
@@ -625,7 +607,7 @@ class conditional_iterator_proxy
|
||||
|
||||
bool empty() const; ///< Return true if the range is empty
|
||||
explicit operator bool() const { return not empty(); } ///< Easy way to detect if the range is empty
|
||||
size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
|
||||
row_handle front() { return *begin(); } ///< Return reference to the first row
|
||||
// row_handle back() { return *begin(); }
|
||||
@@ -646,26 +628,26 @@ class conditional_iterator_proxy
|
||||
|
||||
/** @cond */
|
||||
template <typename Category, typename... Ts>
|
||||
iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, char const *const columns[N])
|
||||
iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, char const *const items[N])
|
||||
: m_category(&cat)
|
||||
, m_begin(pos)
|
||||
, m_end(cat.end())
|
||||
{
|
||||
for (uint16_t i = 0; i < N; ++i)
|
||||
m_column_ix[i] = m_category->get_column_ix(columns[i]);
|
||||
m_item_ix[i] = m_category->get_item_ix(items[i]);
|
||||
}
|
||||
|
||||
template <typename Category, typename... Ts>
|
||||
iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, std::initializer_list<char const *> columns)
|
||||
iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, std::initializer_list<char const *> items)
|
||||
: m_category(&cat)
|
||||
, m_begin(pos)
|
||||
, m_end(cat.end())
|
||||
{
|
||||
// static_assert(columns.size() == N, "The list of column names should be exactly the same as the list of requested columns");
|
||||
// static_assert(items.size() == N, "The list of item names should be exactly the same as the list of requested items");
|
||||
|
||||
std::uint16_t i = 0;
|
||||
for (auto column : columns)
|
||||
m_column_ix[i++] = m_category->get_column_ix(column);
|
||||
for (auto item : items)
|
||||
m_item_ix[i++] = m_category->get_item_ix(item);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -673,13 +655,13 @@ iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos,
|
||||
template <typename Category, typename... Ts>
|
||||
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
|
||||
Category &cat, row_iterator pos, const condition &cond, const std::array<uint16_t, N> &cix)
|
||||
: mCat(&cat)
|
||||
, mBegin(pos, cix)
|
||||
, mEnd(cat.end(), cix)
|
||||
: m_cat(&cat)
|
||||
, m_begin(pos, cix)
|
||||
, m_end(cat.end(), cix)
|
||||
, m_condition(&cond)
|
||||
{
|
||||
if (m_condition == nullptr or m_condition->empty())
|
||||
mBegin = mEnd;
|
||||
m_begin = m_end;
|
||||
}
|
||||
|
||||
template <typename Category, typename... Ts>
|
||||
@@ -702,7 +684,7 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
|
||||
, mCBegin(pos)
|
||||
, mCEnd(cat.end())
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "Number of column names should be equal to number of requested value types");
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "Number of item names should be equal to number of requested value types");
|
||||
|
||||
if (m_condition)
|
||||
{
|
||||
@@ -712,10 +694,10 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
|
||||
++mCBegin;
|
||||
}
|
||||
else
|
||||
mCBegin == mCEnd;
|
||||
mCBegin = mCEnd;
|
||||
|
||||
uint16_t i = 0;
|
||||
((mCix[i++] = m_cat->get_column_ix(names)), ...);
|
||||
((mCix[i++] = m_cat->get_item_ix(names)), ...);
|
||||
}
|
||||
|
||||
template <typename Category, typename... Ts>
|
||||
|
||||
@@ -59,27 +59,27 @@ template <typename M>
|
||||
class matrix_expression
|
||||
{
|
||||
public:
|
||||
constexpr size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); } ///< Return the size (dimension) in direction m
|
||||
constexpr size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); } ///< Return the size (dimension) in direction n
|
||||
constexpr std::size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); } ///< Return the size (dimension) in direction m
|
||||
constexpr std::size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); } ///< Return the size (dimension) in direction n
|
||||
|
||||
constexpr bool empty() const { return dim_m() == 0 or dim_n() == 0; } ///< Convenient way to test for empty matrices
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr auto &operator()(size_t i, size_t j)
|
||||
constexpr auto &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
return static_cast<M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<const M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
/** Swap the contents of rows @a r1 and @a r2 */
|
||||
void swap_row(size_t r1, size_t r2)
|
||||
void swap_row(std::size_t r1, std::size_t r2)
|
||||
{
|
||||
for (size_t c = 0; c < dim_m(); ++c)
|
||||
for (std::size_t c = 0; c < dim_m(); ++c)
|
||||
{
|
||||
auto v = operator()(r1, c);
|
||||
operator()(r1, c) = operator()(r2, c);
|
||||
@@ -88,9 +88,9 @@ class matrix_expression
|
||||
}
|
||||
|
||||
/** Swap the contents of columns @a c1 and @a c2 */
|
||||
void swap_col(size_t c1, size_t c2)
|
||||
void swap_col(std::size_t c1, std::size_t c2)
|
||||
{
|
||||
for (size_t r = 0; r < dim_n(); ++r)
|
||||
for (std::size_t r = 0; r < dim_n(); ++r)
|
||||
{
|
||||
auto &a = operator()(r, c1);
|
||||
auto &b = operator()(r, c2);
|
||||
@@ -103,11 +103,11 @@ class matrix_expression
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (size_t i = 0; i < m.dim_m(); ++i)
|
||||
for (std::size_t i = 0; i < m.dim_m(); ++i)
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (size_t j = 0; j < m.dim_n(); ++j)
|
||||
for (std::size_t j = 0; j < m.dim_n(); ++j)
|
||||
{
|
||||
os << m(i, j);
|
||||
if (j + 1 < m.dim_n())
|
||||
@@ -124,6 +124,23 @@ class matrix_expression
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename M2>
|
||||
constexpr bool operator==(const matrix_expression<M2> &m) const
|
||||
{
|
||||
bool same = false;
|
||||
if (dim_m() == m.dim_m() and dim_n() == m.dim_n())
|
||||
{
|
||||
same = true;
|
||||
for (std::size_t i = 0; same and i < m.dim_m(); ++i)
|
||||
{
|
||||
for (std::size_t j = 0; same and j < m.dim_n(); ++j)
|
||||
same = operator()(i, j) == m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return same;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -156,9 +173,9 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
, m_n(m.dim_n())
|
||||
, m_data(m_m * m_n)
|
||||
{
|
||||
for (size_t i = 0; i < m_m; ++i)
|
||||
for (std::size_t i = 0; i < m_m; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < m_n; ++j)
|
||||
for (std::size_t j = 0; j < m_n; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
@@ -171,7 +188,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
* @param n Requested dimension N
|
||||
* @param v Value to store in each element
|
||||
*/
|
||||
matrix(size_t m, size_t n, value_type v = 0)
|
||||
matrix(std::size_t m, std::size_t n, value_type v = 0)
|
||||
: m_m(m)
|
||||
, m_n(n)
|
||||
, m_data(m_m * m_n)
|
||||
@@ -187,11 +204,11 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
matrix &operator=(const matrix &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
constexpr size_t dim_m() const { return m_m; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
@@ -199,7 +216,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
@@ -207,7 +224,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_m = 0, m_n = 0;
|
||||
std::size_t m_m = 0, m_n = 0;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
@@ -224,7 +241,7 @@ class matrix : public matrix_expression<matrix<F>>
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
|
||||
template <typename F, size_t M, size_t N>
|
||||
template <typename F, std::size_t M, std::size_t N>
|
||||
class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
{
|
||||
public:
|
||||
@@ -232,16 +249,16 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
using value_type = F;
|
||||
|
||||
/** The storage size */
|
||||
static constexpr size_t kSize = M * N;
|
||||
static constexpr std::size_t kSize = M * N;
|
||||
|
||||
/** Copy constructor */
|
||||
template <typename M2>
|
||||
matrix_fixed(const M2 &m)
|
||||
{
|
||||
assert(M == m.dim_m() and N == m.dim_n());
|
||||
for (size_t i = 0; i < M; ++i)
|
||||
for (std::size_t i = 0; i < M; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < N; ++j)
|
||||
for (std::size_t j = 0; j < N; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
@@ -266,18 +283,18 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
/** @endcond */
|
||||
|
||||
/** Store the values in @a a in the matrix */
|
||||
template<size_t... Ixs>
|
||||
template<std::size_t... Ixs>
|
||||
matrix_fixed& fill(const F (&a)[kSize], std::index_sequence<Ixs...>)
|
||||
{
|
||||
m_data = { a[Ixs]... };
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return N; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return N; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
@@ -285,7 +302,7 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
@@ -322,7 +339,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
using value_type = F;
|
||||
|
||||
/** constructor for a matrix of size @a n x @a n elements with value @a v */
|
||||
symmetric_matrix(size_t n, value_type v = 0)
|
||||
symmetric_matrix(std::size_t n, value_type v = 0)
|
||||
: m_n(n)
|
||||
, m_data((m_n * (m_n + 1)) / 2)
|
||||
{
|
||||
@@ -337,11 +354,11 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
symmetric_matrix &operator=(const symmetric_matrix &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
constexpr size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
@@ -349,7 +366,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
@@ -358,7 +375,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_n;
|
||||
std::size_t m_n;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
@@ -373,7 +390,7 @@ class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
|
||||
* matrix is m x n, addressing i,j is 0 <= i < m and 0 <= j < n
|
||||
* element m i,j is mapped to [i * n + j] and thus storage is row major
|
||||
*/
|
||||
template <typename F, size_t M>
|
||||
template <typename F, std::size_t M>
|
||||
class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F, M>>
|
||||
{
|
||||
public:
|
||||
@@ -393,11 +410,11 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
|
||||
symmetric_matrix_fixed &operator=(const symmetric_matrix_fixed &m) = default;
|
||||
/** @endcond */
|
||||
|
||||
constexpr size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return M; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return M; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return i < j
|
||||
? m_data[(j * (j + 1)) / 2 + i]
|
||||
@@ -405,7 +422,7 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
constexpr value_type &operator()(size_t i, size_t j)
|
||||
constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
@@ -444,22 +461,22 @@ class identity_matrix : public matrix_expression<identity_matrix<F>>
|
||||
using value_type = F;
|
||||
|
||||
/** constructor taking a dimension @a n */
|
||||
identity_matrix(size_t n)
|
||||
identity_matrix(std::size_t n)
|
||||
: m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
constexpr value_type operator()(size_t i, size_t j) const
|
||||
constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<value_type>(i == j ? 1 : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_n;
|
||||
std::size_t m_n;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -484,11 +501,11 @@ class matrix_subtraction : public matrix_expression<matrix_subtraction<M1, M2>>
|
||||
assert(m_m1.dim_n() == m_m2.dim_n());
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m1(i, j) - m_m2(i, j);
|
||||
}
|
||||
@@ -523,17 +540,17 @@ class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_mult
|
||||
assert(m1.dim_m() == m2.dim_n());
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
using value_type = decltype(m_m1(0, 0));
|
||||
|
||||
value_type result = {};
|
||||
|
||||
for (size_t k = 0; k < m_m1.dim_m(); ++k)
|
||||
for (std::size_t k = 0; k < m_m1.dim_m(); ++k)
|
||||
result += m_m1(i, k) * m_m2(k, j);
|
||||
|
||||
return result;
|
||||
@@ -564,11 +581,11 @@ class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_mult
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(i, j) * m_v;
|
||||
}
|
||||
@@ -594,6 +611,35 @@ auto operator*(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename M2>
|
||||
class sub_matrix : public matrix_expression<sub_matrix<M2>>
|
||||
{
|
||||
public:
|
||||
sub_matrix(const M2 &m, int i, int j)
|
||||
: m_m(m)
|
||||
, m_i(i)
|
||||
, m_j(j)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr std::size_t dim_m() const { return m_m.dim_m() - 1; } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m.dim_n() - 1; } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(
|
||||
i >= m_i ? i + 1 : i,
|
||||
j >= m_j ? j + 1 : j);
|
||||
}
|
||||
|
||||
private:
|
||||
const M2 &m_m;
|
||||
std::size_t m_i, m_j;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Generic routine to calculate the determinant of a matrix
|
||||
*
|
||||
* @note This is currently only implemented for fixed matrices of size 3x3
|
||||
@@ -605,11 +651,23 @@ auto determinant(const M &m);
|
||||
template <typename F = float>
|
||||
auto determinant(const matrix3x3<F> &m)
|
||||
{
|
||||
return (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
|
||||
m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
|
||||
m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
|
||||
return (m(0, 0) * ((m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1))) +
|
||||
m(0, 1) * ((m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2))) +
|
||||
m(0, 2) * ((m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))));
|
||||
}
|
||||
|
||||
/** Implementation of the determinant function for fixed size matrices of size 4x4 */
|
||||
template <typename F = float>
|
||||
F determinant(const matrix4x4<F> &m)
|
||||
{
|
||||
return m(0, 0) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 0))) -
|
||||
m(0, 1) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 1))) +
|
||||
m(0, 2) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 2))) -
|
||||
m(0, 3) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 3)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Generic routine to calculate the inverse of a matrix
|
||||
*
|
||||
* @note This is currently only implemented for fixed matrices of size 3x3
|
||||
@@ -655,21 +713,21 @@ class matrix_cofactors : public matrix_expression<matrix_cofactors<M>>
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
constexpr auto operator()(size_t i, size_t j) const
|
||||
constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
const size_t ixs[4][3] = {
|
||||
const std::size_t ixs[4][3] = {
|
||||
{ 1, 2, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 1, 2 }
|
||||
};
|
||||
|
||||
const size_t *ix = ixs[i];
|
||||
const size_t *iy = ixs[j];
|
||||
const std::size_t *ix = ixs[i];
|
||||
const std::size_t *iy = ixs[j];
|
||||
|
||||
auto result =
|
||||
m_m(ix[0], iy[0]) * m_m(ix[1], iy[1]) * m_m(ix[2], iy[2]) +
|
||||
|
||||
@@ -29,12 +29,13 @@
|
||||
#include "cif++/atom_type.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
||||
#if __cpp_lib_format
|
||||
#include <format>
|
||||
# include <format>
|
||||
#endif
|
||||
|
||||
/** @file model.hpp
|
||||
@@ -72,7 +73,7 @@ class structure;
|
||||
*
|
||||
* The class atom is a kind of flyweight class. It can be copied
|
||||
* with low overhead. All data is stored in the underlying mmCIF
|
||||
* categories but some very often used fields are cached in the
|
||||
* categories but some very often used items are cached in the
|
||||
* impl.
|
||||
*
|
||||
* It is also possible to have symmetry copies of atoms. They
|
||||
@@ -106,8 +107,6 @@ class atom
|
||||
|
||||
atom_impl(const atom_impl &i) = default;
|
||||
|
||||
void prefetch();
|
||||
|
||||
int compare(const atom_impl &b) const;
|
||||
|
||||
// bool getAnisoU(float anisou[6]) const;
|
||||
@@ -136,14 +135,20 @@ class atom
|
||||
|
||||
row_handle row_aniso()
|
||||
{
|
||||
row_handle result{};
|
||||
auto cat = m_db.get("atom_site_anisotrop");
|
||||
return cat ? cat->operator[]({ { "id", m_id } }) : row_handle{};
|
||||
if (cat)
|
||||
result = cat->operator[]({ { "id", m_id } });
|
||||
return result;
|
||||
}
|
||||
|
||||
const row_handle row_aniso() const
|
||||
{
|
||||
row_handle result{};
|
||||
auto cat = m_db.get("atom_site_anisotrop");
|
||||
return cat ? cat->operator[]({ { "id", m_id } }) : row_handle{};
|
||||
if (cat)
|
||||
result = cat->operator[]({ { "id", m_id } });
|
||||
return result;
|
||||
}
|
||||
|
||||
const datablock &m_db;
|
||||
@@ -185,7 +190,7 @@ class atom
|
||||
* @param row The row containing the data for this atom
|
||||
*/
|
||||
atom(const datablock &db, const row_handle &row)
|
||||
: atom(std::make_shared<atom_impl>(db, row["id"].as<std::string>()))
|
||||
: atom(std::make_shared<atom_impl>(db, row["id"].get<std::string>()))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -207,7 +212,7 @@ class atom
|
||||
/// \brief Copy assignement operator
|
||||
atom &operator=(const atom &rhs) = default;
|
||||
|
||||
/// \brief Return the field named @a name in the _atom_site category for this atom
|
||||
/// \brief Return the item named @a name in the _atom_site category for this atom
|
||||
std::string get_property(std::string_view name) const
|
||||
{
|
||||
if (not m_impl)
|
||||
@@ -215,7 +220,7 @@ class atom
|
||||
return m_impl->get_property(name);
|
||||
}
|
||||
|
||||
/// \brief Return the field named @a name in the _atom_site category for this atom cast to an int
|
||||
/// \brief Return the item named @a name in the _atom_site category for this atom cast to an int
|
||||
int get_property_int(std::string_view name) const
|
||||
{
|
||||
if (not m_impl)
|
||||
@@ -223,7 +228,7 @@ class atom
|
||||
return m_impl->get_property_int(name);
|
||||
}
|
||||
|
||||
/// \brief Return the field named @a name in the _atom_site category for this atom cast to a float
|
||||
/// \brief Return the item named @a name in the _atom_site category for this atom cast to a float
|
||||
float get_property_float(std::string_view name) const
|
||||
{
|
||||
if (not m_impl)
|
||||
@@ -231,7 +236,7 @@ class atom
|
||||
return m_impl->get_property_float(name);
|
||||
}
|
||||
|
||||
/// \brief Set value for the field named @a name in the _atom_site category to @a value
|
||||
/// \brief Set value for the item named @a name in the _atom_site category to @a value
|
||||
void set_property(const std::string_view name, const std::string &value)
|
||||
{
|
||||
if (not m_impl)
|
||||
@@ -239,7 +244,7 @@ class atom
|
||||
m_impl->set_property(name, value);
|
||||
}
|
||||
|
||||
/// \brief Set value for the field named @a name in the _atom_site category to @a value
|
||||
/// \brief Set value for the item named @a name in the _atom_site category to @a value
|
||||
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
|
||||
void set_property(const std::string_view name, const T &value)
|
||||
{
|
||||
@@ -345,12 +350,17 @@ class atom
|
||||
std::string get_auth_asym_id() const { return get_property("auth_asym_id"); } ///< Return the auth_asym_id property
|
||||
std::string get_auth_seq_id() const { return get_property("auth_seq_id"); } ///< Return the auth_seq_id property
|
||||
std::string get_auth_atom_id() const { return get_property("auth_atom_id"); } ///< Return the auth_atom_id property
|
||||
std::string get_auth_alt_id() const { return get_property("auth_alt_id"); } ///< Return the auth_alt_id property
|
||||
std::string get_auth_alt_id() const { return get_property("pdbx_auth_alt_id"); } ///< Return the auth_alt_id property
|
||||
std::string get_auth_comp_id() const { return get_property("auth_comp_id"); } ///< Return the auth_comp_id property
|
||||
std::string get_pdb_ins_code() const { return get_property("pdbx_PDB_ins_code"); } ///< Return the pdb_ins_code property
|
||||
|
||||
/// Return true if this atom is an alternate
|
||||
bool is_alternate() const { return not get_label_alt_id().empty(); }
|
||||
bool is_alternate() const
|
||||
{
|
||||
if (auto alt_id = get_label_alt_id(); alt_id.empty() or alt_id == ".")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Convenience method to return a string that might be ID in PDB space
|
||||
std::string pdb_id() const
|
||||
@@ -476,8 +486,8 @@ class residue
|
||||
, m_compound_id(compoundID)
|
||||
, m_asym_id(asymID)
|
||||
, m_seq_id(seqID)
|
||||
, m_auth_asym_id(authAsymID)
|
||||
, m_auth_seq_id(authSeqID)
|
||||
, m_pdb_strand_id(authAsymID)
|
||||
, m_pdb_seq_num(authSeqID)
|
||||
, m_pdb_ins_code(pdbInsCode)
|
||||
{
|
||||
}
|
||||
@@ -504,9 +514,9 @@ class residue
|
||||
const std::string &get_asym_id() const { return m_asym_id; } ///< Return the asym_id
|
||||
int get_seq_id() const { return m_seq_id; } ///< Return the seq_id
|
||||
|
||||
const std::string get_auth_asym_id() const { return m_auth_asym_id; } ///< Return the auth_asym_id
|
||||
const std::string get_auth_seq_id() const { return m_auth_seq_id; } ///< Return the auth_seq_id
|
||||
std::string get_pdb_ins_code() const { return m_pdb_ins_code; } ///< Return the pdb_ins_code
|
||||
const std::string get_pdb_strand_id() const { return m_pdb_strand_id; } ///< Return the pdb_strand_id
|
||||
const std::string get_pdb_seq_num() const { return m_pdb_seq_num; } ///< Return the pdb_seq_num
|
||||
std::string get_pdb_ins_code() const { return m_pdb_ins_code; } ///< Return the pdb_ins_code
|
||||
|
||||
const std::string &get_compound_id() const { return m_compound_id; } ///< Return the compound_id
|
||||
void set_compound_id(const std::string &id) { m_compound_id = id; } ///< Set the compound_id to @a id
|
||||
@@ -535,6 +545,9 @@ class residue
|
||||
/// \brief Return the atom with atom_id @a atomID
|
||||
atom get_atom_by_atom_id(const std::string &atomID) const;
|
||||
|
||||
/// \brief Return the atom with atom_id @a atomID and alternate_id @a altID
|
||||
atom get_atom_by_atom_id(const std::string &atomID, const std::string &altID) const;
|
||||
|
||||
/// \brief Return the list of atoms having ID \a atomID
|
||||
///
|
||||
/// This includes all alternate atoms with this ID
|
||||
@@ -550,6 +563,9 @@ class residue
|
||||
/// \brief Return true if this residue has alternate atoms
|
||||
bool has_alternate_atoms() const;
|
||||
|
||||
/// \brief Return true if this residue has alternate atoms for the atom \a atomID
|
||||
bool has_alternate_atoms_for(const std::string &atomID) const;
|
||||
|
||||
/// \brief Return the list of unique alt ID's present in this residue
|
||||
std::set<std::string> get_alternate_ids() const;
|
||||
|
||||
@@ -569,9 +585,13 @@ class residue
|
||||
m_seq_id == rhs.m_seq_id and
|
||||
m_asym_id == rhs.m_asym_id and
|
||||
m_compound_id == rhs.m_compound_id and
|
||||
m_auth_seq_id == rhs.m_auth_seq_id);
|
||||
m_pdb_seq_num == rhs.m_pdb_seq_num);
|
||||
}
|
||||
|
||||
/// @brief Create a new atom and add it to the list
|
||||
/// @return newly created atom
|
||||
virtual atom create_new_atom(atom_type inType, const std::string &inAtomID, point inLocation);
|
||||
|
||||
protected:
|
||||
/** @cond */
|
||||
residue() {}
|
||||
@@ -579,7 +599,7 @@ class residue
|
||||
structure *m_structure = nullptr;
|
||||
std::string m_compound_id, m_asym_id;
|
||||
int m_seq_id = 0;
|
||||
std::string m_auth_asym_id, m_auth_seq_id, m_pdb_ins_code;
|
||||
std::string m_pdb_strand_id, m_pdb_seq_num, m_pdb_ins_code;
|
||||
std::vector<atom> m_atoms;
|
||||
/** @endcond */
|
||||
};
|
||||
@@ -604,12 +624,15 @@ class monomer : public residue
|
||||
monomer &operator=(monomer &&rhs);
|
||||
|
||||
/// \brief constructor with actual values
|
||||
monomer(const polymer &polymer, size_t index, int seqID, const std::string &authSeqID,
|
||||
monomer(const polymer &polymer, std::size_t index, int seqID, const std::string &authSeqID,
|
||||
const std::string &pdbInsCode, const std::string &compoundID);
|
||||
|
||||
bool is_first_in_chain() const; ///< Return if this residue is the first residue in the chain
|
||||
bool is_last_in_chain() const; ///< Return if this residue is the last residue in the chain
|
||||
|
||||
const monomer &prev() const; // Return previous monomer in polymer
|
||||
const monomer &next() const; // Return next monomer in polymer
|
||||
|
||||
// convenience
|
||||
bool has_alpha() const; ///< Return if a alpha value can be calculated (depends on location in chain)
|
||||
bool has_kappa() const; ///< Return if a kappa value can be calculated (depends on location in chain)
|
||||
@@ -624,8 +647,8 @@ class monomer : public residue
|
||||
float omega() const; ///< Return the omega value for this residue
|
||||
|
||||
// torsion angles
|
||||
size_t nr_of_chis() const; ///< Return how many torsion angles can be calculated
|
||||
float chi(size_t i) const; ///< Return torsion angle @a i
|
||||
std::size_t nr_of_chis() const; ///< Return how many torsion angles can be calculated
|
||||
float chi(std::size_t i) const; ///< Return torsion angle @a i
|
||||
|
||||
bool is_cis() const; ///< Return true if this residue is in a cis conformation
|
||||
|
||||
@@ -672,9 +695,11 @@ class monomer : public residue
|
||||
return m_polymer == rhs.m_polymer and m_index == rhs.m_index;
|
||||
}
|
||||
|
||||
atom create_new_atom(atom_type inType, const std::string &inAtomID, point inLocation) override;
|
||||
|
||||
private:
|
||||
const polymer *m_polymer;
|
||||
size_t m_index;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -694,15 +719,15 @@ class polymer : public std::vector<monomer>
|
||||
|
||||
structure *get_structure() const { return m_structure; } ///< Return the structure
|
||||
|
||||
std::string get_asym_id() const { return m_asym_id; } ///< Return the asym_id
|
||||
std::string get_auth_asym_id() const { return m_auth_asym_id; } ///< Return the PDB chain ID, actually
|
||||
std::string get_entity_id() const { return m_entity_id; } ///< Return the entity_id
|
||||
std::string get_asym_id() const { return m_asym_id; } ///< Return the asym_id
|
||||
std::string get_pdb_strand_id() const { return m_pdb_strand_id; } ///< Return the PDB chain ID, actually
|
||||
std::string get_entity_id() const { return m_entity_id; } ///< Return the entity_id
|
||||
|
||||
private:
|
||||
structure *m_structure;
|
||||
std::string m_entity_id;
|
||||
std::string m_asym_id;
|
||||
std::string m_auth_asym_id;
|
||||
std::string m_pdb_strand_id;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -730,7 +755,7 @@ class sugar : public residue
|
||||
/**
|
||||
* @brief Return the sugar number in the glycosylation tree
|
||||
*
|
||||
* To store the sugar number, the auth_seq_id field has been overloaded
|
||||
* To store the sugar number, the auth_seq_id item has been overloaded
|
||||
* in the specification. But since a sugar number should be, ehm, a number
|
||||
* and auth_seq_id is specified to contain a string, we do a check here
|
||||
* to see if it really is a number.
|
||||
@@ -740,8 +765,8 @@ class sugar : public residue
|
||||
int num() const
|
||||
{
|
||||
int result;
|
||||
auto r = std::from_chars(m_auth_seq_id.data(), m_auth_seq_id.data() + m_auth_seq_id.length(), result);
|
||||
if (r.ec != std::errc())
|
||||
auto r = std::from_chars(m_pdb_seq_num.data(), m_pdb_seq_num.data() + m_pdb_seq_num.length(), result);
|
||||
if ((bool)r.ec)
|
||||
throw std::runtime_error("The auth_seq_id should be a number for a sugar");
|
||||
return result;
|
||||
}
|
||||
@@ -756,9 +781,9 @@ class sugar : public residue
|
||||
void set_link(atom link) { m_link = link; }
|
||||
|
||||
/// \brief Return the sugar number of the sugar linked to C1
|
||||
size_t get_link_nr() const
|
||||
std::size_t get_link_nr() const
|
||||
{
|
||||
size_t result = 0;
|
||||
std::size_t result = 0;
|
||||
if (m_link)
|
||||
result = m_link.get_property_int("auth_seq_id");
|
||||
return result;
|
||||
@@ -839,19 +864,38 @@ class branch : public std::vector<sugar>
|
||||
std::string m_asym_id, m_entity_id;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief A still very limited set of options for reading structures
|
||||
enum class StructureOpenOptions
|
||||
/** @brief Enumeration for controlling atom selection based on occupancy. */
|
||||
enum class occupancy_policy
|
||||
{
|
||||
SkipHydrogen = 1 << 0 ///< Do not include hydrogen atoms in the structure object
|
||||
/** @brief Include all atoms regardless of their occupancy factor. */
|
||||
ALL = 0,
|
||||
|
||||
/** @brief Select only alternate atoms with the maximum occupancy factor.
|
||||
* If multiple atoms have the same maximum occupancy, choose the one with the minimum B-factor.
|
||||
* If multiple atoms share both the maximum occupancy and the minimum B-factor, select the first encountered atom.
|
||||
*/
|
||||
MAX = 1,
|
||||
|
||||
/** @brief Select only alternate atoms with the minimum occupancy factor.
|
||||
* Similar to MAX, if multiple atoms have the same minimum occupancy, choose the one with the minimum B-factor.
|
||||
* If multiple atoms share both the minimum occupancy and the minimum B-factor, select the first encountered atom.
|
||||
*/
|
||||
MIN = 2,
|
||||
|
||||
/** @brief Exclude all atoms with an occupancy factor greater than zero. */
|
||||
UNOCCUPIED = 3
|
||||
};
|
||||
|
||||
/// \brief A way to combine two options. Not very useful as there is only one...
|
||||
constexpr inline bool operator&(StructureOpenOptions a, StructureOpenOptions b)
|
||||
struct structure_open_options
|
||||
{
|
||||
return static_cast<int>(a) bitand static_cast<int>(b);
|
||||
}
|
||||
bool skip_hydrogen = false; ///< Do not include hydrogen atoms in the structure object
|
||||
bool skip_hetatom = false; ///< Do not include HET atoms in the structure object
|
||||
bool skip_water = false; ///< Do not include water atoms in the structure object
|
||||
occupancy_policy occupancy_mode = occupancy_policy::ALL; ///< By default, the occupancy policy is set to occupancy_policy::ALL
|
||||
std::vector<std::string> asyms; ///< The asyms to load, if empty load all
|
||||
std::optional<float> min_b_factor; ///< Only load atoms with at least this b_factor
|
||||
std::optional<float> max_b_factor; ///< Only load atoms with at most this b_factor
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -865,10 +909,10 @@ class structure
|
||||
{
|
||||
public:
|
||||
/// \brief Read the structure from cif::file @a p
|
||||
structure(file &p, size_t modelNr = 1, StructureOpenOptions options = {});
|
||||
structure(file &p, std::size_t modelNr = 1, structure_open_options options = {});
|
||||
|
||||
/// \brief Load the structure from already parsed mmCIF data in @a db
|
||||
structure(datablock &db, size_t modelNr = 1, StructureOpenOptions options = {});
|
||||
structure(datablock &db, std::size_t modelNr = 1, structure_open_options options = {});
|
||||
|
||||
/** @cond */
|
||||
structure(structure &&s) = default;
|
||||
@@ -881,7 +925,7 @@ class structure
|
||||
~structure() = default;
|
||||
|
||||
/// \brief Return the model number
|
||||
size_t get_model_nr() const { return m_model_nr; }
|
||||
std::size_t get_model_nr() const { return m_model_nr; }
|
||||
|
||||
/// \brief Return a list of all the atoms in this structure
|
||||
const std::vector<atom> &atoms() const { return m_atoms; }
|
||||
@@ -978,18 +1022,18 @@ class structure
|
||||
/**
|
||||
* @brief Change residue @a res to a new compound ID optionally
|
||||
* remapping atoms.
|
||||
*
|
||||
*
|
||||
* A new chem_comp entry as well as an entity is created if needed and
|
||||
* if the list of @a remappedAtoms is not empty it is used to remap.
|
||||
*
|
||||
*
|
||||
* The array in @a remappedAtoms contains tuples of strings, both
|
||||
* strings contain an atom_id. The first is the one in the current
|
||||
* residue and the second is the atom_id that should be used instead.
|
||||
* If the second string is empty, the atom is removed from the residue.
|
||||
*
|
||||
* @param res
|
||||
* @param newcompound
|
||||
* @param remappedAtoms
|
||||
*
|
||||
* @param res
|
||||
* @param newcompound
|
||||
* @param remappedAtoms
|
||||
*/
|
||||
void change_residue(residue &res, const std::string &newcompound,
|
||||
const std::vector<std::tuple<std::string, std::string>> &remappedAtoms);
|
||||
@@ -1022,26 +1066,44 @@ class structure
|
||||
/// \return The newly create asym ID
|
||||
std::string create_non_poly(const std::string &entity_id, std::vector<row_initializer> atoms);
|
||||
|
||||
/// \brief Create a new NonPolymer struct_asym for a compound of type \a compound_id, returns asym_id.
|
||||
/// This method creates new atom records filled with info from the CCD compound info.
|
||||
///
|
||||
/// \param compound_id The compound ID of the new nonpoly
|
||||
/// \param skip_hydrogen Do not create hydrogen atoms when true
|
||||
/// \return The newly create asym ID
|
||||
std::string create_non_poly(const std::string &compound_id, bool skip_hydrogen);
|
||||
|
||||
/// \brief Create a new water with atom constructed from info in \a atom_info
|
||||
/// This method creates a new atom record filled with info from the info.
|
||||
///
|
||||
/// \param atom The set of item data containing the data for the atoms.
|
||||
void create_water(row_initializer atom);
|
||||
|
||||
/// \brief Create a link, a struct_conn record for two atoms.
|
||||
///
|
||||
/// \param a1 Atom 1
|
||||
/// \param a2 Atom 2
|
||||
/// \param link_type The struct_conn_type ID for the link
|
||||
/// \param role The pdbx_role field value
|
||||
/// \return The ID of the struct_conn record created
|
||||
|
||||
std::string create_link(atom a1, atom a2, const std::string &link_type, const std::string &role);
|
||||
|
||||
/// \brief Create a new and empty (sugar) branch
|
||||
branch &create_branch();
|
||||
|
||||
/// \brief Create a new (sugar) branch with one first NAG containing atoms constructed from \a atoms
|
||||
branch &create_branch(std::vector<row_initializer> atoms);
|
||||
// /// \brief Create a new (sugar) branch with one first NAG containing atoms constructed from \a atoms
|
||||
// branch &create_branch(std::vector<row_initializer> atoms);
|
||||
|
||||
/// \brief Extend an existing (sugar) branch identified by \a asymID with one sugar containing atoms constructed from \a atom_info
|
||||
///
|
||||
/// \param asym_id The asym id of the branch to extend
|
||||
/// \param atom_info Array containing the info for the atoms to construct for the new sugar
|
||||
/// \param link_sugar The sugar to link to, note: this is the sugar number (1 based)
|
||||
/// \param link_atom The atom id of the atom linked in the sugar
|
||||
branch &extend_branch(const std::string &asym_id, std::vector<row_initializer> atom_info,
|
||||
int link_sugar, const std::string &link_atom);
|
||||
// /// \brief Extend an existing (sugar) branch identified by \a asymID with one sugar containing atoms constructed from \a atom_info
|
||||
// ///
|
||||
// /// \param asym_id The asym id of the branch to extend
|
||||
// /// \param atom_info Array containing the info for the atoms to construct for the new sugar
|
||||
// /// \param link_sugar The sugar to link to, note: this is the sugar number (1 based)
|
||||
// /// \param link_atom The atom id of the atom linked in the sugar
|
||||
// branch &extend_branch(const std::string &asym_id, std::vector<row_initializer> atom_info,
|
||||
// int link_sugar, const std::string &link_atom);
|
||||
|
||||
/// \brief Remove \a branch
|
||||
void remove_branch(branch &branch);
|
||||
@@ -1091,11 +1153,14 @@ class structure
|
||||
/// \brief emplace the moved atom @a atom
|
||||
atom &emplace_atom(atom &&atom);
|
||||
|
||||
/// \brief Reorder atom_site atoms based on 'natural' ordering
|
||||
void reorder_atoms();
|
||||
|
||||
private:
|
||||
friend polymer;
|
||||
friend residue;
|
||||
|
||||
void load_atoms_for_model(StructureOpenOptions options);
|
||||
void load_atoms_for_model(structure_open_options options);
|
||||
|
||||
std::string insert_compound(const std::string &compoundID, bool is_entity);
|
||||
|
||||
@@ -1107,19 +1172,12 @@ class structure
|
||||
void remove_sugar(sugar &sugar);
|
||||
|
||||
datablock &m_db;
|
||||
size_t m_model_nr;
|
||||
std::size_t m_model_nr;
|
||||
std::vector<atom> m_atoms;
|
||||
std::vector<size_t> m_atom_index;
|
||||
std::vector<std::size_t> m_atom_index;
|
||||
std::list<polymer> m_polymers;
|
||||
std::list<branch> m_branches;
|
||||
std::vector<residue> m_non_polymers;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
/// Some people believe that simply dumping some atom records is enough.
|
||||
/// \param db The cif::datablock that hopefully contains some valid data
|
||||
void reconstruct_pdbx(datablock &db);
|
||||
|
||||
} // namespace cif::mm
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Exception that is thrown when the mmCIF file contains a parsing error */
|
||||
@@ -73,7 +75,15 @@ class sac_parser
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
using datablock_index = std::map<std::string, std::size_t>;
|
||||
struct iless_op
|
||||
{
|
||||
bool operator()(std::string_view a, std::string_view b) const
|
||||
{
|
||||
return icompare(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
using datablock_index = std::map<std::string, std::size_t, iless_op>;
|
||||
|
||||
virtual ~sac_parser() = default;
|
||||
/** @endcond */
|
||||
@@ -143,9 +153,9 @@ class sac_parser
|
||||
|
||||
enum class CIFToken
|
||||
{
|
||||
Unknown,
|
||||
UNKNOWN,
|
||||
|
||||
Eof,
|
||||
END_OF_FILE,
|
||||
|
||||
DATA,
|
||||
LOOP,
|
||||
@@ -153,24 +163,38 @@ class sac_parser
|
||||
SAVE_,
|
||||
SAVE_NAME,
|
||||
STOP,
|
||||
Tag,
|
||||
Value
|
||||
ITEM_NAME,
|
||||
|
||||
VALUE_INAPPLICABLE,
|
||||
VALUE_UNKNOWN,
|
||||
VALUE_NUMERIC_INTEGER,
|
||||
VALUE_NUMERIC_FLOAT,
|
||||
VALUE_CHARSTRING,
|
||||
VALUE_TEXTFIELD
|
||||
};
|
||||
|
||||
static constexpr const char *get_token_name(CIFToken token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case CIFToken::Unknown: return "Unknown";
|
||||
case CIFToken::Eof: return "Eof";
|
||||
case CIFToken::UNKNOWN: return "Unknown";
|
||||
case CIFToken::END_OF_FILE: return "Eof";
|
||||
case CIFToken::DATA: return "DATA";
|
||||
case CIFToken::LOOP: return "LOOP";
|
||||
case CIFToken::GLOBAL: return "GLOBAL";
|
||||
case CIFToken::SAVE_: return "SAVE";
|
||||
case CIFToken::SAVE_NAME: return "SAVE+name";
|
||||
case CIFToken::STOP: return "STOP";
|
||||
case CIFToken::Tag: return "Tag";
|
||||
case CIFToken::Value: return "Value";
|
||||
case CIFToken::ITEM_NAME: return "Tag";
|
||||
// case CIFToken::VALUE: return "Value";
|
||||
|
||||
case CIFToken::VALUE_INAPPLICABLE: return "Inapplicable value";
|
||||
case CIFToken::VALUE_UNKNOWN: return "'Unknown' value (=null)";
|
||||
case CIFToken::VALUE_NUMERIC_INTEGER: return "Integer value";
|
||||
case CIFToken::VALUE_NUMERIC_FLOAT: return "Float value";
|
||||
case CIFToken::VALUE_CHARSTRING: return "Charstring value";
|
||||
case CIFToken::VALUE_TEXTFIELD: return "Textfield value";
|
||||
|
||||
default: return "Invalid token parameter";
|
||||
}
|
||||
}
|
||||
@@ -252,7 +276,7 @@ class sac_parser
|
||||
virtual void produce_datablock(std::string_view name) = 0;
|
||||
virtual void produce_category(std::string_view name) = 0;
|
||||
virtual void produce_row() = 0;
|
||||
virtual void produce_item(std::string_view category, std::string_view item, std::string_view value) = 0;
|
||||
virtual void produce_item(std::string_view category, std::string_view item, item_value value) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -267,11 +291,16 @@ class sac_parser
|
||||
QuotedString,
|
||||
QuotedStringQuote,
|
||||
UnquotedString,
|
||||
Tag,
|
||||
TextField,
|
||||
TextFieldNL,
|
||||
ItemName,
|
||||
TextItem,
|
||||
TextItemNL,
|
||||
Reserved,
|
||||
Value
|
||||
Value,
|
||||
|
||||
Numeric_Integer,
|
||||
Numeric_Float,
|
||||
Numeric_Exponent1,
|
||||
Numeric_Exponent2
|
||||
};
|
||||
|
||||
std::streambuf &m_source;
|
||||
@@ -284,6 +313,8 @@ class sac_parser
|
||||
// token buffer
|
||||
std::vector<char> m_token_buffer;
|
||||
std::string_view m_token_value;
|
||||
int64_t m_token_value_int;
|
||||
double m_token_value_float;
|
||||
|
||||
/** @endcond */
|
||||
};
|
||||
@@ -299,6 +330,14 @@ class sac_parser
|
||||
class parser : public sac_parser
|
||||
{
|
||||
public:
|
||||
/// \brief constructor, generates data into @a file from @a is using validator @a v
|
||||
parser(std::istream &is, file &file, const validator *v)
|
||||
: sac_parser(is)
|
||||
, m_file(file)
|
||||
, m_validator(v)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor, generates data into @a file from @a is
|
||||
parser(std::istream &is, file &file)
|
||||
: sac_parser(is)
|
||||
@@ -313,12 +352,13 @@ class parser : public sac_parser
|
||||
|
||||
void produce_row() override;
|
||||
|
||||
void produce_item(std::string_view category, std::string_view item, std::string_view value) override;
|
||||
void produce_item(std::string_view category, std::string_view item, item_value value) override;
|
||||
|
||||
protected:
|
||||
file &m_file;
|
||||
datablock *m_datablock = nullptr;
|
||||
category *m_category = nullptr;
|
||||
const validator *m_validator = nullptr;
|
||||
row_handle m_row;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2023 NKI/AVL, Netherlands Cancer Institute
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -27,16 +27,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
/**
|
||||
* @file pdb.hpp
|
||||
*
|
||||
*
|
||||
* This file presents the API to read and write files in the
|
||||
* legacy and ancient PDB format.
|
||||
*
|
||||
*
|
||||
* The code works on the basis of best effort since it is
|
||||
* impossible to have correct round trip fidelity.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace cif::pdb
|
||||
@@ -81,7 +84,7 @@ inline void write(std::ostream &os, const file &f)
|
||||
/** @brief Write out the data in @a db to file @a file
|
||||
* in legacy PDB format or mmCIF format, depending on the
|
||||
* filename extension.
|
||||
*
|
||||
*
|
||||
* If extension of @a file is *.gz* the resulting file will
|
||||
* be written in gzip compressed format.
|
||||
*/
|
||||
@@ -90,7 +93,7 @@ void write(const std::filesystem::path &file, const datablock &db);
|
||||
/** @brief Write out the data in @a f to file @a file
|
||||
* in legacy PDB format or mmCIF format, depending on the
|
||||
* filename extension.
|
||||
*
|
||||
*
|
||||
* If extension of @a file is *.gz* the resulting file will
|
||||
* be written in gzip compressed format.
|
||||
*/
|
||||
@@ -99,6 +102,108 @@ inline void write(const std::filesystem::path &p, const file &f)
|
||||
write(p, f.front());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Quickly fix a PDB file that lacks some often needed categories
|
||||
*
|
||||
* This differs from reconstruct_pdbx which does a much more thorough job
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
*/
|
||||
|
||||
void fixup_pdbx(file &pdbx_file);
|
||||
|
||||
/**
|
||||
* @brief Quickly fix a PDB file that lacks some often needed categories
|
||||
*
|
||||
* This differs from reconstruct_pdbx which does a much more thorough job
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \param v The validator to use
|
||||
*/
|
||||
|
||||
void fixup_pdbx(file &pdbx_file, const validator &v);
|
||||
|
||||
/** \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
*
|
||||
* Some people believe that simply dumping some atom records is enough.
|
||||
*
|
||||
* This version uses the audit_conform information and falls back to
|
||||
* using mmcif_pdbx.dic if not specified.
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \result Returns true if the resulting file is valid
|
||||
*/
|
||||
|
||||
bool reconstruct_pdbx(file &pdbx_file);
|
||||
|
||||
/** \brief Reconstruct all missing categories for an assumed PDBx file.
|
||||
*
|
||||
* Some people believe that simply dumping some atom records is enough.
|
||||
*
|
||||
* \param pdbx_file The cif::file that hopefully contains some valid data
|
||||
* \param v The validator to use
|
||||
* \result Returns true if the resulting file is valid
|
||||
*/
|
||||
|
||||
bool reconstruct_pdbx(file &pdbx_file, const validator &v);
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
*
|
||||
* This function for now checks if the following categories are consistent:
|
||||
*
|
||||
* atom_site -> pdbx_poly_seq_scheme -> entity_poly_seq -> entity_poly -> entity
|
||||
*
|
||||
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
|
||||
*
|
||||
* This function throws a std::system_error in case of an error
|
||||
*
|
||||
* \param pdbx_file The input file
|
||||
* \param v The validator to use
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file,
|
||||
const validator &v = validator_factory::instance().get("mmcif_pdbx.dic"));
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
*
|
||||
* This function for now checks if the following categories are consistent:
|
||||
*
|
||||
* atom_site -> pdbx_poly_seq_scheme -> entity_poly_seq -> entity_poly -> entity
|
||||
*
|
||||
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
|
||||
*
|
||||
* The dictionary is assumed to be specified in the file or to be the
|
||||
* default mmcif_pdbx.dic dictionary.
|
||||
*
|
||||
* \param file The input file
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, std::error_code &ec);
|
||||
|
||||
/** \brief This is an extension to cif::validator, use the logic in common
|
||||
* PDBx files to see if the file is internally consistent.
|
||||
*
|
||||
* This function for now checks if the following categories are consistent:
|
||||
*
|
||||
* atom_site -> pdbx_poly_seq_scheme -> entity_poly_seq -> entity_poly -> entity
|
||||
*
|
||||
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
|
||||
*
|
||||
* \param file The input file
|
||||
* \param v The validator to use
|
||||
* \param ec The error_code in case something was wrong
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file, const validator &v,
|
||||
std::error_code &ec);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Other I/O related routines
|
||||
|
||||
@@ -106,7 +211,7 @@ inline void write(const std::filesystem::path &p, const file &f)
|
||||
*
|
||||
* The line returned should be compatible with the legacy PDB
|
||||
* format and is e.g. used in the DSSP program.
|
||||
*
|
||||
*
|
||||
* @param data The datablock to use as source for the requested data
|
||||
* @param truncate_at The maximum length of the line returned
|
||||
*/
|
||||
@@ -116,7 +221,7 @@ std::string get_HEADER_line(const datablock &data, std::string::size_type trunca
|
||||
*
|
||||
* The line returned should be compatible with the legacy PDB
|
||||
* format and is e.g. used in the DSSP program.
|
||||
*
|
||||
*
|
||||
* @param data The datablock to use as source for the requested data
|
||||
* @param truncate_at The maximum length of the line returned
|
||||
*/
|
||||
@@ -126,7 +231,7 @@ std::string get_COMPND_line(const datablock &data, std::string::size_type trunca
|
||||
*
|
||||
* The line returned should be compatible with the legacy PDB
|
||||
* format and is e.g. used in the DSSP program.
|
||||
*
|
||||
*
|
||||
* @param data The datablock to use as source for the requested data
|
||||
* @param truncate_at The maximum length of the line returned
|
||||
*/
|
||||
@@ -136,12 +241,11 @@ std::string get_SOURCE_line(const datablock &data, std::string::size_type trunca
|
||||
*
|
||||
* The line returned should be compatible with the legacy PDB
|
||||
* format and is e.g. used in the DSSP program.
|
||||
*
|
||||
*
|
||||
* @param data The datablock to use as source for the requested data
|
||||
* @param truncate_at The maximum length of the line returned
|
||||
*/
|
||||
|
||||
std::string get_AUTHOR_line(const datablock &data, std::string::size_type truncate_at = 127);
|
||||
|
||||
} // namespace pdbx
|
||||
|
||||
} // namespace cif::pdb
|
||||
|
||||
@@ -26,18 +26,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <format>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <valarray>
|
||||
|
||||
#if __has_include(<clipper/core/coords.h>)
|
||||
#define HAVE_LIBCLIPPER 1
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
#include <clipper/core/coords.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/** \file point.hpp
|
||||
@@ -364,11 +367,18 @@ class quaternion_type
|
||||
}
|
||||
|
||||
/// \brief test for all zero values
|
||||
constexpr operator bool() const
|
||||
constexpr explicit operator bool() const
|
||||
{
|
||||
return a != 0 or b != 0 or c != 0 or d != 0;
|
||||
}
|
||||
|
||||
/// \brief for debugging e.g.
|
||||
friend std::ostream &operator<<(std::ostream &os, const quaternion_type &rhs)
|
||||
{
|
||||
os << std::format("{{ a: {}, b: {}, c: {}, d: {} }}", rhs.a, rhs.b, rhs.c, rhs.d);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type a, b, c, d;
|
||||
};
|
||||
@@ -661,12 +671,23 @@ struct point_type
|
||||
return std::make_tuple(std::ref(m_x), std::ref(m_y), std::ref(m_z));
|
||||
}
|
||||
|
||||
/// \brief Compare with @a rhs
|
||||
#if defined(__cpp_impl_three_way_comparison)
|
||||
/// \brief a default spaceship operator
|
||||
constexpr auto operator<=>(const point_type &rhs) const = default;
|
||||
#else
|
||||
/// \brief a default equals operator
|
||||
constexpr bool operator==(const point_type &rhs) const
|
||||
{
|
||||
return m_x == rhs.m_x and m_y == rhs.m_y and m_z == rhs.m_z;
|
||||
}
|
||||
|
||||
/// \brief a default not-equals operator
|
||||
constexpr bool operator!=(const point_type &rhs) const
|
||||
{
|
||||
return not operator==(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
// consider point as a vector... perhaps I should rename point?
|
||||
|
||||
/// \brief looking at the point as if it is a vector, return the squared length
|
||||
@@ -731,6 +752,55 @@ inline constexpr auto cross_product(const point_type<F1> &a, const point_type<F2
|
||||
a.m_x * b.m_y - b.m_x * a.m_y);
|
||||
}
|
||||
|
||||
/// \brief return the squared norm of point @a p
|
||||
template <typename F>
|
||||
constexpr F norm_squared(const point_type<F> &p)
|
||||
{
|
||||
return p.m_x * p.m_x + p.m_y * p.m_y + p.m_z * p.m_z;
|
||||
}
|
||||
|
||||
/// \brief return the norm of point @a p
|
||||
template <typename F>
|
||||
constexpr point_type<F> norm(const point_type<F> &p)
|
||||
{
|
||||
return std::sqrt(norm_squared(p));
|
||||
}
|
||||
|
||||
/// \brief return the point where two lines intersect, or an empty value if they don't intersect at all
|
||||
template <typename F>
|
||||
std::optional<cif::point> line_line_intersection(const point_type<F> &p1,
|
||||
const point_type<F> &p2, const point_type<F> &p3, const point_type<F> &p4)
|
||||
{
|
||||
auto p13 = p1 - p3;
|
||||
auto p43 = p4 - p3;
|
||||
if (std::abs(p43.m_x) < std::numeric_limits<F>::epsilon() and std::abs(p43.m_y) < std::numeric_limits<F>::epsilon() and std::abs(p43.m_z) < std::numeric_limits<F>::epsilon())
|
||||
return {};
|
||||
|
||||
auto p21 = p2 - p1;
|
||||
if (std::abs(p21.m_x) < std::numeric_limits<F>::epsilon() and std::abs(p21.m_y) < std::numeric_limits<F>::epsilon() and std::abs(p21.m_z) < std::numeric_limits<F>::epsilon())
|
||||
return {};
|
||||
|
||||
auto d1343 = cif::dot_product(p43, p13);
|
||||
auto d4321 = cif::dot_product(p43, p21);
|
||||
auto d1321 = cif::dot_product(p13, p21);
|
||||
auto d4343 = cif::dot_product(p43, p43);
|
||||
auto d2121 = cif::dot_product(p21, p21);
|
||||
|
||||
auto denom = d2121 * d4343 - d4321 * d4321;
|
||||
if (std::abs(denom) < std::numeric_limits<F>::epsilon())
|
||||
return {};
|
||||
|
||||
auto numer = d1343 * d4321 - d1321 * d4343;
|
||||
|
||||
auto mua = numer / denom;
|
||||
auto mub = (d1343 + d4321 * mua) / d4343;
|
||||
|
||||
auto pa = p1 + mua * p21;
|
||||
auto pb = p3 + mub * p43;
|
||||
|
||||
return { (pa + pb) / 2 };
|
||||
}
|
||||
|
||||
/// \brief return the angle in degrees between the vectors from point @a p2 to @a p1 and @a p2 to @a p3
|
||||
template <typename F>
|
||||
constexpr auto angle(const point_type<F> &p1, const point_type<F> &p2, const point_type<F> &p3)
|
||||
@@ -794,6 +864,9 @@ constexpr auto distance_point_to_line(const point_type<F> &l1, const point_type<
|
||||
return cross.length() / line.length();
|
||||
}
|
||||
|
||||
/// \brief return the smallest sphere around the points in @a pts
|
||||
std::tuple<point, float> smallest_sphere_around_points(std::vector<point> pts);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/**
|
||||
* @brief For e.g. simulated annealing, returns a new point that is moved in
|
||||
@@ -866,7 +939,7 @@ class spherical_dots
|
||||
}
|
||||
|
||||
/// \brief The number of points
|
||||
size_t size() const { return P; }
|
||||
std::size_t size() const { return P; }
|
||||
|
||||
/// \brief Access a point by index
|
||||
const point operator[](uint32_t inIx) const { return m_points[inIx]; }
|
||||
@@ -882,7 +955,7 @@ class spherical_dots
|
||||
|
||||
spherical_dots()
|
||||
{
|
||||
constexpr double
|
||||
const double
|
||||
kGoldenRatio = (1 + std::sqrt(5.0)) / 2;
|
||||
|
||||
auto p = m_points.begin();
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
* that's not the case.
|
||||
*
|
||||
* You can access the values of stored items by name or index.
|
||||
* The return value of operator[] is an cif::item_handle object.
|
||||
* The return value of operator[] is a reference to a cif::item_value object.
|
||||
*
|
||||
* @code {.cpp}
|
||||
* cif::category &atom_site = my_db["atom_site"];
|
||||
@@ -51,7 +51,7 @@
|
||||
* std::string name = rh["label_atom_id"].as<std::string>();
|
||||
*
|
||||
* // by index:
|
||||
* uint16_t ix = atom_site.get_column_ix("label_atom_id");
|
||||
* uint16_t ix = atom_site.get_item_ix("label_atom_id");
|
||||
* assert(rh[ix].as<std::string() == name);
|
||||
* @endcode
|
||||
*
|
||||
@@ -85,17 +85,17 @@ namespace detail
|
||||
template <typename... C>
|
||||
struct get_row_result
|
||||
{
|
||||
static constexpr size_t N = sizeof...(C);
|
||||
static constexpr std::size_t N = sizeof...(C);
|
||||
|
||||
get_row_result(const row_handle &r, std::array<uint16_t, N> &&columns)
|
||||
get_row_result(const row_handle &r, std::array<uint16_t, N> &&items)
|
||||
: m_row(r)
|
||||
, m_columns(std::move(columns))
|
||||
, m_items(std::move(items))
|
||||
{
|
||||
}
|
||||
|
||||
const item_handle operator[](uint16_t ix) const
|
||||
const item_value &operator[](uint16_t ix) const
|
||||
{
|
||||
return m_row[m_columns[ix]];
|
||||
return m_row[m_items[ix]];
|
||||
}
|
||||
|
||||
template <typename... Ts, std::enable_if_t<N == sizeof...(Ts), int> = 0>
|
||||
@@ -104,14 +104,14 @@ namespace detail
|
||||
return get<Ts...>(std::index_sequence_for<Ts...>{});
|
||||
}
|
||||
|
||||
template <typename... Ts, size_t... Is>
|
||||
template <typename... Ts, std::size_t... Is>
|
||||
std::tuple<Ts...> get(std::index_sequence<Is...>) const
|
||||
{
|
||||
return std::tuple<Ts...>{ m_row[m_columns[Is]].template as<Ts>()... };
|
||||
return std::tuple<Ts...>{ m_row[m_items[Is]].template get<Ts>()... };
|
||||
}
|
||||
|
||||
const row_handle &m_row;
|
||||
std::array<uint16_t, N> m_columns;
|
||||
std::array<uint16_t, N> m_items;
|
||||
};
|
||||
|
||||
// we want to be able to tie some variables to a get_row_result, for this we use tiewraps
|
||||
@@ -173,14 +173,14 @@ class row : public std::vector<item_value>
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// private:
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
|
||||
template <typename, typename...>
|
||||
friend class iterator_impl;
|
||||
|
||||
void append(uint16_t ix, item_value &&iv)
|
||||
void append(uint16_t ix, item_value iv)
|
||||
{
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
@@ -204,10 +204,10 @@ class row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
friend struct item_handle;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
template <typename, typename...> friend class iterator_impl;
|
||||
|
||||
row_handle() = default;
|
||||
|
||||
@@ -244,63 +244,61 @@ class row_handle
|
||||
return not empty();
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in column @a column_ix
|
||||
item_handle operator[](uint16_t column_ix)
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(column_ix, *this);
|
||||
}
|
||||
/// \brief return the count of the items
|
||||
[[nodiscard]] size_t size() const { return m_row->size(); }
|
||||
|
||||
/// \brief return a const cif::item_handle to the item in column @a column_ix
|
||||
const item_handle operator[](uint16_t column_ix) const
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(column_ix, const_cast<row_handle &>(*this));
|
||||
}
|
||||
/// \brief return a reference to a cif::item_value to the item in item @a item_ix
|
||||
item_value &operator[](uint16_t item_ix);
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the column named @a column_name
|
||||
item_handle operator[](std::string_view column_name)
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(add_column(column_name), *this);
|
||||
}
|
||||
/// \brief return a const reference to a cif::item_value to the item in item @a item_ix
|
||||
const item_value &operator[](uint16_t item_ix) const;
|
||||
|
||||
/// \brief return a const cif::item_handle to the item in the column named @a column_name
|
||||
const item_handle operator[](std::string_view column_name) const
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(get_column_ix(column_name), const_cast<row_handle &>(*this));
|
||||
}
|
||||
/// \brief return a reference to a cif::item_value to the item in the item named @a item_name
|
||||
item_value &operator[](std::string_view item_name);
|
||||
|
||||
/// \brief return a const reference to a cif::item_value to the item in the item named @a item_name
|
||||
const item_value &operator[](std::string_view item_name) const;
|
||||
|
||||
/// \brief Return an object that can be used in combination with cif::tie
|
||||
/// to assign the values for the columns @a columns
|
||||
/// to assign the values for the items @a items
|
||||
template <typename... C>
|
||||
auto get(C... columns) const
|
||||
auto get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<C...>(*this, { get_column_ix(columns)... });
|
||||
return detail::get_row_result<C...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Return a tuple of values of types @a Ts for the columns @a columns
|
||||
/// \brief Return a tuple of values of types @a Ts for the items @a items
|
||||
template <typename... Ts, typename... C, std::enable_if_t<sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1, int> = 0>
|
||||
std::tuple<Ts...> get(C... columns) const
|
||||
std::tuple<Ts...> get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_column_ix(columns)... });
|
||||
return detail::get_row_result<Ts...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Get the value of column @a column cast to type @a T
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
T get(const char *column) const
|
||||
T get(const char *item) const
|
||||
{
|
||||
return operator[](get_column_ix(column)).template as<T>();
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief assign each of the columns named in @a values to their respective value
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief assign each of the items named in @a values to their respective value
|
||||
void assign(const std::vector<item> &values)
|
||||
{
|
||||
for (auto &value : values)
|
||||
assign(value, true);
|
||||
}
|
||||
|
||||
/** \brief assign the value @a value to the column named @a name
|
||||
/** \brief assign the value @a value to the item named @a name
|
||||
*
|
||||
* If updateLinked it true, linked records are updated as well.
|
||||
* That means that if column @a name is part of the link definition
|
||||
* That means that if item @a name is part of the link definition
|
||||
* and the link results in a linked record in another category
|
||||
* this record in the linked category is updated as well.
|
||||
*
|
||||
@@ -308,15 +306,15 @@ class row_handle
|
||||
* checked to see if it conforms to the rules defined in the dictionary
|
||||
*/
|
||||
|
||||
void assign(std::string_view name, std::string_view value, bool updateLinked, bool validate = true)
|
||||
void assign(std::string_view name, item_value value, bool updateLinked, bool validate = true)
|
||||
{
|
||||
assign(add_column(name), value, updateLinked, validate);
|
||||
assign(add_item(name), std::move(value), updateLinked, validate);
|
||||
}
|
||||
|
||||
/** \brief assign the value @a value to column at index @a column
|
||||
/** \brief assign the value @a value to item at index @a item
|
||||
*
|
||||
* If updateLinked it true, linked records are updated as well.
|
||||
* That means that if column @a column is part of the link definition
|
||||
* That means that if item @a item is part of the link definition
|
||||
* and the link results in a linked record in another category
|
||||
* this record in the linked category is updated as well.
|
||||
*
|
||||
@@ -324,7 +322,7 @@ class row_handle
|
||||
* checked to see if it conforms to the rules defined in the dictionary
|
||||
*/
|
||||
|
||||
void assign(uint16_t column, std::string_view value, bool updateLinked, bool validate = true);
|
||||
void assign(uint16_t item, item_value value, bool updateLinked, bool validate = true);
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator==(const row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
|
||||
@@ -333,10 +331,10 @@ class row_handle
|
||||
bool operator!=(const row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
|
||||
|
||||
private:
|
||||
uint16_t get_column_ix(std::string_view name) const;
|
||||
std::string_view get_column_name(uint16_t ix) const;
|
||||
uint16_t get_item_ix(std::string_view name) const;
|
||||
std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
uint16_t add_column(std::string_view name);
|
||||
uint16_t add_item(std::string_view name);
|
||||
|
||||
row *get_row()
|
||||
{
|
||||
@@ -348,12 +346,12 @@ class row_handle
|
||||
return m_row;
|
||||
}
|
||||
|
||||
void assign(const item &i, bool updateLinked)
|
||||
void assign(const item &i, bool updateLinked);/*
|
||||
{
|
||||
assign(i.name(), i.value(), updateLinked);
|
||||
}
|
||||
} */
|
||||
|
||||
void swap(uint16_t column, row_handle &r);
|
||||
void swap(uint16_t item, row_handle &r);
|
||||
|
||||
category *m_category = nullptr;
|
||||
row *m_row = nullptr;
|
||||
@@ -400,7 +398,7 @@ class row_initializer : public std::vector<item>
|
||||
|
||||
|
||||
/// \brief set the value for item name @a name to @a value
|
||||
void set_value(std::string_view name, std::string_view value);
|
||||
void set_value(std::string name, item_value value);
|
||||
|
||||
/// \brief set the value for item based on @a i
|
||||
void set_value(const item &i)
|
||||
@@ -409,7 +407,7 @@ class row_initializer : public std::vector<item>
|
||||
}
|
||||
|
||||
/// \brief set the value for item name @a name to @a value, but only if the item did not have a value already
|
||||
void set_value_if_empty(std::string_view name, std::string_view value);
|
||||
void set_value_if_empty(std::string name, item_value value);
|
||||
|
||||
/// \brief set the value for item @a i, but only if the item did not have a value already
|
||||
void set_value_if_empty(const item &i)
|
||||
|
||||
@@ -300,7 +300,7 @@ namespace literals
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
inline sym_op operator""_symop(const char *text, size_t length)
|
||||
inline sym_op operator""_symop(const char *text, std::size_t length)
|
||||
{
|
||||
return sym_op({ text, length });
|
||||
}
|
||||
@@ -397,6 +397,8 @@ class cell
|
||||
float get_beta() const { return m_beta; } ///< return angle beta
|
||||
float get_gamma() const { return m_gamma; } ///< return angle gamma
|
||||
|
||||
float get_volume() const; ///< return the calculated volume for this cell
|
||||
|
||||
matrix3x3<float> get_orthogonal_matrix() const { return m_orthogonal; } ///< return the matrix to use to transform coordinates from fractional to orthogonal
|
||||
matrix3x3<float> get_fractional_matrix() const { return m_fractional; } ///< return the matrix to use to transform coordinates from orthogonal to fractional
|
||||
|
||||
@@ -462,7 +464,7 @@ class spacegroup : public std::vector<transformation>
|
||||
|
||||
private:
|
||||
int m_nr;
|
||||
size_t m_index;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -38,15 +38,44 @@
|
||||
#include <vector>
|
||||
|
||||
#if __has_include(<experimental/type_traits>)
|
||||
|
||||
#include <experimental/type_traits>
|
||||
namespace std_experimental = std::experimental;
|
||||
|
||||
#else
|
||||
// sub optimal, but replicating the same code is worse
|
||||
#include <zeep/type-traits.hpp>
|
||||
|
||||
// A quick hack to work around the missing is_detected in MSVC
|
||||
namespace std_experimental
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class AlwaysVoid, template <class...> class Op, class... Args>
|
||||
struct detector
|
||||
{
|
||||
using value_t = std::false_type;
|
||||
};
|
||||
|
||||
template <template <class...> class Op, class... Args>
|
||||
struct detector<std::void_t<Op<Args...>>, Op, Args...>
|
||||
{
|
||||
using value_t = std::true_type;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <template <class...> class Op, class... Args>
|
||||
using is_detected = typename detail::detector<void, Op, Args...>::value_t;
|
||||
|
||||
template <template <class...> class Op, class... Args>
|
||||
const auto is_detected_v = is_detected<Op, Args...>::value;
|
||||
|
||||
} // namespace std_experimental
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \file text.hpp
|
||||
*
|
||||
*
|
||||
* Various text manipulating routines
|
||||
*/
|
||||
|
||||
@@ -82,15 +111,15 @@ void to_upper(std::string &s);
|
||||
/**
|
||||
* @brief Join the strings in the range [ @a a, @a e ) using
|
||||
* @a sep as separator
|
||||
*
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
*
|
||||
* @code {.cpp}
|
||||
* std::vector<std::string> v{ "aap", "noot", "mies" };
|
||||
*
|
||||
*
|
||||
* assert(cif::join(v.begin(), v.end(), ", ") == "aap, noot, mies");
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
*/
|
||||
template <typename IterType>
|
||||
std::string join(IterType b, IterType e, std::string_view sep)
|
||||
@@ -121,15 +150,15 @@ std::string join(IterType b, IterType e, std::string_view sep)
|
||||
|
||||
/**
|
||||
* @brief Join the strings in the array @a arr using @a sep as separator
|
||||
*
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
*
|
||||
* @code {.cpp}
|
||||
* std::list<std::string> v{ "aap", "noot", "mies" };
|
||||
*
|
||||
*
|
||||
* assert(cif::join(v, ", ") == "aap, noot, mies");
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
*/
|
||||
template <typename V>
|
||||
std::string join(const V &arr, std::string_view sep)
|
||||
@@ -139,20 +168,20 @@ std::string join(const V &arr, std::string_view sep)
|
||||
|
||||
/**
|
||||
* @brief Split the string in @a s based on the characters in @a separators
|
||||
*
|
||||
*
|
||||
* Each of the characters in @a separators induces a split.
|
||||
*
|
||||
*
|
||||
* When suppress_empty is true, empty strings are not produced in the
|
||||
* resulting array.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
*
|
||||
* @code {.cpp}
|
||||
* auto v = cif::split("aap:noot,,mies", ":,", true);
|
||||
*
|
||||
*
|
||||
* assert(v == std::vector{"aap", "noot", "mies"});
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
*/
|
||||
template <typename StringType = std::string_view>
|
||||
std::vector<StringType> split(std::string_view s, std::string_view separators, bool suppress_empty = false)
|
||||
@@ -183,7 +212,7 @@ std::vector<StringType> split(std::string_view s, std::string_view separators, b
|
||||
|
||||
/**
|
||||
* @brief Replace all occurrences of @a what in string @a s with the string @a with
|
||||
*
|
||||
*
|
||||
* The string @a with may be empty in which case each occurrence of @a what is simply
|
||||
* deleted.
|
||||
*/
|
||||
@@ -270,7 +299,6 @@ struct iless
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// iset is a std::set of std::string but with a comparator that
|
||||
/// ignores character case.
|
||||
using iset = std::set<std::string, iless>;
|
||||
@@ -289,15 +317,27 @@ inline char tolower(int ch)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** \brief return a tuple consisting of the category and item name for @a tag
|
||||
*
|
||||
/** \brief return a tuple consisting of the category and item name for @a item_name
|
||||
*
|
||||
* The category name is stripped of its leading underscore character.
|
||||
*
|
||||
*
|
||||
* If no dot character was found, the category name is empty. That's for
|
||||
* cif 1.0 formatted data.
|
||||
*/
|
||||
*/
|
||||
|
||||
std::tuple<std::string, std::string> split_tag_name(std::string_view tag);
|
||||
[[deprecated("use split_item_name instead")]]
|
||||
std::tuple<std::string, std::string> split_tag_name(std::string_view item_name);
|
||||
|
||||
|
||||
/** \brief return a tuple consisting of the category and item name for @a item_name
|
||||
*
|
||||
* The category name is stripped of its leading underscore character.
|
||||
*
|
||||
* If no dot character was found, the category name is empty. That's for
|
||||
* cif 1.0 formatted data.
|
||||
*/
|
||||
|
||||
std::tuple<std::string, std::string> split_item_name(std::string_view item_name);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -307,277 +347,43 @@ std::string cif_id_for_number(int number);
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** \brief custom word wrapping routine.
|
||||
*
|
||||
*
|
||||
* Wrap the text in @a text based on a maximum line width @a width using
|
||||
* a dynamic programming approach to get the most efficient filling of
|
||||
* the space.
|
||||
*/
|
||||
std::vector<std::string> word_wrap(const std::string &text, size_t width);
|
||||
std::vector<std::string> word_wrap(const std::string &text, std::size_t width);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief std::from_chars for floating point types.
|
||||
///
|
||||
/// These are optional, there's a selected_charconv class below that selects
|
||||
/// the best option to use based on support by the stl library.
|
||||
///
|
||||
/// I.e. that in case of GNU < 12 (or something) the cif implementation will
|
||||
/// be used, all other cases will use the stl version.
|
||||
|
||||
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
|
||||
std::from_chars_result from_chars(const char *first, const char *last, FloatType &value)
|
||||
{
|
||||
std::from_chars_result result{ first, {} };
|
||||
|
||||
enum State
|
||||
{
|
||||
IntegerSign,
|
||||
Integer,
|
||||
Fraction,
|
||||
ExponentSign,
|
||||
Exponent
|
||||
} state = IntegerSign;
|
||||
int sign = 1;
|
||||
unsigned long long vi = 0;
|
||||
long double f = 1;
|
||||
int exponent_sign = 1;
|
||||
int exponent = 0;
|
||||
bool done = false;
|
||||
|
||||
while (not done and result.ec == std::errc())
|
||||
{
|
||||
char ch = result.ptr != last ? *result.ptr : 0;
|
||||
++result.ptr;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case IntegerSign:
|
||||
if (ch == '-')
|
||||
{
|
||||
sign = -1;
|
||||
state = Integer;
|
||||
}
|
||||
else if (ch == '+')
|
||||
state = Integer;
|
||||
else if (ch >= '0' and ch <= '9')
|
||||
{
|
||||
vi = ch - '0';
|
||||
state = Integer;
|
||||
}
|
||||
else if (ch == '.')
|
||||
state = Fraction;
|
||||
else
|
||||
result.ec = std::errc::invalid_argument;
|
||||
break;
|
||||
|
||||
case Integer:
|
||||
if (ch >= '0' and ch <= '9')
|
||||
vi = 10 * vi + (ch - '0');
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = ExponentSign;
|
||||
else if (ch == '.')
|
||||
state = Fraction;
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
--result.ptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case Fraction:
|
||||
if (ch >= '0' and ch <= '9')
|
||||
{
|
||||
vi = 10 * vi + (ch - '0');
|
||||
f /= 10;
|
||||
}
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = ExponentSign;
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
--result.ptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ExponentSign:
|
||||
if (ch == '-')
|
||||
{
|
||||
exponent_sign = -1;
|
||||
state = Exponent;
|
||||
}
|
||||
else if (ch == '+')
|
||||
state = Exponent;
|
||||
else if (ch >= '0' and ch <= '9')
|
||||
{
|
||||
exponent = ch - '0';
|
||||
state = Exponent;
|
||||
}
|
||||
else
|
||||
result.ec = std::errc::invalid_argument;
|
||||
break;
|
||||
|
||||
case Exponent:
|
||||
if (ch >= '0' and ch <= '9')
|
||||
exponent = 10 * exponent + (ch - '0');
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
--result.ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.ec == std::errc())
|
||||
{
|
||||
long double v = f * vi * sign;
|
||||
if (exponent != 0)
|
||||
v *= std::pow(10, exponent * exponent_sign);
|
||||
|
||||
if (std::isnan(v))
|
||||
result.ec = std::errc::invalid_argument;
|
||||
else if (std::abs(v) > std::numeric_limits<FloatType>::max())
|
||||
result.ec = std::errc::result_out_of_range;
|
||||
|
||||
value = static_cast<FloatType>(v);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief duplication of std::chars_format for deficient STL implementations
|
||||
enum class chars_format
|
||||
{
|
||||
scientific = 1,
|
||||
fixed = 2,
|
||||
// hex,
|
||||
general = fixed | scientific
|
||||
};
|
||||
|
||||
/// \brief a simplistic implementation of std::to_chars for old STL implementations
|
||||
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
|
||||
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt)
|
||||
{
|
||||
int size = static_cast<int>(last - first);
|
||||
int r = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case chars_format::scientific:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%le", value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%e", value);
|
||||
break;
|
||||
|
||||
case chars_format::fixed:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%lf", value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%f", value);
|
||||
break;
|
||||
|
||||
case chars_format::general:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%lg", value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%g", value);
|
||||
break;
|
||||
}
|
||||
|
||||
std::to_chars_result result;
|
||||
if (r < 0 or r >= size)
|
||||
result = { first, std::errc::value_too_large };
|
||||
else
|
||||
result = { first + r, std::errc() };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief a simplistic implementation of std::to_chars for old STL implementations
|
||||
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
|
||||
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt, int precision)
|
||||
{
|
||||
int size = static_cast<int>(last - first);
|
||||
int r = 0;
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case chars_format::scientific:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%.*le", precision, value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%.*e", precision, value);
|
||||
break;
|
||||
|
||||
case chars_format::fixed:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%.*lf", precision, value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%.*f", precision, value);
|
||||
break;
|
||||
|
||||
case chars_format::general:
|
||||
if constexpr (std::is_same_v<FloatType, long double>)
|
||||
r = snprintf(first, last - first, "%.*lg", precision, value);
|
||||
else
|
||||
r = snprintf(first, last - first, "%.*g", precision, value);
|
||||
break;
|
||||
}
|
||||
|
||||
std::to_chars_result result;
|
||||
if (r < 0 or r >= size)
|
||||
result = { first, std::errc::value_too_large };
|
||||
else
|
||||
result = { first + r, std::errc() };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief class that uses our implementation of std::from_chars and std::to_chars
|
||||
template <typename T>
|
||||
struct my_charconv
|
||||
{
|
||||
/// @brief Simply call our version of std::from_chars
|
||||
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
|
||||
{
|
||||
return cif::from_chars(a, b, d);
|
||||
}
|
||||
using from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<T &>()));
|
||||
|
||||
/// @brief Simply call our version of std::to_chars
|
||||
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
|
||||
{
|
||||
return cif::to_chars(first, last, value, fmt);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief class that uses the STL implementation of std::from_chars and std::to_chars
|
||||
template <typename T>
|
||||
struct std_charconv
|
||||
{
|
||||
/// @brief Simply call std::from_chars
|
||||
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
|
||||
{
|
||||
return std::from_chars(a, b, d);
|
||||
}
|
||||
|
||||
/// @brief Simply call std::to_chars
|
||||
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
|
||||
{
|
||||
return std::to_chars(first, last, value, fmt);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief helper to find a from_chars function
|
||||
template <typename T>
|
||||
using from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<T &>()));
|
||||
template <typename T, typename = void>
|
||||
struct ff_charconv;
|
||||
|
||||
/**
|
||||
* @brief Helper to select the best implementation of charconv based on availability of the
|
||||
* function in the std:: namespace
|
||||
*
|
||||
* @tparam T The type for which we want to find a from_chars/to_chars function
|
||||
*/
|
||||
template <typename T>
|
||||
using selected_charconv = typename std::conditional_t<std::experimental::is_detected_v<from_chars_function, T>, std_charconv<T>, my_charconv<T>>;
|
||||
struct ff_charconv<T, typename std::enable_if_t<std::is_floating_point_v<T>>>
|
||||
{
|
||||
static std::from_chars_result from_chars(const char *a, const char *b, T &v);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using charconv = typename std::conditional_t<std_experimental::is_detected_v<from_chars_function, T>, std_charconv<T>, ff_charconv<T>>;
|
||||
|
||||
template <typename T>
|
||||
constexpr auto from_chars(const char *s, const char *e, T &v)
|
||||
{
|
||||
return charconv<T>::from_chars(s, e, v);
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
@@ -53,6 +53,7 @@
|
||||
#pragma warning(disable : 4068) // unknown pragma
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
#pragma warning(disable : 4101) // unreferenced local variable
|
||||
#pragma warning(disable : 4702) // unreachable code (too bad, this one. Happens in for loops)
|
||||
#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1
|
||||
#endif
|
||||
|
||||
@@ -77,6 +78,9 @@ extern CIFPP_EXPORT int VERBOSE;
|
||||
/// return the git 'build' number
|
||||
std::string get_version_nr();
|
||||
|
||||
/// return the width of the current output terminal, or 80 if it cannot be determined
|
||||
uint32_t get_terminal_width();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
namespace colour
|
||||
@@ -110,16 +114,12 @@ namespace colour
|
||||
/**
|
||||
* @brief Struct for delimited strings.
|
||||
*/
|
||||
template <typename StringType>
|
||||
struct coloured_string_t
|
||||
{
|
||||
static_assert(std::is_reference_v<StringType> or std::is_pointer_v<StringType>,
|
||||
"String type must be pointer or reference");
|
||||
|
||||
/**
|
||||
* @brief Construct a new coloured string t object
|
||||
*/
|
||||
coloured_string_t(StringType s, colour_type fc, colour_type bc, style_type st)
|
||||
coloured_string_t(std::string_view s, colour_type fc, colour_type bc, style_type st)
|
||||
: m_str(s)
|
||||
, m_fore_colour(static_cast<int>(fc) + 30)
|
||||
, m_back_colour(static_cast<int>(bc) + 40)
|
||||
@@ -149,12 +149,14 @@ namespace colour
|
||||
<< cs.m_str
|
||||
<< "\033[0m";
|
||||
}
|
||||
else
|
||||
os << cs.m_str;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/// @cond
|
||||
StringType m_str;
|
||||
std::string_view m_str;
|
||||
int m_fore_colour, m_back_colour;
|
||||
int m_style;
|
||||
/// @endcond
|
||||
@@ -188,39 +190,13 @@ namespace colour
|
||||
* @param st Text style to use
|
||||
*/
|
||||
|
||||
template <typename char_type>
|
||||
inline auto coloured(const char_type *str,
|
||||
template <typename T>
|
||||
requires std::is_assignable_v<std::string_view, T>
|
||||
inline auto coloured(T str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<const char_type *>(str, fg, bg, st);
|
||||
}
|
||||
|
||||
/// @brief Manipulator for coloured strings.
|
||||
template <typename char_type, typename traits_type, typename allocator_type>
|
||||
inline auto coloured(const std::basic_string<char_type, traits_type, allocator_type> &str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<const std::basic_string<char_type, traits_type, allocator_type> &>(str, fg, bg, st);
|
||||
}
|
||||
|
||||
/// @brief Manipulator for coloured strings.
|
||||
template <typename char_type, typename traits_type, typename allocator_type>
|
||||
inline auto coloured(std::basic_string<char_type, traits_type, allocator_type> &str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<std::basic_string<char_type, traits_type, allocator_type> &>(str, fg, bg, st);
|
||||
}
|
||||
|
||||
/// @brief Manipulator for coloured strings.
|
||||
template <typename char_type, typename traits_type>
|
||||
inline auto coloured(std::basic_string_view<char_type, traits_type> &str,
|
||||
colour::colour_type fg, colour::colour_type bg = colour::colour_type::none,
|
||||
colour::style_type st = colour::style_type::regular)
|
||||
{
|
||||
return colour::detail::coloured_string_t<std::basic_string_view<char_type, traits_type> &>(str, fg, bg, st);
|
||||
return colour::detail::coloured_string_t(str, fg, bg, st);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -320,6 +296,11 @@ class progress_bar
|
||||
*/
|
||||
void message(const std::string &inMessage);
|
||||
|
||||
/**
|
||||
* @brief Flush the progress bar to the output stream
|
||||
*/
|
||||
void flush();
|
||||
|
||||
private:
|
||||
progress_bar(const progress_bar &) = delete;
|
||||
progress_bar &operator=(const progress_bar &) = delete;
|
||||
@@ -362,6 +343,14 @@ std::unique_ptr<std::istream> load_resource(std::filesystem::path name);
|
||||
|
||||
void add_file_resource(const std::string &name, std::filesystem::path dataFile);
|
||||
|
||||
/**
|
||||
* @brief List all the file resources added with cif::add_file_resource.
|
||||
*
|
||||
* @param os The std::ostream to write the directories to
|
||||
*/
|
||||
|
||||
void list_file_resources(std::ostream &os);
|
||||
|
||||
/**
|
||||
* @brief Add a directory to the list of search directories. This list is
|
||||
* searched in a last-in-first-out order.
|
||||
@@ -376,4 +365,12 @@ void add_file_resource(const std::string &name, std::filesystem::path dataFile);
|
||||
|
||||
void add_data_directory(std::filesystem::path dataDir);
|
||||
|
||||
/**
|
||||
* @brief List all the data directories, for error reporting on missing resources.
|
||||
*
|
||||
* @param os The std::ostream to write the directories to
|
||||
*/
|
||||
|
||||
void list_data_directories(std::ostream &os);
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -26,11 +26,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <filesystem>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
@@ -46,30 +50,152 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
struct category_validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// New: error_code
|
||||
|
||||
/**
|
||||
* @brief The exception thrown when a validation error occurs
|
||||
* @enum validation_error
|
||||
*
|
||||
* @brief A stronly typed class containing the error codes reported by @ref cif::validator and friends
|
||||
*/
|
||||
enum class validation_error
|
||||
{
|
||||
value_does_not_match_rx = 1, /**< The value of an item does not conform to the regular expression specified for it */
|
||||
value_is_not_in_enumeration_list, /**< The value of an item is not in the list of values allowed */
|
||||
not_a_known_primitive_type, /**< The type is not a known primitive type */
|
||||
undefined_category, /**< Category has no definition in the dictionary */
|
||||
unknown_item, /**< The item is not defined to be part of the category */
|
||||
incorrect_item_validator, /**< Incorrectly specified validator for item */
|
||||
missing_mandatory_items, /**< Missing mandatory items */
|
||||
missing_key_items, /**< An index could not be constructed due to missing key items */
|
||||
item_not_allowed_in_category, /**< Requested item allowed in category according to dictionary */
|
||||
empty_file, /**< The file contains no datablocks */
|
||||
empty_datablock, /**< The datablock contains no categories */
|
||||
empty_category, /**< The category is empty */
|
||||
not_valid_pdbx, /**< The file is not a valid PDBx file */
|
||||
};
|
||||
/**
|
||||
* @brief The implementation for @ref validation_category error messages
|
||||
*
|
||||
*/
|
||||
class validation_error : public std::exception
|
||||
class validation_category_impl : public std::error_category
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor
|
||||
validation_error(const std::string &msg);
|
||||
/**
|
||||
* @brief User friendly name
|
||||
*
|
||||
* @return const char*
|
||||
*/
|
||||
|
||||
/// @brief Constructor
|
||||
validation_error(const std::string &cat, const std::string &item,
|
||||
const std::string &msg);
|
||||
const char *name() const noexcept override
|
||||
{
|
||||
return "cif::validation";
|
||||
}
|
||||
|
||||
/// @brief The description of the error
|
||||
const char *what() const noexcept { return m_msg.c_str(); }
|
||||
/**
|
||||
* @brief Provide the error message as a string for the error code @a ev
|
||||
*
|
||||
* @param ev The error code
|
||||
* @return std::string
|
||||
*/
|
||||
|
||||
/// @cond
|
||||
std::string m_msg;
|
||||
/// @endcond
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
switch (static_cast<validation_error>(ev))
|
||||
{
|
||||
case validation_error::value_does_not_match_rx:
|
||||
return "Value in item does not match regular expression";
|
||||
case validation_error::value_is_not_in_enumeration_list:
|
||||
return "Value is not in the enumerated list of valid values";
|
||||
case validation_error::not_a_known_primitive_type:
|
||||
return "The type is not a known primitive type";
|
||||
case validation_error::undefined_category:
|
||||
return "Category has no definition in the dictionary";
|
||||
case validation_error::unknown_item:
|
||||
return "Item is not defined to be part of the category";
|
||||
case validation_error::incorrect_item_validator:
|
||||
return "Incorrectly specified validator for item";
|
||||
case validation_error::missing_mandatory_items:
|
||||
return "Missing mandatory items";
|
||||
case validation_error::missing_key_items:
|
||||
return "An index could not be constructed due to missing key items";
|
||||
case validation_error::item_not_allowed_in_category:
|
||||
return "Requested item not allowed in category according to dictionary";
|
||||
case validation_error::empty_file:
|
||||
return "The file contains no datablocks";
|
||||
case validation_error::empty_datablock:
|
||||
return "The datablock contains no categories";
|
||||
case validation_error::empty_category:
|
||||
return "The category is empty";
|
||||
case validation_error::not_valid_pdbx:
|
||||
return "The file is not a valid PDBx file";
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return "unknown error code";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return whether two error codes are equivalent, always false in this case
|
||||
*
|
||||
*/
|
||||
|
||||
bool equivalent(const std::error_code & /*code*/, int /*condition*/) const noexcept override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Return the implementation for the validation_category
|
||||
*
|
||||
* @return std::error_category&
|
||||
*/
|
||||
inline std::error_category &validation_category()
|
||||
{
|
||||
static validation_category_impl instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline std::error_code make_error_code(validation_error e)
|
||||
{
|
||||
return std::error_code(static_cast<int>(e), validation_category());
|
||||
}
|
||||
|
||||
inline std::error_condition make_error_condition(validation_error e)
|
||||
{
|
||||
return std::error_condition(static_cast<int>(e), validation_category());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class validation_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
validation_exception(validation_error err)
|
||||
: validation_exception(make_error_code(err))
|
||||
{
|
||||
}
|
||||
|
||||
validation_exception(validation_error err, std::string_view category)
|
||||
: validation_exception(make_error_code(err), category)
|
||||
{
|
||||
}
|
||||
|
||||
validation_exception(validation_error err, std::string_view category, std::string_view item)
|
||||
: validation_exception(make_error_code(err), category, item)
|
||||
{
|
||||
}
|
||||
|
||||
validation_exception(std::error_code ec);
|
||||
|
||||
validation_exception(std::error_code ec, std::string_view category);
|
||||
|
||||
validation_exception(std::error_code ec, std::string_view category, std::string_view item);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -85,6 +211,9 @@ enum class DDL_PrimitiveType
|
||||
/// @brief Return the DDL_PrimitiveType encoded in @a s
|
||||
DDL_PrimitiveType map_to_primitive_type(std::string_view s);
|
||||
|
||||
/// @brief Return the DDL_PrimitiveType encoded in @a s, error reporting variant
|
||||
DDL_PrimitiveType map_to_primitive_type(std::string_view s, std::error_code &ec) noexcept;
|
||||
|
||||
struct regex_impl;
|
||||
|
||||
/**
|
||||
@@ -101,38 +230,39 @@ struct type_validator
|
||||
{
|
||||
std::string m_name; ///< The name of the type
|
||||
DDL_PrimitiveType m_primitive_type; ///< The primitive_type of the type
|
||||
regex_impl *m_rx; ///< The regular expression for the type
|
||||
std::shared_ptr<regex_impl> m_rx; ///< The regular expression for the type
|
||||
|
||||
type_validator() = delete;
|
||||
|
||||
/// @brief Constructor
|
||||
type_validator(std::string_view name, DDL_PrimitiveType type, std::string_view rx);
|
||||
|
||||
type_validator(const type_validator &) = delete;
|
||||
|
||||
/// @brief Copy constructor
|
||||
type_validator(type_validator &&rhs)
|
||||
: m_name(std::move(rhs.m_name))
|
||||
, m_primitive_type(rhs.m_primitive_type)
|
||||
{
|
||||
m_rx = std::exchange(rhs.m_rx, nullptr);
|
||||
}
|
||||
|
||||
type_validator &operator=(const type_validator &) = delete;
|
||||
type_validator(const type_validator &tv);
|
||||
|
||||
/// @brief Move constructor
|
||||
type_validator &operator=(type_validator &&rhs)
|
||||
type_validator(type_validator &&rhs)
|
||||
{
|
||||
m_name = std::move(rhs.m_name);
|
||||
m_primitive_type = rhs.m_primitive_type;
|
||||
m_rx = std::exchange(rhs.m_rx, nullptr);
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// @brief Move constructor
|
||||
type_validator &operator=(type_validator rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
~type_validator();
|
||||
|
||||
friend void swap(type_validator &a, type_validator &b)
|
||||
{
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_primitive_type, b.m_primitive_type);
|
||||
std::swap(a.m_rx, b.m_rx);
|
||||
}
|
||||
|
||||
/// @brief Return the sorting order
|
||||
bool operator<(const type_validator &rhs) const
|
||||
{
|
||||
@@ -146,6 +276,26 @@ struct type_validator
|
||||
int compare(std::string_view a, std::string_view b) const;
|
||||
};
|
||||
|
||||
/** @brief Item alias, items can be renamed over time
|
||||
*/
|
||||
|
||||
struct item_alias
|
||||
{
|
||||
item_alias(const std::string &alias_name, const std::string &dictionary, const std::string &version)
|
||||
: m_name(alias_name)
|
||||
, m_dict(dictionary)
|
||||
, m_vers(version)
|
||||
{
|
||||
}
|
||||
|
||||
item_alias(const item_alias &) = default;
|
||||
item_alias &operator=(const item_alias &) = default;
|
||||
|
||||
std::string m_name; ///< The alias_name
|
||||
std::string m_dict; ///< The dictionary in which it was known
|
||||
std::string m_vers; ///< The version of the dictionary
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An item_validator binds a type_validator to an item in
|
||||
* a category along with other information found in the dictionary.
|
||||
@@ -157,28 +307,32 @@ struct type_validator
|
||||
*/
|
||||
struct item_validator
|
||||
{
|
||||
std::string m_tag; ///< The item name
|
||||
bool m_mandatory; ///< Flag indicating this item is mandatory
|
||||
const type_validator *m_type; ///< The type for this item
|
||||
cif::iset m_enums; ///< If filled, the set of allowed values
|
||||
std::string m_default; ///< If filled, a default value for this item
|
||||
category_validator *m_category = nullptr; ///< The category_validator this item_validator belongs to
|
||||
std::string m_item_name; ///< The item name
|
||||
bool m_mandatory; ///< Flag indicating this item is mandatory
|
||||
const type_validator *m_type; ///< The type for this item
|
||||
cif::iset m_enums; ///< If filled, the set of allowed values
|
||||
std::string m_default; ///< If filled, a default value for this item
|
||||
std::string m_category; ///< The category this item_validator belongs to
|
||||
std::vector<item_alias> m_aliases; ///< The aliases for this item
|
||||
|
||||
/// @brief Compare based on the name
|
||||
bool operator<(const item_validator &rhs) const
|
||||
{
|
||||
return icompare(m_tag, rhs.m_tag) < 0;
|
||||
return icompare(m_item_name, rhs.m_item_name) < 0;
|
||||
}
|
||||
|
||||
/// @brief Compare based on the name
|
||||
bool operator==(const item_validator &rhs) const
|
||||
{
|
||||
return iequals(m_tag, rhs.m_tag);
|
||||
return iequals(m_item_name, rhs.m_item_name);
|
||||
}
|
||||
|
||||
/// @brief Validate the value in @a value for this item
|
||||
/// Will throw a validation_error exception if it fails
|
||||
void operator()(std::string_view value) const;
|
||||
/// Will throw a std::system_error exception if it fails
|
||||
void operator()(const item_value &value) const;
|
||||
|
||||
/// @brief A more gentle version of value validation
|
||||
bool validate_value(const item_value &value, std::error_code &ec) const noexcept;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -191,8 +345,8 @@ struct category_validator
|
||||
{
|
||||
std::string m_name; ///< The name of the category
|
||||
std::vector<std::string> m_keys; ///< The list of items that make up the key
|
||||
cif::iset m_groups; ///< The category groups this category belongs to
|
||||
cif::iset m_mandatory_fields; ///< The mandatory fields for this category
|
||||
cif::iset m_groups; ///< The category groups this category belongs to
|
||||
cif::iset m_mandatory_items; ///< The mandatory items for this category
|
||||
std::set<item_validator> m_item_validators; ///< The item validators for the items in this category
|
||||
|
||||
/// @brief return true if this category sorts before @a rhs
|
||||
@@ -202,10 +356,13 @@ struct category_validator
|
||||
}
|
||||
|
||||
/// @brief Add item_validator @a v to the list of item validators
|
||||
void addItemValidator(item_validator &&v);
|
||||
void add_item_validator(item_validator &&v);
|
||||
|
||||
/// @brief Return the item_validator for item @a tag, may return nullptr
|
||||
const item_validator *get_validator_for_item(std::string_view tag) const;
|
||||
/// @brief Return the item_validator for item @a item_name, may return nullptr
|
||||
const item_validator *get_validator_for_item(std::string_view item_name) const;
|
||||
|
||||
/// @brief Return the item_validator for an item that has as alias name @a item_name, may return nullptr
|
||||
const item_validator *get_validator_for_aliased_item(std::string_view item_name) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -243,24 +400,48 @@ class validator
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
*/
|
||||
validator(std::string_view name)
|
||||
: m_name(name)
|
||||
validator()
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param name The name of the underlying dictionary
|
||||
* @param is The data to parse
|
||||
*/
|
||||
validator(std::istream &is)
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
parse(is);
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
~validator() = default;
|
||||
|
||||
validator(const validator &rhs) = delete;
|
||||
validator &operator=(const validator &rhs) = delete;
|
||||
validator(const validator &rhs);
|
||||
|
||||
/// @brief move constructor
|
||||
validator(validator &&rhs) = default;
|
||||
validator(validator &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// @brief move assignment operator
|
||||
validator &operator=(validator &&rhs) = default;
|
||||
validator &operator=(validator rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend void swap(validator &a, validator &b) noexcept;
|
||||
|
||||
friend class dictionary_parser;
|
||||
friend class validator_factory;
|
||||
|
||||
/// @brief Parse dictionary in @a is and put content in this validator, optionally extending it
|
||||
/// @param is The stream containing a valid cif dictionary
|
||||
void parse(std::istream &is);
|
||||
|
||||
/// @brief Add type_validator @a v to the list of type validators
|
||||
void add_type_validator(type_validator &&v);
|
||||
@@ -284,20 +465,41 @@ class validator
|
||||
std::vector<const link_validator *> get_links_for_child(std::string_view category) const;
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(const std::string &msg, bool fatal) const;
|
||||
void report_error(validation_error err, bool fatal = true) const
|
||||
{
|
||||
report_error(make_error_code(err), fatal);
|
||||
}
|
||||
|
||||
const std::string &name() const { return m_name; } ///< Get the name of this validator
|
||||
void set_name(const std::string &name) { m_name = name; } ///< Set the name of this validator
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(std::error_code ec, bool fatal = true) const;
|
||||
|
||||
const std::string &version() const { return m_version; } ///< Get the version of this validator
|
||||
void set_version(const std::string &version) { m_version = version; } ///< Set the version of this validator
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(validation_error err, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const
|
||||
{
|
||||
report_error(make_error_code(err), category, item, fatal);
|
||||
}
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(std::error_code ec, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const;
|
||||
|
||||
/// @brief Write out the audit_conform data for this validator
|
||||
/// @param audit_conform
|
||||
void fill_audit_conform(category &audit_conform) const;
|
||||
|
||||
/// @brief Return true if this validator matches @a audit_conform
|
||||
bool matches_audit_conform(const category &audit_conform) const;
|
||||
|
||||
/// @brief Add info
|
||||
void append_audit_conform(const std::string &name, const std::optional<std::string> &version);
|
||||
|
||||
private:
|
||||
// name is fully qualified here:
|
||||
item_validator *get_validator_for_item(std::string_view name) const;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_version;
|
||||
category m_audit_conform;
|
||||
|
||||
bool m_strict = false;
|
||||
std::set<type_validator> m_type_validators;
|
||||
std::set<category_validator> m_category_validators;
|
||||
@@ -315,23 +517,30 @@ class validator_factory
|
||||
{
|
||||
public:
|
||||
/// @brief Return the singleton instance
|
||||
static validator_factory &instance()
|
||||
static validator_factory &instance();
|
||||
|
||||
/// @brief Return validator with info recorded in @a audit_conform
|
||||
const validator &get(const category &audit_conform);
|
||||
|
||||
/// @brief Return the single-file validator with name @a dictionary_name
|
||||
const validator &get(std::string_view dictionary_name);
|
||||
|
||||
/// @brief Return true if the version @a found is equal or higher than @a expected for dictionary @a name
|
||||
static bool check_version(std::string_view name, std::string_view expected, std::string_view found);
|
||||
|
||||
/// @brief Add validator @a v to the list of known validators
|
||||
const validator &add(validator &&v)
|
||||
{
|
||||
static validator_factory s_instance;
|
||||
return s_instance;
|
||||
std::unique_lock lock(m_mutex);
|
||||
return m_validators.emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
/// @brief Return the validator with name @a dictionary_name
|
||||
const validator &operator[](std::string_view dictionary_name);
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is
|
||||
const validator &construct_validator(std::string_view name, std::istream &is);
|
||||
|
||||
private:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
validator_factory() = default;
|
||||
|
||||
/// @brief Construct a new validator with name @a name from the data in @a is with at least version @a version if specified
|
||||
validator construct_validator(std::string_view name, std::optional<std::string> version);
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::list<validator> m_validators;
|
||||
};
|
||||
|
||||
316
pcre2-simple/CMakeLists.txt
Normal file
316
pcre2-simple/CMakeLists.txt
Normal file
@@ -0,0 +1,316 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2025 Maarten L. Hekkelman
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# A simplified wrapper CMakeLists.txt file for PCRE2
|
||||
#
|
||||
# This will generate an OBJECT library so it can be linked into another library
|
||||
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
project(pcre2s VERSION 1.0.0 LANGUAGES C CXX)
|
||||
|
||||
# The original code:
|
||||
|
||||
file(DOWNLOAD https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.46/pcre2-10.46.tar.gz
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2-code.tgz
|
||||
EXPECTED_HASH SHA256=8d28d7f2c3b970c3a4bf3776bcbb5adfc923183ce74bc8df1ebaad8c1985bd07)
|
||||
file(ARCHIVE_EXTRACT INPUT ${CMAKE_CURRENT_BINARY_DIR}/pcre2-code.tgz
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(PCRE2_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/pcre2-10.46)
|
||||
set(PCRE2_MAJOR 10)
|
||||
set(PCRE2_MINOR 46)
|
||||
set(PCRE2_VERSION "${PCRE2_MAJOR}.${PCRE2_MINOR}")
|
||||
set(PCRE2_DATE "2024-06-09")
|
||||
|
||||
# Some needed configuration options
|
||||
|
||||
# option(PCRE2_BUILD_PCRE2_8 "Build 8 bit PCRE2 library" ON)
|
||||
# option(PCRE2_BUILD_PCRE2_16 "Build 16 bit PCRE2 library" OFF)
|
||||
# option(PCRE2_BUILD_PCRE2_32 "Build 32 bit PCRE2 library" OFF)
|
||||
|
||||
option(PCRE2_STATIC_PIC "Build the static library with the option position independent code enabled." OFF)
|
||||
|
||||
set(PCRE2_NEWLINE "LF" CACHE STRING "What to recognize as a newline (one of CR, LF, CRLF, ANY, ANYCRLF, NUL)." FORCE)
|
||||
set_property(CACHE PCRE2_NEWLINE PROPERTY STRINGS "CR" "LF" "CRLF" "ANY" "ANYCRLF" "NUL")
|
||||
|
||||
set(PCRE2_LINK_SIZE "2" CACHE STRING "Internal link size (2, 3 or 4 allowed). See LINK_SIZE in config.h.in for details.")
|
||||
set_property(CACHE PCRE2_LINK_SIZE PROPERTY STRINGS "2" "3" "4")
|
||||
|
||||
set(PCRE2_PARENS_NEST_LIMIT "250" CACHE STRING "Default nested parentheses limit. See PARENS_NEST_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_HEAP_LIMIT "20000000" CACHE STRING "Default limit on heap memory (kibibytes). See HEAP_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_MAX_VARLOOKBEHIND "255" CACHE STRING "Default limit on variable lookbehinds.")
|
||||
set(PCRE2_MATCH_LIMIT "10000000" CACHE STRING "Default limit on internal looping. See MATCH_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_MATCH_LIMIT_DEPTH "MATCH_LIMIT" CACHE STRING "Default limit on internal depth of search. See MATCH_LIMIT_DEPTH in config.h.in for details.")
|
||||
set(PCRE2GREP_BUFSIZE "20480" CACHE STRING "Buffer starting size parameter for pcre2grep. See PCRE2GREP_BUFSIZE in config.h.in for details.")
|
||||
set(PCRE2GREP_MAX_BUFSIZE "1048576" CACHE STRING "Buffer maximum size parameter for pcre2grep. See PCRE2GREP_MAX_BUFSIZE in config.h.in for details.")
|
||||
set(PCRE2_SUPPORT_JIT OFF CACHE BOOL "Enable support for Just-in-time compiling.")
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES Linux|NetBSD)
|
||||
set(PCRE2_SUPPORT_JIT_SEALLOC OFF CACHE BOOL "Enable SELinux compatible execmem allocator in JIT (experimental).")
|
||||
else()
|
||||
set(PCRE2_SUPPORT_JIT_SEALLOC IGNORE)
|
||||
endif()
|
||||
|
||||
set(PCRE2GREP_SUPPORT_JIT ON CACHE BOOL "Enable use of Just-in-time compiling in pcre2grep.")
|
||||
set(PCRE2GREP_SUPPORT_CALLOUT ON CACHE BOOL "Enable callout string support in pcre2grep.")
|
||||
set(PCRE2GREP_SUPPORT_CALLOUT_FORK ON CACHE BOOL "Enable callout string fork support in pcre2grep.")
|
||||
set(PCRE2_SUPPORT_UNICODE ON CACHE BOOL "Enable support for Unicode and UTF-8/UTF-16/UTF-32 encoding.")
|
||||
set(PCRE2_SUPPORT_BSR_ANYCRLF OFF CACHE BOOL "ON=Backslash-R matches only LF CR and CRLF, OFF=Backslash-R matches all Unicode Linebreaks")
|
||||
set(PCRE2_NEVER_BACKSLASH_C OFF CACHE BOOL "If ON, backslash-C (upper case C) is locked out.")
|
||||
set(PCRE2_SUPPORT_VALGRIND OFF CACHE BOOL "Enable Valgrind support.")
|
||||
|
||||
if(MINGW)
|
||||
option(NON_STANDARD_LIB_PREFIX "ON=Shared libraries built in mingw will be named pcre2.dll, etc., instead of libpcre2.dll, etc." OFF)
|
||||
option(NON_STANDARD_LIB_SUFFIX "ON=Shared libraries built in mingw will be named libpcre2-0.dll, etc., instead of libpcre2.dll, etc." OFF)
|
||||
endif()
|
||||
|
||||
#
|
||||
|
||||
set(NEWLINE_DEFAULT "")
|
||||
|
||||
if(PCRE2_NEWLINE STREQUAL "CR")
|
||||
set(NEWLINE_DEFAULT "1")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "LF")
|
||||
set(NEWLINE_DEFAULT "2")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "CRLF")
|
||||
set(NEWLINE_DEFAULT "3")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "ANY")
|
||||
set(NEWLINE_DEFAULT "4")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "ANYCRLF")
|
||||
set(NEWLINE_DEFAULT "5")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "NUL")
|
||||
set(NEWLINE_DEFAULT "6")
|
||||
else()
|
||||
message(FATAL_ERROR "The PCRE2_NEWLINE variable must be set to one of the following values: \"LF\", \"CR\", \"CRLF\", \"ANY\", \"ANYCRLF\".")
|
||||
endif()
|
||||
|
||||
# Some tests
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckIncludeFile)
|
||||
|
||||
check_include_file(assert.h HAVE_ASSERT_H)
|
||||
check_include_file(dirent.h HAVE_DIRENT_H)
|
||||
check_include_file(sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
check_include_file(windows.h HAVE_WINDOWS_H)
|
||||
|
||||
check_symbol_exists(bcopy "strings.h" HAVE_BCOPY)
|
||||
check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
|
||||
check_symbol_exists(memmove "string.h" HAVE_MEMMOVE)
|
||||
check_symbol_exists(secure_getenv "stdlib.h" HAVE_SECURE_GETENV)
|
||||
check_symbol_exists(strerror "string.h" HAVE_STRERROR)
|
||||
|
||||
check_c_source_compiles(
|
||||
"int main(void) { char buf[128] __attribute__((uninitialized)); (void)buf; return 0; }"
|
||||
HAVE_ATTRIBUTE_UNINITIALIZED
|
||||
)
|
||||
|
||||
check_c_source_compiles(
|
||||
[=[
|
||||
extern __attribute__ ((visibility ("default"))) int f(void);
|
||||
int main(void) { return f(); }
|
||||
int f(void) { return 42; }
|
||||
]=]
|
||||
HAVE_VISIBILITY
|
||||
)
|
||||
|
||||
if(HAVE_VISIBILITY)
|
||||
set(PCRE2_EXPORT [=[__attribute__ ((visibility ("default")))]=])
|
||||
else()
|
||||
set(PCRE2_EXPORT)
|
||||
endif()
|
||||
|
||||
check_c_source_compiles("int main(void) { __assume(1); return 0; }" HAVE_BUILTIN_ASSUME)
|
||||
|
||||
check_c_source_compiles(
|
||||
[=[
|
||||
#include <stddef.h>
|
||||
int main(void) { int a,b; size_t m; __builtin_mul_overflow(a,b,&m); return 0; }
|
||||
]=]
|
||||
HAVE_BUILTIN_MUL_OVERFLOW
|
||||
)
|
||||
|
||||
check_c_source_compiles(
|
||||
"int main(int c, char *v[]) { if (c) __builtin_unreachable(); return (int)(*v[0]); }"
|
||||
HAVE_BUILTIN_UNREACHABLE
|
||||
)
|
||||
|
||||
# # Check whether Intel CET is enabled, and if so, adjust compiler flags. This
|
||||
# # code was written by PH, trying to imitate the logic from the autotools
|
||||
# # configuration.
|
||||
|
||||
# check_c_source_compiles(
|
||||
# [=[
|
||||
# #ifndef __CET__
|
||||
# #error CET is not enabled
|
||||
# #endif
|
||||
# int main() { return 0; }
|
||||
# ]=]
|
||||
# INTEL_CET_ENABLED
|
||||
# )
|
||||
|
||||
# if(INTEL_CET_ENABLED)
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mshstk")
|
||||
# endif()
|
||||
|
||||
# Set up some dependencies first
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_chartables.c.dist
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2_chartables.c
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/config-cmake.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/config.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/pcre2.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
# Define our library
|
||||
|
||||
list(APPEND PCRE2_HEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/pcre2.h)
|
||||
|
||||
list(APPEND PCRE2_SOURCES
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_auto_possess.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2_chartables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_chkdint.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_compile.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_compile_class.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_config.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_context.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_convert.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_dfa_match.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_error.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_extuni.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_find_bracket.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_jit_compile.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_maketables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_match.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_match_data.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_newline.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_ord2utf.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_pattern_info.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_script_run.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_serialize.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_string_utils.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_study.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_substitute.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_substring.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_tables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_ucd.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_valid_utf.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_xclass.c
|
||||
)
|
||||
|
||||
add_library(pcre2s OBJECT)
|
||||
|
||||
target_sources(pcre2s
|
||||
PRIVATE ${PCRE2_SOURCES}
|
||||
PUBLIC
|
||||
FILE_SET pcre2_headers TYPE HEADERS
|
||||
BASE_DIRS ${PCRE2_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/interface
|
||||
FILES ${PCRE2_HEADERS}
|
||||
)
|
||||
|
||||
target_compile_definitions(pcre2s PUBLIC PCRE2_CODE_UNIT_WIDTH=8 HAVE_CONFIG_H)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(pcre2s PUBLIC PCRE2_STATIC)
|
||||
endif()
|
||||
|
||||
target_include_directories(pcre2s PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/interface ${PCRE2_SOURCE_DIR}/src)
|
||||
|
||||
if(PCRE2_STATIC_PIC)
|
||||
set_target_properties(pcre2s PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||
endif()
|
||||
|
||||
# # Installation and config files
|
||||
|
||||
# include(CMakePackageConfigHelpers)
|
||||
# include(GenerateExportHeader)
|
||||
|
||||
# # Install rules
|
||||
# install(TARGETS pcre2s
|
||||
# EXPORT pcre2s
|
||||
# FILE_SET pcre2_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# if(MSVC AND BUILD_SHARED_LIBS)
|
||||
# install(
|
||||
# FILES $<TARGET_PDB_FILE:pcre2s>
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
# OPTIONAL)
|
||||
# endif()
|
||||
|
||||
# install(EXPORT pcre2s
|
||||
# NAMESPACE pcre2s::
|
||||
# FILE "pcre2s-targets.cmake"
|
||||
# DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# configure_package_config_file(
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/pcre2s-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config.cmake
|
||||
# INSTALL_DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# install(
|
||||
# FILES "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config.cmake"
|
||||
# "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config-version.cmake"
|
||||
# DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# set_target_properties(
|
||||
# pcre2s
|
||||
# PROPERTIES VERSION ${PCRE2_VERSION}
|
||||
# SOVERSION ${PCRE2_VERSION}
|
||||
# INTERFACE_pcre2s_MAJOR_VERSION ${PCRE2_MAJOR})
|
||||
|
||||
# set_property(
|
||||
# TARGET pcre2s
|
||||
# APPEND
|
||||
# PROPERTY COMPATIBLE_INTERFACE_STRING pcre2s_MAJOR_VERSION)
|
||||
|
||||
# write_basic_package_version_file(
|
||||
# "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config-version.cmake"
|
||||
# VERSION "${PCRE2_VERSION}"
|
||||
# COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
# # Testing
|
||||
|
||||
# if(PROJECT_IS_TOP_LEVEL)
|
||||
# include(CTest)
|
||||
|
||||
# if(BUILD_TESTING)
|
||||
# add_subdirectory(test)
|
||||
# endif()
|
||||
# endif()
|
||||
@@ -1,69 +0,0 @@
|
||||
# Copyright 2018 Mike Dev
|
||||
# Copyright 2019 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
# We support CMake 3.5, but prefer 3.16 policies and behavior
|
||||
cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_regex VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_regex INTERFACE)
|
||||
add_library(Boost::regex ALIAS boost_regex)
|
||||
|
||||
target_include_directories(boost_regex INTERFACE include)
|
||||
|
||||
option(BOOST_REGEX_STANDALONE "Boost.Regex: Enable Standalone Mode (i.e. no Boost dependencies)")
|
||||
|
||||
if(NOT BOOST_REGEX_STANDALONE)
|
||||
|
||||
target_link_libraries(boost_regex
|
||||
INTERFACE
|
||||
Boost::config
|
||||
Boost::throw_exception
|
||||
Boost::predef
|
||||
Boost::assert
|
||||
)
|
||||
|
||||
else()
|
||||
|
||||
target_compile_definitions(boost_regex
|
||||
INTERFACE BOOST_REGEX_STANDALONE
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
find_package(ICU COMPONENTS data i18n uc QUIET)
|
||||
#option(BOOST_REGEX_ENABLE_ICU "Boost.Regex: enable ICU support" ${ICU_FOUND})
|
||||
|
||||
if(ICU_FOUND)
|
||||
|
||||
add_library(boost_regex_icu INTERFACE)
|
||||
add_library(Boost::regex_icu ALIAS boost_regex_icu)
|
||||
|
||||
target_include_directories(boost_regex_icu INTERFACE include)
|
||||
|
||||
if(NOT BOOST_REGEX_STANDALONE)
|
||||
|
||||
target_link_libraries(boost_regex_icu
|
||||
INTERFACE
|
||||
Boost::config
|
||||
Boost::throw_exception
|
||||
Boost::predef
|
||||
Boost::assert
|
||||
)
|
||||
|
||||
else()
|
||||
|
||||
target_compile_definitions(boost_regex_icu
|
||||
INTERFACE BOOST_REGEX_STANDALONE
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
find_package(ICU COMPONENTS data i18n uc REQUIRED)
|
||||
|
||||
target_link_libraries(boost_regex_icu INTERFACE ICU::data ICU::i18n ICU::uc)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,47 +0,0 @@
|
||||
Boost Regex Library
|
||||
============================
|
||||
|
||||
The Boost Regex library provides regular expression support for C++, this library is the ancestor to std::regex and still goes beyond
|
||||
and offers some advantages to, the standard version.
|
||||
|
||||
The full documentation is available on [boost.org](http://www.boost.org/doc/libs/release/libs/regex/index.html).
|
||||
|
||||
## Standalone Mode ##
|
||||
|
||||
This library may now be used in "standalone" mode without the rest of the Boost C++ libraries, in order to do this you must either:
|
||||
|
||||
* Have a C++17 compiler that supports __has_include, in this case if <boost/config.hpp> is not present then the library will automoatically enter standalone mode. Or:
|
||||
* Define BOOST_REGEX_STANDALONE when building.
|
||||
|
||||
The main difference between the 2 modes, is that when Boost.Config is present the library will automatically configure itself around various compiler defects. In particular in order to use the library with exception support turned off, you will either need a copy of Boost.Config in your include path, or else manually define BOOST_NO_EXCEPTIONS when building.
|
||||
|
||||
In any event, to obtain a standalone version of this library, simply download a .zip of the "master" branch of this repository.
|
||||
|
||||
## Support, bugs and feature requests ##
|
||||
|
||||
Bugs and feature requests can be reported through the [Gitub issue tracker](https://github.com/boostorg/regex/issues)
|
||||
(see [open issues](https://github.com/boostorg/regex/issues) and
|
||||
[closed issues](https://github.com/boostorg/regex/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aclosed)).
|
||||
|
||||
You can submit your changes through a [pull request](https://github.com/boostorg/regex/pulls).
|
||||
|
||||
There is no mailing-list specific to Boost Regex, although you can use the general-purpose Boost [mailing-list](http://lists.boost.org/mailman/listinfo.cgi/boost-users) using the tag [regex].
|
||||
|
||||
|
||||
## Development ##
|
||||
|
||||
Clone the whole boost project, which includes the individual Boost projects as submodules ([see boost+git doc](https://github.com/boostorg/boost/wiki/Getting-Started)):
|
||||
|
||||
git clone https://github.com/boostorg/boost
|
||||
cd boost
|
||||
git submodule update --init
|
||||
|
||||
The Boost Regex Library is located in `libs/regex/`.
|
||||
|
||||
### Running tests ###
|
||||
First, make sure you are in `libs/regex/test`.
|
||||
You can either run all the tests listed in `Jamfile.v2` or run a single test:
|
||||
|
||||
../../../b2 <- run all tests
|
||||
../../../b2 regex_regress <- single test
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org/libs/regex for most recent version.
|
||||
* FILE cregex.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares POSIX API functions
|
||||
* + boost::RegEx high level wrapper.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_CREGEX_HPP
|
||||
#define BOOST_RE_CREGEX_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#include <boost/regex/v4/cregex.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/cregex.hpp>
|
||||
#endif
|
||||
|
||||
#endif /* include guard */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2000
|
||||
* Dr John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org/libs/regex for documentation.
|
||||
* FILE regex.h
|
||||
* VERSION 3.12
|
||||
* DESCRIPTION: Declares POSIX API functions
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_REGEX_H
|
||||
#define BOOST_RE_REGEX_H
|
||||
|
||||
#include <boost/cregex.hpp>
|
||||
|
||||
/*
|
||||
* add using declarations to bring POSIX API functions into
|
||||
* global scope, only if this is C++ (and not C).
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
using boost::regoff_t;
|
||||
using boost::regex_tA;
|
||||
using boost::regmatch_t;
|
||||
using boost::REG_BASIC;
|
||||
using boost::REG_EXTENDED;
|
||||
using boost::REG_ICASE;
|
||||
using boost::REG_NOSUB;
|
||||
using boost::REG_NEWLINE;
|
||||
using boost::REG_NOSPEC;
|
||||
using boost::REG_PEND;
|
||||
using boost::REG_DUMP;
|
||||
using boost::REG_NOCOLLATE;
|
||||
using boost::REG_ESCAPE_IN_LISTS;
|
||||
using boost::REG_NEWLINE_ALT;
|
||||
using boost::REG_PERL;
|
||||
using boost::REG_AWK;
|
||||
using boost::REG_GREP;
|
||||
using boost::REG_EGREP;
|
||||
using boost::REG_ASSERT;
|
||||
using boost::REG_INVARG;
|
||||
using boost::REG_ATOI;
|
||||
using boost::REG_ITOA;
|
||||
|
||||
using boost::REG_NOTBOL;
|
||||
using boost::REG_NOTEOL;
|
||||
using boost::REG_STARTEND;
|
||||
|
||||
using boost::reg_comp_flags;
|
||||
using boost::reg_exec_flags;
|
||||
using boost::regcompA;
|
||||
using boost::regerrorA;
|
||||
using boost::regexecA;
|
||||
using boost::regfreeA;
|
||||
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
using boost::regcompW;
|
||||
using boost::regerrorW;
|
||||
using boost::regexecW;
|
||||
using boost::regfreeW;
|
||||
using boost::regex_tW;
|
||||
#endif
|
||||
|
||||
using boost::REG_NOERROR;
|
||||
using boost::REG_NOMATCH;
|
||||
using boost::REG_BADPAT;
|
||||
using boost::REG_ECOLLATE;
|
||||
using boost::REG_ECTYPE;
|
||||
using boost::REG_EESCAPE;
|
||||
using boost::REG_ESUBREG;
|
||||
using boost::REG_EBRACK;
|
||||
using boost::REG_EPAREN;
|
||||
using boost::REG_EBRACE;
|
||||
using boost::REG_BADBR;
|
||||
using boost::REG_ERANGE;
|
||||
using boost::REG_ESPACE;
|
||||
using boost::REG_BADRPT;
|
||||
using boost::REG_EEND;
|
||||
using boost::REG_ESIZE;
|
||||
using boost::REG_ERPAREN;
|
||||
using boost::REG_EMPTY;
|
||||
using boost::REG_E_MEMORY;
|
||||
using boost::REG_E_UNKNOWN;
|
||||
using boost::reg_errcode_t;
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BOOST_RE_REGEX_H */
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org/libs/regex for documentation.
|
||||
* FILE regex.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares boost::basic_regex<> and associated
|
||||
* functions and classes. This header is the main
|
||||
* entry point for the template regex code.
|
||||
*/
|
||||
|
||||
|
||||
/* start with C compatibility API */
|
||||
|
||||
#ifndef BOOST_RE_REGEX_HPP
|
||||
#define BOOST_RE_REGEX_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#include <boost/regex/v4/regex.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/regex.hpp>
|
||||
#endif
|
||||
|
||||
#endif // include
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,480 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE config.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: regex extended config setup.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#define BOOST_REGEX_CONFIG_HPP
|
||||
|
||||
#if !((__cplusplus >= 201103L) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(BOOST_REGEX_CXX03))
|
||||
# define BOOST_REGEX_CXX03
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_CXX03)
|
||||
# define BOOST_REGEX_CXX03
|
||||
#endif
|
||||
|
||||
#if defined(__has_include)
|
||||
#if !defined(BOOST_REGEX_STANDALONE) && !__has_include(<boost/version.hpp>)
|
||||
#define BOOST_REGEX_STANDALONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Borland C++ Fix/error check
|
||||
* this has to go *before* we include any std lib headers:
|
||||
*/
|
||||
#if defined(__BORLANDC__) && !defined(__clang__)
|
||||
# include <boost/regex/config/borland.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
#include <boost/version.hpp>
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Asserts:
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
#ifdef BOOST_REGEX_STANDALONE
|
||||
#include <cassert>
|
||||
# define BOOST_REGEX_ASSERT(x) assert(x)
|
||||
#else
|
||||
#include <boost/assert.hpp>
|
||||
# define BOOST_REGEX_ASSERT(x) BOOST_ASSERT(x)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Include all the headers we need here:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# ifndef BOOST_REGEX_USER_CONFIG
|
||||
# define BOOST_REGEX_USER_CONFIG <boost/regex/user.hpp>
|
||||
# endif
|
||||
|
||||
# include BOOST_REGEX_USER_CONFIG
|
||||
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
# include <boost/config.hpp>
|
||||
# include <boost/predef.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
/*
|
||||
* C build,
|
||||
* don't include <boost/config.hpp> because that may
|
||||
* do C++ specific things in future...
|
||||
*/
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
# ifdef _MSC_VER
|
||||
# define BOOST_MSVC _MSC_VER
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Legacy support:
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#if defined(BOOST_NO_STD_LOCALE) || defined(BOOST_NO_CXX11_HDR_MUTEX) || defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) \
|
||||
|| defined(BOOST_NO_CXX11_HDR_ATOMIC) || defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_CXX11_SMART_PTR) \
|
||||
|| defined(BOOST_NO_CXX11_STATIC_ASSERT) || defined(BOOST_NO_NOEXCEPT)
|
||||
#ifndef BOOST_REGEX_CXX03
|
||||
# define BOOST_REGEX_CXX03
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Boilerplate regex config options:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Obsolete macro, use BOOST_VERSION instead: */
|
||||
#define BOOST_RE_VERSION 500
|
||||
|
||||
/* fix: */
|
||||
#if defined(_UNICODE) && !defined(UNICODE)
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#define BOOST_REGEX_JOIN(X, Y) BOOST_REGEX_DO_JOIN(X, Y)
|
||||
#define BOOST_REGEX_DO_JOIN(X, Y) BOOST_REGEX_DO_JOIN2(X,Y)
|
||||
#define BOOST_REGEX_DO_JOIN2(X, Y) X##Y
|
||||
|
||||
#ifdef BOOST_FALLTHROUGH
|
||||
# define BOOST_REGEX_FALLTHROUGH BOOST_FALLTHROUGH
|
||||
#else
|
||||
|
||||
#if defined(__clang__) && (__cplusplus >= 201103L) && defined(__has_warning)
|
||||
# if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
||||
# define BOOST_REGEX_FALLTHROUGH [[clang::fallthrough]]
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1800) && (__cplusplus >= 201703)
|
||||
# define BOOST_REGEX_FALLTHROUGH [[fallthrough]]
|
||||
#endif
|
||||
#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__GNUC__) && (__GNUC__ >= 7)
|
||||
# define BOOST_REGEX_FALLTHROUGH __attribute__((fallthrough))
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_REGEX_FALLTHROUGH)
|
||||
# define BOOST_REGEX_FALLTHROUGH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NORETURN
|
||||
# define BOOST_REGEX_NORETURN BOOST_NORETURN
|
||||
#else
|
||||
# define BOOST_REGEX_NORETURN
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define a macro for the namespace that details are placed in, this includes the Boost
|
||||
* version number to avoid mismatched header and library versions:
|
||||
*/
|
||||
#define BOOST_REGEX_DETAIL_NS BOOST_REGEX_JOIN(re_detail_, BOOST_RE_VERSION)
|
||||
|
||||
/*
|
||||
* Fix for gcc prior to 3.4: std::ctype<wchar_t> doesn't allow
|
||||
* masks to be combined, for example:
|
||||
* std::use_facet<std::ctype<wchar_t> >.is(std::ctype_base::lower|std::ctype_base::upper, L'a');
|
||||
* returns *false*.
|
||||
*/
|
||||
#if defined(__GLIBCPP__) && defined(BOOST_REGEX_CXX03)
|
||||
# define BOOST_REGEX_BUGGY_CTYPE_FACET
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there isn't good enough wide character support then there will
|
||||
* be no wide character regular expressions:
|
||||
*/
|
||||
#if (defined(BOOST_NO_CWCHAR) || defined(BOOST_NO_CWCTYPE) || defined(BOOST_NO_STD_WSTRING))
|
||||
# if !defined(BOOST_NO_WREGEX)
|
||||
# define BOOST_NO_WREGEX
|
||||
# endif
|
||||
#else
|
||||
# if defined(__sgi) && (defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION))
|
||||
/* STLPort on IRIX is misconfigured: <cwctype> does not compile
|
||||
* as a temporary fix include <wctype.h> instead and prevent inclusion
|
||||
* of STLPort version of <cwctype> */
|
||||
# include <wctype.h>
|
||||
# define __STLPORT_CWCTYPE
|
||||
# define _STLP_CWCTYPE
|
||||
# endif
|
||||
|
||||
#if defined(__cplusplus) && defined(BOOST_REGEX_CXX03)
|
||||
# include <boost/regex/config/cwchar.hpp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If Win32 support has been disabled for boost in general, then
|
||||
* it is for regex in particular:
|
||||
*/
|
||||
#if defined(BOOST_DISABLE_WIN32) && !defined(BOOST_REGEX_NO_W32)
|
||||
# define BOOST_REGEX_NO_W32
|
||||
#endif
|
||||
|
||||
/* disable our own file-iterators and mapfiles if we can't
|
||||
* support them: */
|
||||
#if defined(_WIN32)
|
||||
# if defined(BOOST_REGEX_NO_W32) || BOOST_PLAT_WINDOWS_RUNTIME
|
||||
# define BOOST_REGEX_NO_FILEITER
|
||||
# endif
|
||||
#else /* defined(_WIN32) */
|
||||
# if !defined(BOOST_HAS_DIRENT_H)
|
||||
# define BOOST_REGEX_NO_FILEITER
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* backwards compatibitity: */
|
||||
#if defined(BOOST_RE_NO_LIB)
|
||||
# define BOOST_REGEX_NO_LIB
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(_MSC_VER) && (defined(_WIN32) || defined(__CYGWIN__))
|
||||
/* gcc on win32 has problems if you include <windows.h>
|
||||
(sporadically generates bad code). */
|
||||
# define BOOST_REGEX_NO_W32
|
||||
#endif
|
||||
#if defined(__COMO__) && !defined(BOOST_REGEX_NO_W32) && !defined(_MSC_EXTENSIONS)
|
||||
# define BOOST_REGEX_NO_W32
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_STANDALONE
|
||||
# if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
|
||||
# define BOOST_REGEX_MSVC _MSC_VER
|
||||
#endif
|
||||
#elif defined(BOOST_MSVC)
|
||||
# define BOOST_REGEX_MSVC BOOST_MSVC
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Set up dll import/export options:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if (defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_REGEX_STATIC_LINK) && defined(BOOST_SYMBOL_IMPORT)
|
||||
# if defined(BOOST_REGEX_SOURCE)
|
||||
# define BOOST_REGEX_BUILD_DLL
|
||||
# define BOOST_REGEX_DECL BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_REGEX_DECL BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_REGEX_DECL
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#if !defined(BOOST_REGEX_NO_LIB) && !defined(BOOST_REGEX_SOURCE) && !defined(BOOST_ALL_NO_LIB) && defined(__cplusplus)
|
||||
# define BOOST_LIB_NAME boost_regex
|
||||
# if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
# endif
|
||||
# ifdef BOOST_REGEX_DIAG
|
||||
# define BOOST_LIB_DIAGNOSTIC
|
||||
# endif
|
||||
# include <boost/config/auto_link.hpp>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Set up function call type:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(_MSC_VER) && defined(_MSC_EXTENSIONS)
|
||||
#if defined(_DEBUG) || defined(__MSVC_RUNTIME_CHECKS) || defined(_MANAGED) || defined(BOOST_REGEX_NO_FASTCALL)
|
||||
# define BOOST_REGEX_CALL __cdecl
|
||||
#else
|
||||
# define BOOST_REGEX_CALL __fastcall
|
||||
#endif
|
||||
# define BOOST_REGEX_CCALL __cdecl
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__) && !defined(BOOST_DISABLE_WIN32)
|
||||
#if defined(__clang__)
|
||||
# define BOOST_REGEX_CALL __cdecl
|
||||
# define BOOST_REGEX_CCALL __cdecl
|
||||
#else
|
||||
# define BOOST_REGEX_CALL __fastcall
|
||||
# define BOOST_REGEX_CCALL __stdcall
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_REGEX_CALL
|
||||
# define BOOST_REGEX_CALL
|
||||
#endif
|
||||
#ifndef BOOST_REGEX_CCALL
|
||||
#define BOOST_REGEX_CCALL
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Set up localisation model:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* backwards compatibility: */
|
||||
#ifdef BOOST_RE_LOCALE_C
|
||||
# define BOOST_REGEX_USE_C_LOCALE
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_RE_LOCALE_CPP
|
||||
# define BOOST_REGEX_USE_CPP_LOCALE
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
# define BOOST_REGEX_USE_C_LOCALE
|
||||
#endif
|
||||
|
||||
/* use C++ locale when targeting windows store */
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
# define BOOST_REGEX_USE_CPP_LOCALE
|
||||
# define BOOST_REGEX_NO_WIN32_LOCALE
|
||||
#endif
|
||||
|
||||
/* Win32 defaults to native Win32 locale: */
|
||||
#if defined(_WIN32) && \
|
||||
!defined(BOOST_REGEX_USE_WIN32_LOCALE) && \
|
||||
!defined(BOOST_REGEX_USE_C_LOCALE) && \
|
||||
!defined(BOOST_REGEX_USE_CPP_LOCALE) && \
|
||||
!defined(BOOST_REGEX_NO_W32) && \
|
||||
!defined(BOOST_REGEX_NO_WIN32_LOCALE)
|
||||
# define BOOST_REGEX_USE_WIN32_LOCALE
|
||||
#endif
|
||||
/* otherwise use C++ locale if supported: */
|
||||
#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE) && !defined(BOOST_NO_STD_LOCALE)
|
||||
# define BOOST_REGEX_USE_CPP_LOCALE
|
||||
#endif
|
||||
/* otherwise use C locale: */
|
||||
#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE)
|
||||
# define BOOST_REGEX_USE_C_LOCALE
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_REGEX_MAX_STATE_COUNT
|
||||
# define BOOST_REGEX_MAX_STATE_COUNT 100000000
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Error Handling for exception free compilers:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef BOOST_NO_EXCEPTIONS
|
||||
/*
|
||||
* If there are no exceptions then we must report critical-errors
|
||||
* the only way we know how; by terminating.
|
||||
*/
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
# define BOOST_REGEX_NOEH_ASSERT(x)\
|
||||
if(0 == (x))\
|
||||
{\
|
||||
std::string s("Error: critical regex++ failure in: ");\
|
||||
s.append(#x);\
|
||||
std::runtime_error e(s);\
|
||||
boost::throw_exception(e);\
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* With exceptions then error handling is taken care of and
|
||||
* there is no need for these checks:
|
||||
*/
|
||||
# define BOOST_REGEX_NOEH_ASSERT(x)
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Stack protection under MS Windows:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(BOOST_REGEX_NO_W32) && !defined(BOOST_REGEX_V3)
|
||||
# if(defined(_WIN32) || defined(_WIN64) || defined(_WINCE)) \
|
||||
&& !(defined(__GNUC__) || defined(__BORLANDC__) && defined(__clang__)) \
|
||||
&& !(defined(__BORLANDC__) && (__BORLANDC__ >= 0x600)) \
|
||||
&& !(defined(__MWERKS__) && (__MWERKS__ <= 0x3003))
|
||||
# define BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
# endif
|
||||
#elif defined(BOOST_REGEX_HAS_MS_STACK_GUARD)
|
||||
# undef BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && defined(BOOST_REGEX_HAS_MS_STACK_GUARD)
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CALL reset_stack_guard_page();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Algorithm selection and configuration.
|
||||
* These options are now obsolete for C++11 and later (regex v5).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_NON_RECURSIVE)
|
||||
# if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && !defined(_STLP_DEBUG) && !defined(__STL_DEBUG) && !(defined(_MSC_VER) && (_MSC_VER >= 1400)) && defined(BOOST_REGEX_CXX03)
|
||||
# define BOOST_REGEX_RECURSIVE
|
||||
# else
|
||||
# define BOOST_REGEX_NON_RECURSIVE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_NON_RECURSIVE
|
||||
# ifdef BOOST_REGEX_RECURSIVE
|
||||
# error "Can't set both BOOST_REGEX_RECURSIVE and BOOST_REGEX_NON_RECURSIVE"
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_BLOCKSIZE
|
||||
# define BOOST_REGEX_BLOCKSIZE 4096
|
||||
# endif
|
||||
# if BOOST_REGEX_BLOCKSIZE < 512
|
||||
# error "BOOST_REGEX_BLOCKSIZE must be at least 512"
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_MAX_BLOCKS
|
||||
# define BOOST_REGEX_MAX_BLOCKS 1024
|
||||
# endif
|
||||
# ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
# undef BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_MAX_CACHE_BLOCKS
|
||||
# define BOOST_REGEX_MAX_CACHE_BLOCKS 16
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Diagnostics:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef BOOST_REGEX_CONFIG_INFO
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CALL print_regex_library_info();
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_REGEX_DIAG)
|
||||
# pragma message ("BOOST_REGEX_DECL" BOOST_STRINGIZE(=BOOST_REGEX_DECL))
|
||||
# pragma message ("BOOST_REGEX_CALL" BOOST_STRINGIZE(=BOOST_REGEX_CALL))
|
||||
# pragma message ("BOOST_REGEX_CCALL" BOOST_STRINGIZE(=BOOST_REGEX_CCALL))
|
||||
#ifdef BOOST_REGEX_USE_C_LOCALE
|
||||
# pragma message ("Using C locale in regex traits class")
|
||||
#elif BOOST_REGEX_USE_CPP_LOCALE
|
||||
# pragma message ("Using C++ locale in regex traits class")
|
||||
#else
|
||||
# pragma message ("Using Win32 locale in regex traits class")
|
||||
#endif
|
||||
#if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# pragma message ("Dynamic linking enabled")
|
||||
#endif
|
||||
#if defined(BOOST_REGEX_NO_LIB) || defined(BOOST_ALL_NO_LIB)
|
||||
# pragma message ("Auto-linking disabled")
|
||||
#endif
|
||||
#ifdef BOOST_REGEX_NO_EXTERNAL_TEMPLATES
|
||||
# pragma message ("Extern templates disabled")
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE boost/regex/config/borland.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: regex borland-specific config setup.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__BORLANDC__) && !defined(__clang__)
|
||||
# if (__BORLANDC__ == 0x550) || (__BORLANDC__ == 0x551)
|
||||
// problems with std::basic_string and dll RTL:
|
||||
# if defined(_RTLDLL) && defined(_RWSTD_COMPILE_INSTANTIATE)
|
||||
# ifdef BOOST_REGEX_BUILD_DLL
|
||||
# error _RWSTD_COMPILE_INSTANTIATE must not be defined when building regex++ as a DLL
|
||||
# else
|
||||
# pragma message("Defining _RWSTD_COMPILE_INSTANTIATE when linking to the DLL version of the RTL may produce memory corruption problems in std::basic_string, as a result of separate versions of basic_string's static data in the RTL and you're exe/dll: be warned!!")
|
||||
# endif
|
||||
# endif
|
||||
# ifndef _RTLDLL
|
||||
// this is harmless for a staic link:
|
||||
# define _RWSTD_COMPILE_INSTANTIATE
|
||||
# endif
|
||||
// external templates cause problems for some reason:
|
||||
# define BOOST_REGEX_NO_EXTERNAL_TEMPLATES
|
||||
# endif
|
||||
# if (__BORLANDC__ <= 0x540) && !defined(BOOST_REGEX_NO_LIB) && !defined(_NO_VCL)
|
||||
// C++ Builder 4 and earlier, we can't tell whether we should be using
|
||||
// the VCL runtime or not, do a static link instead:
|
||||
# define BOOST_REGEX_STATIC_LINK
|
||||
# endif
|
||||
//
|
||||
// VCL support:
|
||||
// if we're building a console app then there can't be any VCL (can there?)
|
||||
# if !defined(__CONSOLE__) && !defined(_NO_VCL)
|
||||
# define BOOST_REGEX_USE_VCL
|
||||
# endif
|
||||
//
|
||||
// if this isn't Win32 then don't automatically select link
|
||||
// libraries:
|
||||
//
|
||||
# ifndef _Windows
|
||||
# ifndef BOOST_REGEX_NO_LIB
|
||||
# define BOOST_REGEX_NO_LIB
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_STATIC_LINK
|
||||
# define BOOST_REGEX_STATIC_LINK
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#if __BORLANDC__ < 0x600
|
||||
//
|
||||
// string workarounds:
|
||||
//
|
||||
#include <cstring>
|
||||
#undef strcmp
|
||||
#undef strcpy
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE boost/regex/config/cwchar.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: regex wide character string fixes.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_CWCHAR_HPP
|
||||
#define BOOST_REGEX_CONFIG_CWCHAR_HPP
|
||||
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
|
||||
// apparently this is required for the RW STL on Linux:
|
||||
#undef iswalnum
|
||||
#undef iswalpha
|
||||
#undef iswblank
|
||||
#undef iswcntrl
|
||||
#undef iswdigit
|
||||
#undef iswgraph
|
||||
#undef iswlower
|
||||
#undef iswprint
|
||||
#undef iswprint
|
||||
#undef iswpunct
|
||||
#undef iswspace
|
||||
#undef iswupper
|
||||
#undef iswxdigit
|
||||
#undef iswctype
|
||||
#undef towlower
|
||||
#undef towupper
|
||||
#undef towctrans
|
||||
#undef wctrans
|
||||
#undef wctype
|
||||
#endif
|
||||
|
||||
namespace std{
|
||||
|
||||
#ifndef BOOST_NO_STDC_NAMESPACE
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#ifdef iswalnum
|
||||
inline int (iswalnum)(wint_t i)
|
||||
{ return iswalnum(i); }
|
||||
#undef iswalnum
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswalnum;
|
||||
#endif
|
||||
|
||||
#ifdef iswalpha
|
||||
inline int (iswalpha)(wint_t i)
|
||||
{ return iswalpha(i); }
|
||||
#undef iswalpha
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswalpha;
|
||||
#endif
|
||||
|
||||
#ifdef iswcntrl
|
||||
inline int (iswcntrl)(wint_t i)
|
||||
{ return iswcntrl(i); }
|
||||
#undef iswcntrl
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswcntrl;
|
||||
#endif
|
||||
|
||||
#ifdef iswdigit
|
||||
inline int (iswdigit)(wint_t i)
|
||||
{ return iswdigit(i); }
|
||||
#undef iswdigit
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswdigit;
|
||||
#endif
|
||||
|
||||
#ifdef iswgraph
|
||||
inline int (iswgraph)(wint_t i)
|
||||
{ return iswgraph(i); }
|
||||
#undef iswgraph
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswgraph;
|
||||
#endif
|
||||
|
||||
#ifdef iswlower
|
||||
inline int (iswlower)(wint_t i)
|
||||
{ return iswlower(i); }
|
||||
#undef iswlower
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswlower;
|
||||
#endif
|
||||
|
||||
#ifdef iswprint
|
||||
inline int (iswprint)(wint_t i)
|
||||
{ return iswprint(i); }
|
||||
#undef iswprint
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswprint;
|
||||
#endif
|
||||
|
||||
#ifdef iswpunct
|
||||
inline int (iswpunct)(wint_t i)
|
||||
{ return iswpunct(i); }
|
||||
#undef iswpunct
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswpunct;
|
||||
#endif
|
||||
|
||||
#ifdef iswspace
|
||||
inline int (iswspace)(wint_t i)
|
||||
{ return iswspace(i); }
|
||||
#undef iswspace
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswspace;
|
||||
#endif
|
||||
|
||||
#ifdef iswupper
|
||||
inline int (iswupper)(wint_t i)
|
||||
{ return iswupper(i); }
|
||||
#undef iswupper
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswupper;
|
||||
#endif
|
||||
|
||||
#ifdef iswxdigit
|
||||
inline int (iswxdigit)(wint_t i)
|
||||
{ return iswxdigit(i); }
|
||||
#undef iswxdigit
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswxdigit;
|
||||
#endif
|
||||
|
||||
#ifdef towlower
|
||||
inline wint_t (towlower)(wint_t i)
|
||||
{ return towlower(i); }
|
||||
#undef towlower
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::towlower;
|
||||
#endif
|
||||
|
||||
#ifdef towupper
|
||||
inline wint_t (towupper)(wint_t i)
|
||||
{ return towupper(i); }
|
||||
#undef towupper
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using :: towupper;
|
||||
#endif
|
||||
|
||||
#ifdef wcscmp
|
||||
inline int (wcscmp)(const wchar_t *p1, const wchar_t *p2)
|
||||
{ return wcscmp(p1,p2); }
|
||||
#undef wcscmp
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcscmp;
|
||||
#endif
|
||||
|
||||
#ifdef wcscoll
|
||||
inline int (wcscoll)(const wchar_t *p1, const wchar_t *p2)
|
||||
{ return wcscoll(p1,p2); }
|
||||
#undef wcscoll
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(UNDER_CE)
|
||||
using ::wcscoll;
|
||||
#endif
|
||||
|
||||
#ifdef wcscpy
|
||||
inline wchar_t *(wcscpy)(wchar_t *p1, const wchar_t *p2)
|
||||
{ return wcscpy(p1,p2); }
|
||||
#undef wcscpy
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcscpy;
|
||||
#endif
|
||||
|
||||
#ifdef wcslen
|
||||
inline size_t (wcslen)(const wchar_t *p)
|
||||
{ return wcslen(p); }
|
||||
#undef wcslen
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcslen;
|
||||
#endif
|
||||
|
||||
#ifdef wcsxfrm
|
||||
size_t wcsxfrm(wchar_t *p1, const wchar_t *p2, size_t s)
|
||||
{ return wcsxfrm(p1,p2,s); }
|
||||
#undef wcsxfrm
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcsxfrm;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_NO_STDC_NAMESPACE
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2020
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE icu.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Unicode regular expressions on top of the ICU Library.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_ICU_HPP
|
||||
#define BOOST_REGEX_ICU_HPP
|
||||
|
||||
#include <boost/regex/config.hpp>
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#include <boost/regex/v4/icu.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/icu.hpp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE mfc.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Overloads and helpers for using MFC/ATL string types with Boost.Regex.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_MFC_HPP
|
||||
#define BOOST_REGEX_MFC_HPP
|
||||
|
||||
#include <atlsimpstr.h>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
//
|
||||
// define the types used for TCHAR's:
|
||||
typedef basic_regex<TCHAR> tregex;
|
||||
typedef match_results<TCHAR const*> tmatch;
|
||||
typedef regex_iterator<TCHAR const*> tregex_iterator;
|
||||
typedef regex_token_iterator<TCHAR const*> tregex_token_iterator;
|
||||
|
||||
// Obsolete. Remove
|
||||
#define SIMPLE_STRING_PARAM class B, bool b
|
||||
#define SIMPLE_STRING_ARG_LIST B, b
|
||||
|
||||
//
|
||||
// define regex creation functions:
|
||||
//
|
||||
template <class B, bool b>
|
||||
inline basic_regex<B>
|
||||
make_regex(const ATL::CSimpleStringT<B, b>& s, ::boost::regex_constants::syntax_option_type f = boost::regex_constants::normal)
|
||||
{
|
||||
basic_regex<B> result(s.GetString(), s.GetString() + s.GetLength(), f);
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// regex_match overloads:
|
||||
//
|
||||
template <class B, bool b, class A, class T>
|
||||
inline bool regex_match(const ATL::CSimpleStringT<B, b>& s,
|
||||
match_results<const B*, A>& what,
|
||||
const basic_regex<B, T>& e,
|
||||
boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
return ::boost::regex_match(s.GetString(),
|
||||
s.GetString() + s.GetLength(),
|
||||
what,
|
||||
e,
|
||||
f);
|
||||
}
|
||||
|
||||
template <class B, bool b, class T>
|
||||
inline bool regex_match(const ATL::CSimpleStringT<B, b>& s,
|
||||
const basic_regex<B, T>& e,
|
||||
boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
return ::boost::regex_match(s.GetString(),
|
||||
s.GetString() + s.GetLength(),
|
||||
e,
|
||||
f);
|
||||
}
|
||||
//
|
||||
// regex_search overloads:
|
||||
//
|
||||
template <class B, bool b, class A, class T>
|
||||
inline bool regex_search(const ATL::CSimpleStringT<B, b>& s,
|
||||
match_results<const B*, A>& what,
|
||||
const basic_regex<B, T>& e,
|
||||
boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
return ::boost::regex_search(s.GetString(),
|
||||
s.GetString() + s.GetLength(),
|
||||
what,
|
||||
e,
|
||||
f);
|
||||
}
|
||||
|
||||
template <class B, bool b, class T>
|
||||
inline bool regex_search(const ATL::CSimpleStringT<B, b>& s,
|
||||
const basic_regex<B, T>& e,
|
||||
boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
return ::boost::regex_search(s.GetString(),
|
||||
s.GetString() + s.GetLength(),
|
||||
e,
|
||||
f);
|
||||
}
|
||||
//
|
||||
// regex_iterator creation:
|
||||
//
|
||||
template <class B, bool b>
|
||||
inline regex_iterator<B const*>
|
||||
make_regex_iterator(const ATL::CSimpleStringT<B, b>& s, const basic_regex<B>& e, ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
regex_iterator<B const*> result(s.GetString(), s.GetString() + s.GetLength(), e, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class B, bool b>
|
||||
inline regex_token_iterator<B const*>
|
||||
make_regex_token_iterator(const ATL::CSimpleStringT<B, b>& s, const basic_regex<B>& e, int sub = 0, ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
regex_token_iterator<B const*> result(s.GetString(), s.GetString() + s.GetLength(), e, sub, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class B, bool b>
|
||||
inline regex_token_iterator<B const*>
|
||||
make_regex_token_iterator(const ATL::CSimpleStringT<B, b>& s, const basic_regex<B>& e, const std::vector<int>& subs, ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
regex_token_iterator<B const*> result(s.GetString(), s.GetString() + s.GetLength(), e, subs, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class B, bool b, std::size_t N>
|
||||
inline regex_token_iterator<B const*>
|
||||
make_regex_token_iterator(const ATL::CSimpleStringT<B, b>& s, const basic_regex<B>& e, const int (& subs)[N], ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default)
|
||||
{
|
||||
regex_token_iterator<B const*> result(s.GetString(), s.GetString() + s.GetLength(), e, subs, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class OutputIterator, class BidirectionalIterator, class traits,
|
||||
class B, bool b>
|
||||
OutputIterator regex_replace(OutputIterator out,
|
||||
BidirectionalIterator first,
|
||||
BidirectionalIterator last,
|
||||
const basic_regex<B, traits>& e,
|
||||
const ATL::CSimpleStringT<B, b>& fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return ::boost::regex_replace(out, first, last, e, fmt.GetString(), flags);
|
||||
}
|
||||
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
template <class B, bool b>
|
||||
class mfc_string_out_iterator
|
||||
{
|
||||
ATL::CSimpleStringT<B, b>* out;
|
||||
public:
|
||||
mfc_string_out_iterator(ATL::CSimpleStringT<B, b>& s) : out(&s) {}
|
||||
mfc_string_out_iterator& operator++() { return *this; }
|
||||
mfc_string_out_iterator& operator++(int) { return *this; }
|
||||
mfc_string_out_iterator& operator*() { return *this; }
|
||||
mfc_string_out_iterator& operator=(B v)
|
||||
{
|
||||
out->AppendChar(v);
|
||||
return *this;
|
||||
}
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef B value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef std::output_iterator_tag iterator_category;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class traits, class B, bool b>
|
||||
ATL::CSimpleStringT<B, b> regex_replace(const ATL::CSimpleStringT<B, b>& s,
|
||||
const basic_regex<B, traits>& e,
|
||||
const ATL::CSimpleStringT<B, b>& fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
ATL::CSimpleStringT<B, b> result(s.GetManager());
|
||||
BOOST_REGEX_DETAIL_NS::mfc_string_out_iterator<B, b> i(result);
|
||||
regex_replace(i, s.GetString(), s.GetString() + s.GetLength(), e, fmt.GetString(), flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace boost.
|
||||
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE pattern_except.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares pattern-matching exception classes.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_PAT_EXCEPT_HPP
|
||||
#define BOOST_RE_PAT_EXCEPT_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#include <boost/regex/v4/pattern_except.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/pattern_except.hpp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE object_cache.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Implements a generic object cache.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_OBJECT_CACHE_HPP
|
||||
#define BOOST_REGEX_OBJECT_CACHE_HPP
|
||||
|
||||
#include <boost/regex/config.hpp>
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#include <boost/regex/v4/object_cache.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/object_cache.hpp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE static_mutex.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares static_mutex lock type, there are three different
|
||||
* implementations: POSIX pthreads, WIN32 threads, and portable,
|
||||
* these are described in more detail below.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_STATIC_MUTEX_HPP
|
||||
#define BOOST_REGEX_STATIC_MUTEX_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/regex/config.hpp> // dll import/export options.
|
||||
|
||||
#ifdef BOOST_HAS_PTHREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS) && defined(PTHREAD_MUTEX_INITIALIZER)
|
||||
//
|
||||
// pthreads version:
|
||||
// simple wrap around a pthread_mutex_t initialized with
|
||||
// PTHREAD_MUTEX_INITIALIZER.
|
||||
//
|
||||
namespace boost{
|
||||
|
||||
class static_mutex;
|
||||
|
||||
#define BOOST_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, }
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock
|
||||
{
|
||||
public:
|
||||
scoped_static_mutex_lock(static_mutex& mut, bool lk = true);
|
||||
~scoped_static_mutex_lock();
|
||||
inline bool locked()const
|
||||
{
|
||||
return m_have_lock;
|
||||
}
|
||||
inline operator void const*()const
|
||||
{
|
||||
return locked() ? this : 0;
|
||||
}
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
static_mutex& m_mutex;
|
||||
bool m_have_lock;
|
||||
};
|
||||
|
||||
class static_mutex
|
||||
{
|
||||
public:
|
||||
typedef scoped_static_mutex_lock scoped_lock;
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
#elif defined(BOOST_HAS_WINTHREADS)
|
||||
//
|
||||
// Win32 version:
|
||||
// Use a 32-bit int as a lock, along with a test-and-set
|
||||
// implementation using InterlockedCompareExchange.
|
||||
//
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock;
|
||||
|
||||
class static_mutex
|
||||
{
|
||||
public:
|
||||
typedef scoped_static_mutex_lock scoped_lock;
|
||||
boost::int32_t m_mutex;
|
||||
};
|
||||
|
||||
#define BOOST_STATIC_MUTEX_INIT { 0, }
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock
|
||||
{
|
||||
public:
|
||||
scoped_static_mutex_lock(static_mutex& mut, bool lk = true);
|
||||
~scoped_static_mutex_lock();
|
||||
operator void const*()const
|
||||
{
|
||||
return locked() ? this : 0;
|
||||
}
|
||||
bool locked()const
|
||||
{
|
||||
return m_have_lock;
|
||||
}
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
static_mutex& m_mutex;
|
||||
bool m_have_lock;
|
||||
scoped_static_mutex_lock(const scoped_static_mutex_lock&);
|
||||
scoped_static_mutex_lock& operator=(const scoped_static_mutex_lock&);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#else
|
||||
//
|
||||
// Portable version of a static mutex based on Boost.Thread library:
|
||||
// This has to use a single mutex shared by all instances of static_mutex
|
||||
// because boost::call_once doesn't alow us to pass instance information
|
||||
// down to the initialisation proceedure. In fact the initialisation routine
|
||||
// may need to be called more than once - but only once per instance.
|
||||
//
|
||||
// Since this preprocessor path is almost never taken, we hide these header
|
||||
// dependencies so that build tools don't find them.
|
||||
//
|
||||
#define BOOST_REGEX_H1 <boost/thread/once.hpp>
|
||||
#define BOOST_REGEX_H2 <boost/thread/recursive_mutex.hpp>
|
||||
#define BOOST_REGEX_H3 <boost/thread/lock_types.hpp>
|
||||
#include BOOST_REGEX_H1
|
||||
#include BOOST_REGEX_H2
|
||||
#include BOOST_REGEX_H3
|
||||
#undef BOOST_REGEX_H1
|
||||
#undef BOOST_REGEX_H2
|
||||
#undef BOOST_REGEX_H3
|
||||
|
||||
namespace boost{
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock;
|
||||
extern "C" BOOST_REGEX_DECL void boost_regex_free_static_mutex();
|
||||
|
||||
class BOOST_REGEX_DECL static_mutex
|
||||
{
|
||||
public:
|
||||
typedef scoped_static_mutex_lock scoped_lock;
|
||||
static void init();
|
||||
static boost::recursive_mutex* m_pmutex;
|
||||
static boost::once_flag m_once;
|
||||
};
|
||||
|
||||
#define BOOST_STATIC_MUTEX_INIT { }
|
||||
|
||||
class BOOST_REGEX_DECL scoped_static_mutex_lock
|
||||
{
|
||||
public:
|
||||
scoped_static_mutex_lock(static_mutex& mut, bool lk = true);
|
||||
~scoped_static_mutex_lock();
|
||||
operator void const*()const;
|
||||
bool locked()const;
|
||||
void lock();
|
||||
void unlock();
|
||||
private:
|
||||
boost::unique_lock<boost::recursive_mutex>* m_plock;
|
||||
bool m_have_lock;
|
||||
};
|
||||
|
||||
inline scoped_static_mutex_lock::operator void const*()const
|
||||
{
|
||||
return locked() ? this : 0;
|
||||
}
|
||||
|
||||
inline bool scoped_static_mutex_lock::locked()const
|
||||
{
|
||||
return m_have_lock;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2020
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE unicode_iterator.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Iterator adapters for converting between different Unicode encodings.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_PENDING_UNICODE_ITERATOR_HPP
|
||||
#define BOOST_REGEX_PENDING_UNICODE_ITERATOR_HPP
|
||||
|
||||
#include <boost/regex/config.hpp>
|
||||
|
||||
#if defined(BOOST_REGEX_CXX03)
|
||||
#include <boost/regex/v4/unicode_iterator.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/unicode_iterator.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BOOST_REGEX_PENDING_UNICODE_ITERATOR_HPP
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_traits.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares regular expression traits classes.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_TRAITS_HPP
|
||||
#define BOOST_REGEX_TRAITS_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
# include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
# ifndef BOOST_REGEX_TRAITS_HPP_INCLUDED
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
# include <boost/regex/v4/regex_traits.hpp>
|
||||
#else
|
||||
# include <boost/regex/v5/regex_traits.hpp>
|
||||
#endif
|
||||
# endif
|
||||
|
||||
#endif // include
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE user.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: User settable options.
|
||||
*/
|
||||
|
||||
// define if you want the regex library to use the C locale
|
||||
// even on Win32:
|
||||
// #define BOOST_REGEX_USE_C_LOCALE
|
||||
|
||||
// define this is you want the regex library to use the C++
|
||||
// locale:
|
||||
// #define BOOST_REGEX_USE_CPP_LOCALE
|
||||
|
||||
// define this if the runtime library is a dll, and you
|
||||
// want BOOST_REGEX_DYN_LINK to set up dll exports/imports
|
||||
// with __declspec(dllexport)/__declspec(dllimport.)
|
||||
// #define BOOST_REGEX_HAS_DLL_RUNTIME
|
||||
|
||||
// define this if you want to dynamically link to regex,
|
||||
// if the runtime library is also a dll (Probably Win32 specific,
|
||||
// and has no effect unless BOOST_REGEX_HAS_DLL_RUNTIME is set):
|
||||
// #define BOOST_REGEX_DYN_LINK
|
||||
|
||||
// define this if you don't want the lib to automatically
|
||||
// select its link libraries:
|
||||
// #define BOOST_REGEX_NO_LIB
|
||||
|
||||
// define this if templates with switch statements cause problems:
|
||||
// #define BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE
|
||||
|
||||
// define this to disable Win32 support when available:
|
||||
// #define BOOST_REGEX_NO_W32
|
||||
|
||||
// define this if bool is not a real type:
|
||||
// #define BOOST_REGEX_NO_BOOL
|
||||
|
||||
// define this if no template instances are to be placed in
|
||||
// the library rather than users object files:
|
||||
// #define BOOST_REGEX_NO_EXTERNAL_TEMPLATES
|
||||
|
||||
// define this if the forward declarations in regex_fwd.hpp
|
||||
// cause more problems than they are worth:
|
||||
// #define BOOST_REGEX_NO_FWD
|
||||
|
||||
// define this if your compiler supports MS Windows structured
|
||||
// exception handling.
|
||||
// #define BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
|
||||
// define this if you want to use the recursive algorithm
|
||||
// even if BOOST_REGEX_HAS_MS_STACK_GUARD is not defined.
|
||||
// NOTE: OBSOLETE!!
|
||||
// #define BOOST_REGEX_RECURSIVE
|
||||
|
||||
// define this if you want to use the non-recursive
|
||||
// algorithm, even if the recursive version would be the default.
|
||||
// NOTE: OBSOLETE!!
|
||||
// #define BOOST_REGEX_NON_RECURSIVE
|
||||
|
||||
// define this if you want to set the size of the memory blocks
|
||||
// used by the non-recursive algorithm.
|
||||
// #define BOOST_REGEX_BLOCKSIZE 4096
|
||||
|
||||
// define this if you want to set the maximum number of memory blocks
|
||||
// used by the non-recursive algorithm.
|
||||
// #define BOOST_REGEX_MAX_BLOCKS 1024
|
||||
|
||||
// define this if you want to set the maximum number of memory blocks
|
||||
// cached by the non-recursive algorithm: Normally this is 16, but can be
|
||||
// higher if you have multiple threads all using boost.regex, or lower
|
||||
// if you don't want boost.regex to cache memory.
|
||||
// #define BOOST_REGEX_MAX_CACHE_BLOCKS 16
|
||||
|
||||
// define this if you want to be able to access extended capture
|
||||
// information in your sub_match's (caution this will slow things
|
||||
// down quite a bit).
|
||||
// #define BOOST_REGEX_MATCH_EXTRA
|
||||
|
||||
// define this if you want to enable support for Unicode via ICU.
|
||||
// #define BOOST_HAS_ICU
|
||||
|
||||
// define this if you want regex to use __cdecl calling convensions, even when __fastcall is available:
|
||||
// #define BOOST_REGEX_NO_FASTCALL
|
||||
@@ -1,734 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2004 John Maddock
|
||||
* Copyright 2011 Garmin Ltd. or its subsidiaries
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org/ for most recent version.
|
||||
* FILE basic_regex.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares template class basic_regex.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_BASIC_REGEX_HPP
|
||||
#define BOOST_REGEX_V5_BASIC_REGEX_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace boost{
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#if BOOST_REGEX_MSVC < 1700
|
||||
# pragma warning(disable : 4231)
|
||||
#endif
|
||||
#if BOOST_REGEX_MSVC < 1600
|
||||
#pragma warning(disable : 4660)
|
||||
#endif
|
||||
#if BOOST_REGEX_MSVC < 1910
|
||||
#pragma warning(disable:4800)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
//
|
||||
// forward declaration, we will need this one later:
|
||||
//
|
||||
template <class charT, class traits>
|
||||
class basic_regex_parser;
|
||||
|
||||
template <class I>
|
||||
void bubble_down_one(I first, I last)
|
||||
{
|
||||
if(first != last)
|
||||
{
|
||||
I next = last - 1;
|
||||
while((next != first) && (*next < *(next-1)))
|
||||
{
|
||||
(next-1)->swap(*next);
|
||||
--next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const int hash_value_mask = 1 << (std::numeric_limits<int>::digits - 1);
|
||||
|
||||
template <class Iterator>
|
||||
inline int hash_value_from_capture_name(Iterator i, Iterator j)
|
||||
{
|
||||
std::size_t r = 0;
|
||||
while (i != j)
|
||||
{
|
||||
r ^= *i + 0x9e3779b9 + (r << 6) + (r >> 2);
|
||||
++i;
|
||||
}
|
||||
r %= ((std::numeric_limits<int>::max)());
|
||||
return static_cast<int>(r) | hash_value_mask;
|
||||
}
|
||||
|
||||
class named_subexpressions
|
||||
{
|
||||
public:
|
||||
struct name
|
||||
{
|
||||
template <class charT>
|
||||
name(const charT* i, const charT* j, int idx)
|
||||
: index(idx)
|
||||
{
|
||||
hash = hash_value_from_capture_name(i, j);
|
||||
}
|
||||
name(int h, int idx)
|
||||
: index(idx), hash(h)
|
||||
{
|
||||
}
|
||||
int index;
|
||||
int hash;
|
||||
bool operator < (const name& other)const
|
||||
{
|
||||
return hash < other.hash;
|
||||
}
|
||||
bool operator == (const name& other)const
|
||||
{
|
||||
return hash == other.hash;
|
||||
}
|
||||
void swap(name& other)
|
||||
{
|
||||
std::swap(index, other.index);
|
||||
std::swap(hash, other.hash);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<name>::const_iterator const_iterator;
|
||||
typedef std::pair<const_iterator, const_iterator> range_type;
|
||||
|
||||
named_subexpressions(){}
|
||||
|
||||
template <class charT>
|
||||
void set_name(const charT* i, const charT* j, int index)
|
||||
{
|
||||
m_sub_names.push_back(name(i, j, index));
|
||||
bubble_down_one(m_sub_names.begin(), m_sub_names.end());
|
||||
}
|
||||
template <class charT>
|
||||
int get_id(const charT* i, const charT* j)const
|
||||
{
|
||||
name t(i, j, 0);
|
||||
typename std::vector<name>::const_iterator pos = std::lower_bound(m_sub_names.begin(), m_sub_names.end(), t);
|
||||
if((pos != m_sub_names.end()) && (*pos == t))
|
||||
{
|
||||
return pos->index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
template <class charT>
|
||||
range_type equal_range(const charT* i, const charT* j)const
|
||||
{
|
||||
name t(i, j, 0);
|
||||
return std::equal_range(m_sub_names.begin(), m_sub_names.end(), t);
|
||||
}
|
||||
int get_id(int h)const
|
||||
{
|
||||
name t(h, 0);
|
||||
std::vector<name>::const_iterator pos = std::lower_bound(m_sub_names.begin(), m_sub_names.end(), t);
|
||||
if((pos != m_sub_names.end()) && (*pos == t))
|
||||
{
|
||||
return pos->index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
range_type equal_range(int h)const
|
||||
{
|
||||
name t(h, 0);
|
||||
return std::equal_range(m_sub_names.begin(), m_sub_names.end(), t);
|
||||
}
|
||||
private:
|
||||
std::vector<name> m_sub_names;
|
||||
};
|
||||
|
||||
//
|
||||
// class regex_data:
|
||||
// represents the data we wish to expose to the matching algorithms.
|
||||
//
|
||||
template <class charT, class traits>
|
||||
struct regex_data : public named_subexpressions
|
||||
{
|
||||
typedef regex_constants::syntax_option_type flag_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
regex_data(const ::std::shared_ptr<
|
||||
::boost::regex_traits_wrapper<traits> >& t)
|
||||
: m_ptraits(t), m_flags(0), m_status(0), m_expression(0), m_expression_len(0),
|
||||
m_mark_count(0), m_first_state(0), m_restart_type(0),
|
||||
m_startmap{ 0 },
|
||||
m_can_be_null(0), m_word_mask(0), m_has_recursions(false), m_disable_match_any(false) {}
|
||||
regex_data()
|
||||
: m_ptraits(new ::boost::regex_traits_wrapper<traits>()), m_flags(0), m_status(0), m_expression(0), m_expression_len(0),
|
||||
m_mark_count(0), m_first_state(0), m_restart_type(0),
|
||||
m_startmap{ 0 },
|
||||
m_can_be_null(0), m_word_mask(0), m_has_recursions(false), m_disable_match_any(false) {}
|
||||
|
||||
::std::shared_ptr<
|
||||
::boost::regex_traits_wrapper<traits>
|
||||
> m_ptraits; // traits class instance
|
||||
flag_type m_flags; // flags with which we were compiled
|
||||
int m_status; // error code (0 implies OK).
|
||||
const charT* m_expression; // the original expression
|
||||
std::ptrdiff_t m_expression_len; // the length of the original expression
|
||||
size_type m_mark_count; // the number of marked sub-expressions
|
||||
BOOST_REGEX_DETAIL_NS::re_syntax_base* m_first_state; // the first state of the machine
|
||||
unsigned m_restart_type; // search optimisation type
|
||||
unsigned char m_startmap[1 << CHAR_BIT]; // which characters can start a match
|
||||
unsigned int m_can_be_null; // whether we can match a null string
|
||||
BOOST_REGEX_DETAIL_NS::raw_storage m_data; // the buffer in which our states are constructed
|
||||
typename traits::char_class_type m_word_mask; // mask used to determine if a character is a word character
|
||||
std::vector<
|
||||
std::pair<
|
||||
std::size_t, std::size_t> > m_subs; // Position of sub-expressions within the *string*.
|
||||
bool m_has_recursions; // whether we have recursive expressions;
|
||||
bool m_disable_match_any; // when set we need to disable the match_any flag as it causes different/buggy behaviour.
|
||||
};
|
||||
//
|
||||
// class basic_regex_implementation
|
||||
// pimpl implementation class for basic_regex.
|
||||
//
|
||||
template <class charT, class traits>
|
||||
class basic_regex_implementation
|
||||
: public regex_data<charT, traits>
|
||||
{
|
||||
public:
|
||||
typedef regex_constants::syntax_option_type flag_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef typename traits::locale_type locale_type;
|
||||
typedef const charT* const_iterator;
|
||||
|
||||
basic_regex_implementation(){}
|
||||
basic_regex_implementation(const ::std::shared_ptr<
|
||||
::boost::regex_traits_wrapper<traits> >& t)
|
||||
: regex_data<charT, traits>(t) {}
|
||||
void assign(const charT* arg_first,
|
||||
const charT* arg_last,
|
||||
flag_type f)
|
||||
{
|
||||
regex_data<charT, traits>* pdat = this;
|
||||
basic_regex_parser<charT, traits> parser(pdat);
|
||||
parser.parse(arg_first, arg_last, f);
|
||||
}
|
||||
|
||||
locale_type imbue(locale_type l)
|
||||
{
|
||||
return this->m_ptraits->imbue(l);
|
||||
}
|
||||
locale_type getloc()const
|
||||
{
|
||||
return this->m_ptraits->getloc();
|
||||
}
|
||||
std::basic_string<charT> str()const
|
||||
{
|
||||
std::basic_string<charT> result;
|
||||
if(this->m_status == 0)
|
||||
result = std::basic_string<charT>(this->m_expression, this->m_expression_len);
|
||||
return result;
|
||||
}
|
||||
const_iterator expression()const
|
||||
{
|
||||
return this->m_expression;
|
||||
}
|
||||
std::pair<const_iterator, const_iterator> subexpression(std::size_t n)const
|
||||
{
|
||||
const std::pair<std::size_t, std::size_t>& pi = this->m_subs.at(n);
|
||||
std::pair<const_iterator, const_iterator> p(expression() + pi.first, expression() + pi.second);
|
||||
return p;
|
||||
}
|
||||
//
|
||||
// begin, end:
|
||||
const_iterator begin()const
|
||||
{
|
||||
return (this->m_status ? 0 : this->m_expression);
|
||||
}
|
||||
const_iterator end()const
|
||||
{
|
||||
return (this->m_status ? 0 : this->m_expression + this->m_expression_len);
|
||||
}
|
||||
flag_type flags()const
|
||||
{
|
||||
return this->m_flags;
|
||||
}
|
||||
size_type size()const
|
||||
{
|
||||
return this->m_expression_len;
|
||||
}
|
||||
int status()const
|
||||
{
|
||||
return this->m_status;
|
||||
}
|
||||
size_type mark_count()const
|
||||
{
|
||||
return this->m_mark_count - 1;
|
||||
}
|
||||
const BOOST_REGEX_DETAIL_NS::re_syntax_base* get_first_state()const
|
||||
{
|
||||
return this->m_first_state;
|
||||
}
|
||||
unsigned get_restart_type()const
|
||||
{
|
||||
return this->m_restart_type;
|
||||
}
|
||||
const unsigned char* get_map()const
|
||||
{
|
||||
return this->m_startmap;
|
||||
}
|
||||
const ::boost::regex_traits_wrapper<traits>& get_traits()const
|
||||
{
|
||||
return *(this->m_ptraits);
|
||||
}
|
||||
bool can_be_null()const
|
||||
{
|
||||
return this->m_can_be_null;
|
||||
}
|
||||
const regex_data<charT, traits>& get_data()const
|
||||
{
|
||||
basic_regex_implementation<charT, traits> const* p = this;
|
||||
return *static_cast<const regex_data<charT, traits>*>(p);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace BOOST_REGEX_DETAIL_NS
|
||||
//
|
||||
// class basic_regex:
|
||||
// represents the compiled
|
||||
// regular expression:
|
||||
//
|
||||
|
||||
#ifdef BOOST_REGEX_NO_FWD
|
||||
template <class charT, class traits = regex_traits<charT> >
|
||||
#else
|
||||
template <class charT, class traits >
|
||||
#endif
|
||||
class basic_regex : public regbase
|
||||
{
|
||||
public:
|
||||
// typedefs:
|
||||
typedef std::size_t traits_size_type;
|
||||
typedef typename traits::string_type traits_string_type;
|
||||
typedef charT char_type;
|
||||
typedef traits traits_type;
|
||||
|
||||
typedef charT value_type;
|
||||
typedef charT& reference;
|
||||
typedef const charT& const_reference;
|
||||
typedef const charT* const_iterator;
|
||||
typedef const_iterator iterator;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef regex_constants::syntax_option_type flag_type;
|
||||
// locale_type
|
||||
// placeholder for actual locale type used by the
|
||||
// traits class to localise *this.
|
||||
typedef typename traits::locale_type locale_type;
|
||||
|
||||
public:
|
||||
explicit basic_regex(){}
|
||||
explicit basic_regex(const charT* p, flag_type f = regex_constants::normal)
|
||||
{
|
||||
assign(p, f);
|
||||
}
|
||||
basic_regex(const charT* p1, const charT* p2, flag_type f = regex_constants::normal)
|
||||
{
|
||||
assign(p1, p2, f);
|
||||
}
|
||||
basic_regex(const charT* p, size_type len, flag_type f)
|
||||
{
|
||||
assign(p, len, f);
|
||||
}
|
||||
basic_regex(const basic_regex& that)
|
||||
: m_pimpl(that.m_pimpl) {}
|
||||
~basic_regex(){}
|
||||
basic_regex& operator=(const basic_regex& that)
|
||||
{
|
||||
return assign(that);
|
||||
}
|
||||
basic_regex& operator=(const charT* ptr)
|
||||
{
|
||||
return assign(ptr);
|
||||
}
|
||||
|
||||
//
|
||||
// assign:
|
||||
basic_regex& assign(const basic_regex& that)
|
||||
{
|
||||
m_pimpl = that.m_pimpl;
|
||||
return *this;
|
||||
}
|
||||
basic_regex& assign(const charT* p, flag_type f = regex_constants::normal)
|
||||
{
|
||||
return assign(p, p + traits::length(p), f);
|
||||
}
|
||||
basic_regex& assign(const charT* p, size_type len, flag_type f)
|
||||
{
|
||||
return assign(p, p + len, f);
|
||||
}
|
||||
private:
|
||||
basic_regex& do_assign(const charT* p1,
|
||||
const charT* p2,
|
||||
flag_type f);
|
||||
public:
|
||||
basic_regex& assign(const charT* p1,
|
||||
const charT* p2,
|
||||
flag_type f = regex_constants::normal)
|
||||
{
|
||||
return do_assign(p1, p2, f);
|
||||
}
|
||||
|
||||
template <class ST, class SA>
|
||||
unsigned int set_expression(const std::basic_string<charT, ST, SA>& p, flag_type f = regex_constants::normal)
|
||||
{
|
||||
return set_expression(p.data(), p.data() + p.size(), f);
|
||||
}
|
||||
|
||||
template <class ST, class SA>
|
||||
explicit basic_regex(const std::basic_string<charT, ST, SA>& p, flag_type f = regex_constants::normal)
|
||||
{
|
||||
assign(p, f);
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
basic_regex(InputIterator arg_first, InputIterator arg_last, flag_type f = regex_constants::normal)
|
||||
{
|
||||
typedef typename traits::string_type seq_type;
|
||||
seq_type a(arg_first, arg_last);
|
||||
if(!a.empty())
|
||||
assign(static_cast<const charT*>(&*a.begin()), static_cast<const charT*>(&*a.begin() + a.size()), f);
|
||||
else
|
||||
assign(static_cast<const charT*>(0), static_cast<const charT*>(0), f);
|
||||
}
|
||||
|
||||
template <class ST, class SA>
|
||||
basic_regex& operator=(const std::basic_string<charT, ST, SA>& p)
|
||||
{
|
||||
return assign(p.data(), p.data() + p.size(), regex_constants::normal);
|
||||
}
|
||||
|
||||
template <class string_traits, class A>
|
||||
basic_regex& assign(
|
||||
const std::basic_string<charT, string_traits, A>& s,
|
||||
flag_type f = regex_constants::normal)
|
||||
{
|
||||
return assign(s.data(), s.data() + s.size(), f);
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
basic_regex& assign(InputIterator arg_first,
|
||||
InputIterator arg_last,
|
||||
flag_type f = regex_constants::normal)
|
||||
{
|
||||
typedef typename traits::string_type seq_type;
|
||||
seq_type a(arg_first, arg_last);
|
||||
if(a.size())
|
||||
{
|
||||
const charT* p1 = &*a.begin();
|
||||
const charT* p2 = &*a.begin() + a.size();
|
||||
return assign(p1, p2, f);
|
||||
}
|
||||
return assign(static_cast<const charT*>(0), static_cast<const charT*>(0), f);
|
||||
}
|
||||
|
||||
//
|
||||
// locale:
|
||||
locale_type imbue(locale_type l);
|
||||
locale_type getloc()const
|
||||
{
|
||||
return m_pimpl.get() ? m_pimpl->getloc() : locale_type();
|
||||
}
|
||||
//
|
||||
// getflags:
|
||||
// retained for backwards compatibility only, "flags"
|
||||
// is now the preferred name:
|
||||
flag_type getflags()const
|
||||
{
|
||||
return flags();
|
||||
}
|
||||
flag_type flags()const
|
||||
{
|
||||
return m_pimpl.get() ? m_pimpl->flags() : 0;
|
||||
}
|
||||
//
|
||||
// str:
|
||||
std::basic_string<charT> str()const
|
||||
{
|
||||
return m_pimpl.get() ? m_pimpl->str() : std::basic_string<charT>();
|
||||
}
|
||||
//
|
||||
// begin, end, subexpression:
|
||||
std::pair<const_iterator, const_iterator> subexpression(std::size_t n)const
|
||||
{
|
||||
#ifdef BOOST_REGEX_STANDALONE
|
||||
if (!m_pimpl.get())
|
||||
throw std::logic_error("Can't access subexpressions in an invalid regex.");
|
||||
#else
|
||||
if(!m_pimpl.get())
|
||||
boost::throw_exception(std::logic_error("Can't access subexpressions in an invalid regex."));
|
||||
#endif
|
||||
return m_pimpl->subexpression(n);
|
||||
}
|
||||
const_iterator begin()const
|
||||
{
|
||||
return (m_pimpl.get() ? m_pimpl->begin() : 0);
|
||||
}
|
||||
const_iterator end()const
|
||||
{
|
||||
return (m_pimpl.get() ? m_pimpl->end() : 0);
|
||||
}
|
||||
//
|
||||
// swap:
|
||||
void swap(basic_regex& that)throw()
|
||||
{
|
||||
m_pimpl.swap(that.m_pimpl);
|
||||
}
|
||||
//
|
||||
// size:
|
||||
size_type size()const
|
||||
{
|
||||
return (m_pimpl.get() ? m_pimpl->size() : 0);
|
||||
}
|
||||
//
|
||||
// max_size:
|
||||
size_type max_size()const
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
//
|
||||
// empty:
|
||||
bool empty()const
|
||||
{
|
||||
return (m_pimpl.get() ? 0 != m_pimpl->status() : true);
|
||||
}
|
||||
|
||||
size_type mark_count()const
|
||||
{
|
||||
return (m_pimpl.get() ? m_pimpl->mark_count() : 0);
|
||||
}
|
||||
|
||||
int status()const
|
||||
{
|
||||
return (m_pimpl.get() ? m_pimpl->status() : regex_constants::error_empty);
|
||||
}
|
||||
|
||||
int compare(const basic_regex& that) const
|
||||
{
|
||||
if(m_pimpl.get() == that.m_pimpl.get())
|
||||
return 0;
|
||||
if(!m_pimpl.get())
|
||||
return -1;
|
||||
if(!that.m_pimpl.get())
|
||||
return 1;
|
||||
if(status() != that.status())
|
||||
return status() - that.status();
|
||||
if(flags() != that.flags())
|
||||
return flags() - that.flags();
|
||||
return str().compare(that.str());
|
||||
}
|
||||
bool operator==(const basic_regex& e)const
|
||||
{
|
||||
return compare(e) == 0;
|
||||
}
|
||||
bool operator != (const basic_regex& e)const
|
||||
{
|
||||
return compare(e) != 0;
|
||||
}
|
||||
bool operator<(const basic_regex& e)const
|
||||
{
|
||||
return compare(e) < 0;
|
||||
}
|
||||
bool operator>(const basic_regex& e)const
|
||||
{
|
||||
return compare(e) > 0;
|
||||
}
|
||||
bool operator<=(const basic_regex& e)const
|
||||
{
|
||||
return compare(e) <= 0;
|
||||
}
|
||||
bool operator>=(const basic_regex& e)const
|
||||
{
|
||||
return compare(e) >= 0;
|
||||
}
|
||||
|
||||
//
|
||||
// The following are deprecated as public interfaces
|
||||
// but are available for compatibility with earlier versions.
|
||||
const charT* expression()const
|
||||
{
|
||||
return (m_pimpl.get() && !m_pimpl->status() ? m_pimpl->expression() : 0);
|
||||
}
|
||||
unsigned int set_expression(const charT* p1, const charT* p2, flag_type f = regex_constants::normal)
|
||||
{
|
||||
assign(p1, p2, f | regex_constants::no_except);
|
||||
return status();
|
||||
}
|
||||
unsigned int set_expression(const charT* p, flag_type f = regex_constants::normal)
|
||||
{
|
||||
assign(p, f | regex_constants::no_except);
|
||||
return status();
|
||||
}
|
||||
unsigned int error_code()const
|
||||
{
|
||||
return status();
|
||||
}
|
||||
//
|
||||
// private access methods:
|
||||
//
|
||||
const BOOST_REGEX_DETAIL_NS::re_syntax_base* get_first_state()const
|
||||
{
|
||||
BOOST_REGEX_ASSERT(0 != m_pimpl.get());
|
||||
return m_pimpl->get_first_state();
|
||||
}
|
||||
unsigned get_restart_type()const
|
||||
{
|
||||
BOOST_REGEX_ASSERT(0 != m_pimpl.get());
|
||||
return m_pimpl->get_restart_type();
|
||||
}
|
||||
const unsigned char* get_map()const
|
||||
{
|
||||
BOOST_REGEX_ASSERT(0 != m_pimpl.get());
|
||||
return m_pimpl->get_map();
|
||||
}
|
||||
const ::boost::regex_traits_wrapper<traits>& get_traits()const
|
||||
{
|
||||
BOOST_REGEX_ASSERT(0 != m_pimpl.get());
|
||||
return m_pimpl->get_traits();
|
||||
}
|
||||
bool can_be_null()const
|
||||
{
|
||||
BOOST_REGEX_ASSERT(0 != m_pimpl.get());
|
||||
return m_pimpl->can_be_null();
|
||||
}
|
||||
const BOOST_REGEX_DETAIL_NS::regex_data<charT, traits>& get_data()const
|
||||
{
|
||||
BOOST_REGEX_ASSERT(0 != m_pimpl.get());
|
||||
return m_pimpl->get_data();
|
||||
}
|
||||
std::shared_ptr<BOOST_REGEX_DETAIL_NS::named_subexpressions > get_named_subs()const
|
||||
{
|
||||
return m_pimpl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> > m_pimpl;
|
||||
};
|
||||
|
||||
//
|
||||
// out of line members;
|
||||
// these are the only members that mutate the basic_regex object,
|
||||
// and are designed to provide the strong exception guarantee
|
||||
// (in the event of a throw, the state of the object remains unchanged).
|
||||
//
|
||||
template <class charT, class traits>
|
||||
basic_regex<charT, traits>& basic_regex<charT, traits>::do_assign(const charT* p1,
|
||||
const charT* p2,
|
||||
flag_type f)
|
||||
{
|
||||
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> > temp;
|
||||
if(!m_pimpl.get())
|
||||
{
|
||||
temp = std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits>());
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits>(m_pimpl->m_ptraits));
|
||||
}
|
||||
temp->assign(p1, p2, f);
|
||||
temp.swap(m_pimpl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class charT, class traits>
|
||||
typename basic_regex<charT, traits>::locale_type basic_regex<charT, traits>::imbue(locale_type l)
|
||||
{
|
||||
std::shared_ptr<BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits> > temp(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation<charT, traits>());
|
||||
locale_type result = temp->imbue(l);
|
||||
temp.swap(m_pimpl);
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// non-members:
|
||||
//
|
||||
template <class charT, class traits>
|
||||
void swap(basic_regex<charT, traits>& e1, basic_regex<charT, traits>& e2)
|
||||
{
|
||||
e1.swap(e2);
|
||||
}
|
||||
|
||||
template <class charT, class traits, class traits2>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator << (std::basic_ostream<charT, traits>& os,
|
||||
const basic_regex<charT, traits2>& e)
|
||||
{
|
||||
return (os << e.str());
|
||||
}
|
||||
|
||||
//
|
||||
// class reg_expression:
|
||||
// this is provided for backwards compatibility only,
|
||||
// it is deprecated, no not use!
|
||||
//
|
||||
#ifdef BOOST_REGEX_NO_FWD
|
||||
template <class charT, class traits = regex_traits<charT> >
|
||||
#else
|
||||
template <class charT, class traits >
|
||||
#endif
|
||||
class reg_expression : public basic_regex<charT, traits>
|
||||
{
|
||||
public:
|
||||
typedef typename basic_regex<charT, traits>::flag_type flag_type;
|
||||
typedef typename basic_regex<charT, traits>::size_type size_type;
|
||||
explicit reg_expression(){}
|
||||
explicit reg_expression(const charT* p, flag_type f = regex_constants::normal)
|
||||
: basic_regex<charT, traits>(p, f){}
|
||||
reg_expression(const charT* p1, const charT* p2, flag_type f = regex_constants::normal)
|
||||
: basic_regex<charT, traits>(p1, p2, f){}
|
||||
reg_expression(const charT* p, size_type len, flag_type f)
|
||||
: basic_regex<charT, traits>(p, len, f){}
|
||||
reg_expression(const reg_expression& that)
|
||||
: basic_regex<charT, traits>(that) {}
|
||||
~reg_expression(){}
|
||||
reg_expression& operator=(const reg_expression& that)
|
||||
{
|
||||
return this->assign(that);
|
||||
}
|
||||
|
||||
template <class ST, class SA>
|
||||
explicit reg_expression(const std::basic_string<charT, ST, SA>& p, flag_type f = regex_constants::normal)
|
||||
: basic_regex<charT, traits>(p, f)
|
||||
{
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
reg_expression(InputIterator arg_first, InputIterator arg_last, flag_type f = regex_constants::normal)
|
||||
: basic_regex<charT, traits>(arg_first, arg_last, f)
|
||||
{
|
||||
}
|
||||
|
||||
template <class ST, class SA>
|
||||
reg_expression& operator=(const std::basic_string<charT, ST, SA>& p)
|
||||
{
|
||||
this->assign(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,474 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE c_regex_traits.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares regular expression traits class that wraps the global C locale.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_C_REGEX_TRAITS_HPP_INCLUDED
|
||||
#define BOOST_C_REGEX_TRAITS_HPP_INCLUDED
|
||||
|
||||
#include <boost/regex/config.hpp>
|
||||
#include <boost/regex/v5/regex_workaround.hpp>
|
||||
#include <cctype>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace BOOST_REGEX_DETAIL_NS {
|
||||
|
||||
enum
|
||||
{
|
||||
char_class_space = 1 << 0,
|
||||
char_class_print = 1 << 1,
|
||||
char_class_cntrl = 1 << 2,
|
||||
char_class_upper = 1 << 3,
|
||||
char_class_lower = 1 << 4,
|
||||
char_class_alpha = 1 << 5,
|
||||
char_class_digit = 1 << 6,
|
||||
char_class_punct = 1 << 7,
|
||||
char_class_xdigit = 1 << 8,
|
||||
char_class_alnum = char_class_alpha | char_class_digit,
|
||||
char_class_graph = char_class_alnum | char_class_punct,
|
||||
char_class_blank = 1 << 9,
|
||||
char_class_word = 1 << 10,
|
||||
char_class_unicode = 1 << 11,
|
||||
char_class_horizontal = 1 << 12,
|
||||
char_class_vertical = 1 << 13
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class charT>
|
||||
struct c_regex_traits;
|
||||
|
||||
template<>
|
||||
struct c_regex_traits<char>
|
||||
{
|
||||
c_regex_traits(){}
|
||||
typedef char char_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::string string_type;
|
||||
struct locale_type{};
|
||||
typedef std::uint32_t char_class_type;
|
||||
|
||||
static size_type length(const char_type* p)
|
||||
{
|
||||
return (std::strlen)(p);
|
||||
}
|
||||
|
||||
char translate(char c) const
|
||||
{
|
||||
return c;
|
||||
}
|
||||
char translate_nocase(char c) const
|
||||
{
|
||||
return static_cast<char>((std::tolower)(static_cast<unsigned char>(c)));
|
||||
}
|
||||
|
||||
static string_type transform(const char* p1, const char* p2);
|
||||
static string_type transform_primary(const char* p1, const char* p2);
|
||||
|
||||
static char_class_type lookup_classname(const char* p1, const char* p2);
|
||||
static string_type lookup_collatename(const char* p1, const char* p2);
|
||||
|
||||
static bool isctype(char, char_class_type);
|
||||
static int value(char, int);
|
||||
|
||||
locale_type imbue(locale_type l)
|
||||
{ return l; }
|
||||
locale_type getloc()const
|
||||
{ return locale_type(); }
|
||||
|
||||
private:
|
||||
// this type is not copyable:
|
||||
c_regex_traits(const c_regex_traits&);
|
||||
c_regex_traits& operator=(const c_regex_traits&);
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
template<>
|
||||
struct c_regex_traits<wchar_t>
|
||||
{
|
||||
c_regex_traits(){}
|
||||
typedef wchar_t char_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::wstring string_type;
|
||||
struct locale_type{};
|
||||
typedef std::uint32_t char_class_type;
|
||||
|
||||
static size_type length(const char_type* p)
|
||||
{
|
||||
return (std::wcslen)(p);
|
||||
}
|
||||
|
||||
wchar_t translate(wchar_t c) const
|
||||
{
|
||||
return c;
|
||||
}
|
||||
wchar_t translate_nocase(wchar_t c) const
|
||||
{
|
||||
return (std::towlower)(c);
|
||||
}
|
||||
|
||||
static string_type transform(const wchar_t* p1, const wchar_t* p2);
|
||||
static string_type transform_primary(const wchar_t* p1, const wchar_t* p2);
|
||||
|
||||
static char_class_type lookup_classname(const wchar_t* p1, const wchar_t* p2);
|
||||
static string_type lookup_collatename(const wchar_t* p1, const wchar_t* p2);
|
||||
|
||||
static bool isctype(wchar_t, char_class_type);
|
||||
static int value(wchar_t, int);
|
||||
|
||||
locale_type imbue(locale_type l)
|
||||
{ return l; }
|
||||
locale_type getloc()const
|
||||
{ return locale_type(); }
|
||||
|
||||
private:
|
||||
// this type is not copyable:
|
||||
c_regex_traits(const c_regex_traits&);
|
||||
c_regex_traits& operator=(const c_regex_traits&);
|
||||
};
|
||||
|
||||
#endif // BOOST_NO_WREGEX
|
||||
|
||||
inline c_regex_traits<char>::string_type c_regex_traits<char>::transform(const char* p1, const char* p2)
|
||||
{
|
||||
std::string result(10, ' ');
|
||||
std::size_t s = result.size();
|
||||
std::size_t r;
|
||||
std::string src(p1, p2);
|
||||
while (s < (r = std::strxfrm(&*result.begin(), src.c_str(), s)))
|
||||
{
|
||||
#if defined(_CPPLIB_VER)
|
||||
//
|
||||
// A bug in VC11 and 12 causes the program to hang if we pass a null-string
|
||||
// to std::strxfrm, but only for certain locales :-(
|
||||
// Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware).
|
||||
//
|
||||
if (r == INT_MAX)
|
||||
{
|
||||
result.erase();
|
||||
result.insert(result.begin(), static_cast<char>(0));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
result.append(r - s + 3, ' ');
|
||||
s = result.size();
|
||||
}
|
||||
result.erase(r);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline c_regex_traits<char>::string_type c_regex_traits<char>::transform_primary(const char* p1, const char* p2)
|
||||
{
|
||||
static char s_delim;
|
||||
static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast<c_regex_traits<char>*>(0), &s_delim);
|
||||
std::string result;
|
||||
//
|
||||
// What we do here depends upon the format of the sort key returned by
|
||||
// sort key returned by this->transform:
|
||||
//
|
||||
switch (s_collate_type)
|
||||
{
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_C:
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown:
|
||||
// the best we can do is translate to lower case, then get a regular sort key:
|
||||
{
|
||||
result.assign(p1, p2);
|
||||
for (std::string::size_type i = 0; i < result.size(); ++i)
|
||||
result[i] = static_cast<char>((std::tolower)(static_cast<unsigned char>(result[i])));
|
||||
result = transform(&*result.begin(), &*result.begin() + result.size());
|
||||
break;
|
||||
}
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed:
|
||||
{
|
||||
// get a regular sort key, and then truncate it:
|
||||
result = transform(p1, p2);
|
||||
result.erase(s_delim);
|
||||
break;
|
||||
}
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim:
|
||||
// get a regular sort key, and then truncate everything after the delim:
|
||||
result = transform(p1, p2);
|
||||
if ((!result.empty()) && (result[0] == s_delim))
|
||||
break;
|
||||
std::size_t i;
|
||||
for (i = 0; i < result.size(); ++i)
|
||||
{
|
||||
if (result[i] == s_delim)
|
||||
break;
|
||||
}
|
||||
result.erase(i);
|
||||
break;
|
||||
}
|
||||
if (result.empty())
|
||||
result = std::string(1, char(0));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline c_regex_traits<char>::char_class_type c_regex_traits<char>::lookup_classname(const char* p1, const char* p2)
|
||||
{
|
||||
using namespace BOOST_REGEX_DETAIL_NS;
|
||||
static const char_class_type masks[] =
|
||||
{
|
||||
0,
|
||||
char_class_alnum,
|
||||
char_class_alpha,
|
||||
char_class_blank,
|
||||
char_class_cntrl,
|
||||
char_class_digit,
|
||||
char_class_digit,
|
||||
char_class_graph,
|
||||
char_class_horizontal,
|
||||
char_class_lower,
|
||||
char_class_lower,
|
||||
char_class_print,
|
||||
char_class_punct,
|
||||
char_class_space,
|
||||
char_class_space,
|
||||
char_class_upper,
|
||||
char_class_unicode,
|
||||
char_class_upper,
|
||||
char_class_vertical,
|
||||
char_class_alnum | char_class_word,
|
||||
char_class_alnum | char_class_word,
|
||||
char_class_xdigit,
|
||||
};
|
||||
|
||||
int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2);
|
||||
if (idx < 0)
|
||||
{
|
||||
std::string s(p1, p2);
|
||||
for (std::string::size_type i = 0; i < s.size(); ++i)
|
||||
s[i] = static_cast<char>((std::tolower)(static_cast<unsigned char>(s[i])));
|
||||
idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size());
|
||||
}
|
||||
BOOST_REGEX_ASSERT(std::size_t(idx) + 1u < sizeof(masks) / sizeof(masks[0]));
|
||||
return masks[idx + 1];
|
||||
}
|
||||
|
||||
inline bool c_regex_traits<char>::isctype(char c, char_class_type mask)
|
||||
{
|
||||
using namespace BOOST_REGEX_DETAIL_NS;
|
||||
return
|
||||
((mask & char_class_space) && (std::isspace)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_print) && (std::isprint)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_cntrl) && (std::iscntrl)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_upper) && (std::isupper)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_lower) && (std::islower)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_alpha) && (std::isalpha)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_digit) && (std::isdigit)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_punct) && (std::ispunct)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_xdigit) && (std::isxdigit)(static_cast<unsigned char>(c)))
|
||||
|| ((mask & char_class_blank) && (std::isspace)(static_cast<unsigned char>(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c))
|
||||
|| ((mask & char_class_word) && (c == '_'))
|
||||
|| ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v')))
|
||||
|| ((mask & char_class_horizontal) && (std::isspace)(static_cast<unsigned char>(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != '\v'));
|
||||
}
|
||||
|
||||
inline c_regex_traits<char>::string_type c_regex_traits<char>::lookup_collatename(const char* p1, const char* p2)
|
||||
{
|
||||
std::string s(p1, p2);
|
||||
s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s);
|
||||
if (s.empty() && (p2 - p1 == 1))
|
||||
s.append(1, *p1);
|
||||
return s;
|
||||
}
|
||||
|
||||
inline int c_regex_traits<char>::value(char c, int radix)
|
||||
{
|
||||
char b[2] = { c, '\0', };
|
||||
char* ep;
|
||||
int result = std::strtol(b, &ep, radix);
|
||||
if (ep == b)
|
||||
return -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
|
||||
inline c_regex_traits<wchar_t>::string_type c_regex_traits<wchar_t>::transform(const wchar_t* p1, const wchar_t* p2)
|
||||
{
|
||||
std::size_t r;
|
||||
std::size_t s = 10;
|
||||
std::wstring src(p1, p2);
|
||||
std::wstring result(s, L' ');
|
||||
while (s < (r = std::wcsxfrm(&*result.begin(), src.c_str(), s)))
|
||||
{
|
||||
#if defined(_CPPLIB_VER)
|
||||
//
|
||||
// A bug in VC11 and 12 causes the program to hang if we pass a null-string
|
||||
// to std::strxfrm, but only for certain locales :-(
|
||||
// Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware).
|
||||
//
|
||||
if (r == INT_MAX)
|
||||
{
|
||||
result.erase();
|
||||
result.insert(result.begin(), static_cast<wchar_t>(0));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
result.append(r - s + 3, L' ');
|
||||
s = result.size();
|
||||
}
|
||||
result.erase(r);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline c_regex_traits<wchar_t>::string_type c_regex_traits<wchar_t>::transform_primary(const wchar_t* p1, const wchar_t* p2)
|
||||
{
|
||||
static wchar_t s_delim;
|
||||
static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast<const c_regex_traits<wchar_t>*>(0), &s_delim);
|
||||
std::wstring result;
|
||||
//
|
||||
// What we do here depends upon the format of the sort key returned by
|
||||
// sort key returned by this->transform:
|
||||
//
|
||||
switch (s_collate_type)
|
||||
{
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_C:
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown:
|
||||
// the best we can do is translate to lower case, then get a regular sort key:
|
||||
{
|
||||
result.assign(p1, p2);
|
||||
for (std::wstring::size_type i = 0; i < result.size(); ++i)
|
||||
result[i] = (std::towlower)(result[i]);
|
||||
result = c_regex_traits<wchar_t>::transform(&*result.begin(), &*result.begin() + result.size());
|
||||
break;
|
||||
}
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed:
|
||||
{
|
||||
// get a regular sort key, and then truncate it:
|
||||
result = c_regex_traits<wchar_t>::transform(&*result.begin(), &*result.begin() + result.size());
|
||||
result.erase(s_delim);
|
||||
break;
|
||||
}
|
||||
case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim:
|
||||
// get a regular sort key, and then truncate everything after the delim:
|
||||
result = c_regex_traits<wchar_t>::transform(&*result.begin(), &*result.begin() + result.size());
|
||||
if ((!result.empty()) && (result[0] == s_delim))
|
||||
break;
|
||||
std::size_t i;
|
||||
for (i = 0; i < result.size(); ++i)
|
||||
{
|
||||
if (result[i] == s_delim)
|
||||
break;
|
||||
}
|
||||
result.erase(i);
|
||||
break;
|
||||
}
|
||||
if (result.empty())
|
||||
result = std::wstring(1, char(0));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline c_regex_traits<wchar_t>::char_class_type c_regex_traits<wchar_t>::lookup_classname(const wchar_t* p1, const wchar_t* p2)
|
||||
{
|
||||
using namespace BOOST_REGEX_DETAIL_NS;
|
||||
static const char_class_type masks[] =
|
||||
{
|
||||
0,
|
||||
char_class_alnum,
|
||||
char_class_alpha,
|
||||
char_class_blank,
|
||||
char_class_cntrl,
|
||||
char_class_digit,
|
||||
char_class_digit,
|
||||
char_class_graph,
|
||||
char_class_horizontal,
|
||||
char_class_lower,
|
||||
char_class_lower,
|
||||
char_class_print,
|
||||
char_class_punct,
|
||||
char_class_space,
|
||||
char_class_space,
|
||||
char_class_upper,
|
||||
char_class_unicode,
|
||||
char_class_upper,
|
||||
char_class_vertical,
|
||||
char_class_alnum | char_class_word,
|
||||
char_class_alnum | char_class_word,
|
||||
char_class_xdigit,
|
||||
};
|
||||
|
||||
int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2);
|
||||
if (idx < 0)
|
||||
{
|
||||
std::wstring s(p1, p2);
|
||||
for (std::wstring::size_type i = 0; i < s.size(); ++i)
|
||||
s[i] = (std::towlower)(s[i]);
|
||||
idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size());
|
||||
}
|
||||
BOOST_REGEX_ASSERT(idx + 1 < static_cast<int>(sizeof(masks) / sizeof(masks[0])));
|
||||
return masks[idx + 1];
|
||||
}
|
||||
|
||||
inline bool c_regex_traits<wchar_t>::isctype(wchar_t c, char_class_type mask)
|
||||
{
|
||||
using namespace BOOST_REGEX_DETAIL_NS;
|
||||
return
|
||||
((mask & char_class_space) && (std::iswspace)(c))
|
||||
|| ((mask & char_class_print) && (std::iswprint)(c))
|
||||
|| ((mask & char_class_cntrl) && (std::iswcntrl)(c))
|
||||
|| ((mask & char_class_upper) && (std::iswupper)(c))
|
||||
|| ((mask & char_class_lower) && (std::iswlower)(c))
|
||||
|| ((mask & char_class_alpha) && (std::iswalpha)(c))
|
||||
|| ((mask & char_class_digit) && (std::iswdigit)(c))
|
||||
|| ((mask & char_class_punct) && (std::iswpunct)(c))
|
||||
|| ((mask & char_class_xdigit) && (std::iswxdigit)(c))
|
||||
|| ((mask & char_class_blank) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c))
|
||||
|| ((mask & char_class_word) && (c == '_'))
|
||||
|| ((mask & char_class_unicode) && (c & ~static_cast<wchar_t>(0xff)))
|
||||
|| ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == L'\v')))
|
||||
|| ((mask & char_class_horizontal) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != L'\v'));
|
||||
}
|
||||
|
||||
inline c_regex_traits<wchar_t>::string_type c_regex_traits<wchar_t>::lookup_collatename(const wchar_t* p1, const wchar_t* p2)
|
||||
{
|
||||
std::string name;
|
||||
// Usual msvc warning suppression does not work here with std::string template constructor.... use a workaround instead:
|
||||
for (const wchar_t* pos = p1; pos != p2; ++pos)
|
||||
name.push_back((char)*pos);
|
||||
name = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(name);
|
||||
if (!name.empty())
|
||||
return string_type(name.begin(), name.end());
|
||||
if (p2 - p1 == 1)
|
||||
return string_type(1, *p1);
|
||||
return string_type();
|
||||
}
|
||||
|
||||
inline int c_regex_traits<wchar_t>::value(wchar_t c, int radix)
|
||||
{
|
||||
#ifdef BOOST_BORLANDC
|
||||
// workaround for broken wcstol:
|
||||
if ((std::iswxdigit)(c) == 0)
|
||||
return -1;
|
||||
#endif
|
||||
wchar_t b[2] = { c, '\0', };
|
||||
wchar_t* ep;
|
||||
int result = std::wcstol(b, &ep, radix);
|
||||
if (ep == b)
|
||||
return -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE char_regex_traits.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares deprecated traits classes char_regex_traits<>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_REGEX_V5_CHAR_REGEX_TRAITS_HPP
|
||||
#define BOOST_REGEX_V5_CHAR_REGEX_TRAITS_HPP
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace deprecated{
|
||||
//
|
||||
// class char_regex_traits_i
|
||||
// provides case insensitive traits classes (deprecated):
|
||||
template <class charT>
|
||||
class char_regex_traits_i : public regex_traits<charT> {};
|
||||
|
||||
template<>
|
||||
class char_regex_traits_i<char> : public regex_traits<char>
|
||||
{
|
||||
public:
|
||||
typedef char char_type;
|
||||
typedef unsigned char uchar_type;
|
||||
typedef unsigned int size_type;
|
||||
typedef regex_traits<char> base_type;
|
||||
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
template<>
|
||||
class char_regex_traits_i<wchar_t> : public regex_traits<wchar_t>
|
||||
{
|
||||
public:
|
||||
typedef wchar_t char_type;
|
||||
typedef unsigned short uchar_type;
|
||||
typedef unsigned int size_type;
|
||||
typedef regex_traits<wchar_t> base_type;
|
||||
|
||||
};
|
||||
#endif
|
||||
} // namespace deprecated
|
||||
} // namespace boost
|
||||
|
||||
#endif // include
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE cregex.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares POSIX API functions
|
||||
* + boost::RegEx high level wrapper.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_CREGEX_HPP_INCLUDED
|
||||
#define BOOST_RE_CREGEX_HPP_INCLUDED
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
#include <boost/regex/v5/match_flags.hpp>
|
||||
#include <boost/regex/v5/error_type.hpp>
|
||||
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
#if !defined(BOOST_REGEX_NO_LIB) && !defined(BOOST_REGEX_SOURCE) && !defined(BOOST_ALL_NO_LIB) && defined(__cplusplus)
|
||||
# define BOOST_LIB_NAME boost_regex
|
||||
# if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
# endif
|
||||
# ifdef BOOST_REGEX_DIAG
|
||||
# define BOOST_LIB_DIAGNOSTIC
|
||||
# endif
|
||||
# include <boost/config/auto_link.hpp>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/* include these defs only for POSIX compatablity */
|
||||
#ifdef __cplusplus
|
||||
namespace boost{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
typedef std::ptrdiff_t regoff_t;
|
||||
typedef std::size_t regsize_t;
|
||||
#else
|
||||
typedef ptrdiff_t regoff_t;
|
||||
typedef size_t regsize_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int re_magic;
|
||||
#ifdef __cplusplus
|
||||
std::size_t re_nsub; /* number of parenthesized subexpressions */
|
||||
#else
|
||||
size_t re_nsub;
|
||||
#endif
|
||||
const char* re_endp; /* end pointer for REG_PEND */
|
||||
void* guts; /* none of your business :-) */
|
||||
match_flag_type eflags; /* none of your business :-) */
|
||||
} regex_tA;
|
||||
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
typedef struct
|
||||
{
|
||||
unsigned int re_magic;
|
||||
#ifdef __cplusplus
|
||||
std::size_t re_nsub; /* number of parenthesized subexpressions */
|
||||
#else
|
||||
size_t re_nsub;
|
||||
#endif
|
||||
const wchar_t* re_endp; /* end pointer for REG_PEND */
|
||||
void* guts; /* none of your business :-) */
|
||||
match_flag_type eflags; /* none of your business :-) */
|
||||
} regex_tW;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
regoff_t rm_so; /* start of match */
|
||||
regoff_t rm_eo; /* end of match */
|
||||
} regmatch_t;
|
||||
|
||||
/* regcomp() flags */
|
||||
typedef enum{
|
||||
REG_BASIC = 0000,
|
||||
REG_EXTENDED = 0001,
|
||||
REG_ICASE = 0002,
|
||||
REG_NOSUB = 0004,
|
||||
REG_NEWLINE = 0010,
|
||||
REG_NOSPEC = 0020,
|
||||
REG_PEND = 0040,
|
||||
REG_DUMP = 0200,
|
||||
REG_NOCOLLATE = 0400,
|
||||
REG_ESCAPE_IN_LISTS = 01000,
|
||||
REG_NEWLINE_ALT = 02000,
|
||||
REG_PERLEX = 04000,
|
||||
|
||||
REG_PERL = REG_EXTENDED | REG_NOCOLLATE | REG_ESCAPE_IN_LISTS | REG_PERLEX,
|
||||
REG_AWK = REG_EXTENDED | REG_ESCAPE_IN_LISTS,
|
||||
REG_GREP = REG_BASIC | REG_NEWLINE_ALT,
|
||||
REG_EGREP = REG_EXTENDED | REG_NEWLINE_ALT,
|
||||
|
||||
REG_ASSERT = 15,
|
||||
REG_INVARG = 16,
|
||||
REG_ATOI = 255, /* convert name to number (!) */
|
||||
REG_ITOA = 0400 /* convert number to name (!) */
|
||||
} reg_comp_flags;
|
||||
|
||||
/* regexec() flags */
|
||||
typedef enum{
|
||||
REG_NOTBOL = 00001,
|
||||
REG_NOTEOL = 00002,
|
||||
REG_STARTEND = 00004
|
||||
} reg_exec_flags;
|
||||
|
||||
/*
|
||||
* POSIX error codes:
|
||||
*/
|
||||
typedef unsigned reg_error_t;
|
||||
typedef reg_error_t reg_errcode_t; /* backwards compatibility */
|
||||
|
||||
static const reg_error_t REG_NOERROR = 0; /* Success. */
|
||||
static const reg_error_t REG_NOMATCH = 1; /* Didn't find a match (for regexec). */
|
||||
|
||||
/* POSIX regcomp return error codes. (In the order listed in the
|
||||
standard.) */
|
||||
static const reg_error_t REG_BADPAT = 2; /* Invalid pattern. */
|
||||
static const reg_error_t REG_ECOLLATE = 3; /* Undefined collating element. */
|
||||
static const reg_error_t REG_ECTYPE = 4; /* Invalid character class name. */
|
||||
static const reg_error_t REG_EESCAPE = 5; /* Trailing backslash. */
|
||||
static const reg_error_t REG_ESUBREG = 6; /* Invalid back reference. */
|
||||
static const reg_error_t REG_EBRACK = 7; /* Unmatched left bracket. */
|
||||
static const reg_error_t REG_EPAREN = 8; /* Parenthesis imbalance. */
|
||||
static const reg_error_t REG_EBRACE = 9; /* Unmatched \{. */
|
||||
static const reg_error_t REG_BADBR = 10; /* Invalid contents of \{\}. */
|
||||
static const reg_error_t REG_ERANGE = 11; /* Invalid range end. */
|
||||
static const reg_error_t REG_ESPACE = 12; /* Ran out of memory. */
|
||||
static const reg_error_t REG_BADRPT = 13; /* No preceding re for repetition op. */
|
||||
static const reg_error_t REG_EEND = 14; /* unexpected end of expression */
|
||||
static const reg_error_t REG_ESIZE = 15; /* expression too big */
|
||||
static const reg_error_t REG_ERPAREN = 8; /* = REG_EPAREN : unmatched right parenthesis */
|
||||
static const reg_error_t REG_EMPTY = 17; /* empty expression */
|
||||
static const reg_error_t REG_E_MEMORY = 15; /* = REG_ESIZE : out of memory */
|
||||
static const reg_error_t REG_ECOMPLEXITY = 18; /* complexity too high */
|
||||
static const reg_error_t REG_ESTACK = 19; /* out of stack space */
|
||||
static const reg_error_t REG_E_PERL = 20; /* Perl (?...) error */
|
||||
static const reg_error_t REG_E_UNKNOWN = 21; /* unknown error */
|
||||
static const reg_error_t REG_ENOSYS = 21; /* = REG_E_UNKNOWN : Reserved. */
|
||||
|
||||
BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompA(regex_tA*, const char*, int);
|
||||
BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorA(int, const regex_tA*, char*, regsize_t);
|
||||
BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecA(const regex_tA*, const char*, regsize_t, regmatch_t*, int);
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeA(regex_tA*);
|
||||
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompW(regex_tW*, const wchar_t*, int);
|
||||
BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorW(int, const regex_tW*, wchar_t*, regsize_t);
|
||||
BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecW(const regex_tW*, const wchar_t*, regsize_t, regmatch_t*, int);
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeW(regex_tW*);
|
||||
#endif
|
||||
|
||||
#ifdef UNICODE
|
||||
#define regcomp regcompW
|
||||
#define regerror regerrorW
|
||||
#define regexec regexecW
|
||||
#define regfree regfreeW
|
||||
#define regex_t regex_tW
|
||||
#else
|
||||
#define regcomp regcompA
|
||||
#define regerror regerrorA
|
||||
#define regexec regexecA
|
||||
#define regfree regfreeA
|
||||
#define regex_t regex_tA
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
} /* namespace */
|
||||
#endif
|
||||
|
||||
#endif /* include guard */
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2003-2005
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE error_type.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares regular expression error type enumerator.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_ERROR_TYPE_HPP
|
||||
#define BOOST_REGEX_ERROR_TYPE_HPP
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace boost{
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace regex_constants{
|
||||
|
||||
enum error_type{
|
||||
|
||||
error_ok = 0, /* not used */
|
||||
error_no_match = 1, /* not used */
|
||||
error_bad_pattern = 2,
|
||||
error_collate = 3,
|
||||
error_ctype = 4,
|
||||
error_escape = 5,
|
||||
error_backref = 6,
|
||||
error_brack = 7,
|
||||
error_paren = 8,
|
||||
error_brace = 9,
|
||||
error_badbrace = 10,
|
||||
error_range = 11,
|
||||
error_space = 12,
|
||||
error_badrepeat = 13,
|
||||
error_end = 14, /* not used */
|
||||
error_size = 15,
|
||||
error_right_paren = 16, /* not used */
|
||||
error_empty = 17,
|
||||
error_complexity = 18,
|
||||
error_stack = 19,
|
||||
error_perl_extension = 20,
|
||||
error_unknown = 21
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_match.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Iterator traits for selecting an iterator type as
|
||||
* an integral constant expression.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_REGEX_ITERATOR_CATEGORY_HPP
|
||||
#define BOOST_REGEX_ITERATOR_CATEGORY_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost{
|
||||
namespace detail{
|
||||
|
||||
template <class I>
|
||||
struct is_random_imp
|
||||
{
|
||||
private:
|
||||
typedef typename std::iterator_traits<I>::iterator_category cat;
|
||||
public:
|
||||
static const bool value = (std::is_convertible<cat*, std::random_access_iterator_tag*>::value);
|
||||
};
|
||||
|
||||
template <class I>
|
||||
struct is_random_pointer_imp
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <bool is_pointer_type>
|
||||
struct is_random_imp_selector
|
||||
{
|
||||
template <class I>
|
||||
struct rebind
|
||||
{
|
||||
typedef is_random_imp<I> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_random_imp_selector<true>
|
||||
{
|
||||
template <class I>
|
||||
struct rebind
|
||||
{
|
||||
typedef is_random_pointer_imp<I> type;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class I>
|
||||
struct is_random_access_iterator
|
||||
{
|
||||
private:
|
||||
typedef detail::is_random_imp_selector< std::is_pointer<I>::value> selector;
|
||||
typedef typename selector::template rebind<I> bound_type;
|
||||
typedef typename bound_type::type answer;
|
||||
public:
|
||||
static const bool value = answer::value;
|
||||
};
|
||||
|
||||
template <class I>
|
||||
const bool is_random_access_iterator<I>::value;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE iterator_traits.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares iterator traits workarounds.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_ITERATOR_TRAITS_HPP
|
||||
#define BOOST_REGEX_V5_ITERATOR_TRAITS_HPP
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
template <class T>
|
||||
struct regex_iterator_traits : public std::iterator_traits<T> {};
|
||||
|
||||
} // namespace BOOST_REGEX_DETAIL_NS
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE match_flags.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares match_flags type.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_MATCH_FLAGS
|
||||
#define BOOST_REGEX_V5_MATCH_FLAGS
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <cstdint>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace boost{
|
||||
namespace regex_constants{
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#if BOOST_REGEX_MSVC >= 1800
|
||||
#pragma warning(disable : 26812)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum _match_flags
|
||||
{
|
||||
match_default = 0,
|
||||
match_not_bol = 1, /* first is not start of line */
|
||||
match_not_eol = match_not_bol << 1, /* last is not end of line */
|
||||
match_not_bob = match_not_eol << 1, /* first is not start of buffer */
|
||||
match_not_eob = match_not_bob << 1, /* last is not end of buffer */
|
||||
match_not_bow = match_not_eob << 1, /* first is not start of word */
|
||||
match_not_eow = match_not_bow << 1, /* last is not end of word */
|
||||
match_not_dot_newline = match_not_eow << 1, /* \n is not matched by '.' */
|
||||
match_not_dot_null = match_not_dot_newline << 1, /* '\0' is not matched by '.' */
|
||||
match_prev_avail = match_not_dot_null << 1, /* *--first is a valid expression */
|
||||
match_init = match_prev_avail << 1, /* internal use */
|
||||
match_any = match_init << 1, /* don't care what we match */
|
||||
match_not_null = match_any << 1, /* string can't be null */
|
||||
match_continuous = match_not_null << 1, /* each grep match must continue from */
|
||||
/* uninterrupted from the previous one */
|
||||
match_partial = match_continuous << 1, /* find partial matches */
|
||||
|
||||
match_stop = match_partial << 1, /* stop after first match (grep) V3 only */
|
||||
match_not_initial_null = match_stop, /* don't match initial null, V4 only */
|
||||
match_all = match_stop << 1, /* must find the whole of input even if match_any is set */
|
||||
match_perl = match_all << 1, /* Use perl matching rules */
|
||||
match_posix = match_perl << 1, /* Use POSIX matching rules */
|
||||
match_nosubs = match_posix << 1, /* don't trap marked subs */
|
||||
match_extra = match_nosubs << 1, /* include full capture information for repeated captures */
|
||||
match_single_line = match_extra << 1, /* treat text as single line and ignore any \n's when matching ^ and $. */
|
||||
match_unused1 = match_single_line << 1, /* unused */
|
||||
match_unused2 = match_unused1 << 1, /* unused */
|
||||
match_unused3 = match_unused2 << 1, /* unused */
|
||||
match_max = match_unused3,
|
||||
|
||||
format_perl = 0, /* perl style replacement */
|
||||
format_default = 0, /* ditto. */
|
||||
format_sed = match_max << 1, /* sed style replacement. */
|
||||
format_all = format_sed << 1, /* enable all extensions to syntax. */
|
||||
format_no_copy = format_all << 1, /* don't copy non-matching segments. */
|
||||
format_first_only = format_no_copy << 1, /* Only replace first occurrence. */
|
||||
format_is_if = format_first_only << 1, /* internal use only. */
|
||||
format_literal = format_is_if << 1, /* treat string as a literal */
|
||||
|
||||
match_not_any = match_not_bol | match_not_eol | match_not_bob
|
||||
| match_not_eob | match_not_bow | match_not_eow | match_not_dot_newline
|
||||
| match_not_dot_null | match_prev_avail | match_init | match_not_null
|
||||
| match_continuous | match_partial | match_stop | match_not_initial_null
|
||||
| match_stop | match_all | match_perl | match_posix | match_nosubs
|
||||
| match_extra | match_single_line | match_unused1 | match_unused2
|
||||
| match_unused3 | match_max | format_perl | format_default | format_sed
|
||||
| format_all | format_no_copy | format_first_only | format_is_if
|
||||
| format_literal
|
||||
|
||||
|
||||
} match_flags;
|
||||
|
||||
typedef match_flags match_flag_type;
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline match_flags operator&(match_flags m1, match_flags m2)
|
||||
{ return static_cast<match_flags>(static_cast<std::int32_t>(m1) & static_cast<std::int32_t>(m2)); }
|
||||
inline match_flags operator|(match_flags m1, match_flags m2)
|
||||
{ return static_cast<match_flags>(static_cast<std::int32_t>(m1) | static_cast<std::int32_t>(m2)); }
|
||||
inline match_flags operator^(match_flags m1, match_flags m2)
|
||||
{ return static_cast<match_flags>(static_cast<std::int32_t>(m1) ^ static_cast<std::int32_t>(m2)); }
|
||||
inline match_flags operator~(match_flags m1)
|
||||
{ return static_cast<match_flags>(~static_cast<std::int32_t>(m1)); }
|
||||
inline match_flags& operator&=(match_flags& m1, match_flags m2)
|
||||
{ m1 = m1&m2; return m1; }
|
||||
inline match_flags& operator|=(match_flags& m1, match_flags m2)
|
||||
{ m1 = m1|m2; return m1; }
|
||||
inline match_flags& operator^=(match_flags& m1, match_flags m2)
|
||||
{ m1 = m1^m2; return m1; }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* namespace regex_constants */
|
||||
/*
|
||||
* import names into boost for backwards compatibility:
|
||||
*/
|
||||
using regex_constants::match_flag_type;
|
||||
using regex_constants::match_default;
|
||||
using regex_constants::match_not_bol;
|
||||
using regex_constants::match_not_eol;
|
||||
using regex_constants::match_not_bob;
|
||||
using regex_constants::match_not_eob;
|
||||
using regex_constants::match_not_bow;
|
||||
using regex_constants::match_not_eow;
|
||||
using regex_constants::match_not_dot_newline;
|
||||
using regex_constants::match_not_dot_null;
|
||||
using regex_constants::match_prev_avail;
|
||||
/* using regex_constants::match_init; */
|
||||
using regex_constants::match_any;
|
||||
using regex_constants::match_not_null;
|
||||
using regex_constants::match_continuous;
|
||||
using regex_constants::match_partial;
|
||||
/*using regex_constants::match_stop; */
|
||||
using regex_constants::match_all;
|
||||
using regex_constants::match_perl;
|
||||
using regex_constants::match_posix;
|
||||
using regex_constants::match_nosubs;
|
||||
using regex_constants::match_extra;
|
||||
using regex_constants::match_single_line;
|
||||
/*using regex_constants::match_max; */
|
||||
using regex_constants::format_all;
|
||||
using regex_constants::format_sed;
|
||||
using regex_constants::format_perl;
|
||||
using regex_constants::format_default;
|
||||
using regex_constants::format_no_copy;
|
||||
using regex_constants::format_first_only;
|
||||
/*using regex_constants::format_is_if;*/
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
} /* namespace boost */
|
||||
#endif /* __cplusplus */
|
||||
#endif /* include guard */
|
||||
|
||||
@@ -1,667 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2009
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE match_results.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares template class match_results.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_MATCH_RESULTS_HPP
|
||||
#define BOOST_REGEX_V5_MATCH_RESULTS_HPP
|
||||
|
||||
namespace boost{
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251 4459)
|
||||
#if BOOST_REGEX_MSVC < 1700
|
||||
# pragma warning(disable : 4231)
|
||||
#endif
|
||||
# if BOOST_REGEX_MSVC < 1600
|
||||
# pragma warning(disable : 4660)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
class named_subexpressions;
|
||||
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator>
|
||||
class match_results
|
||||
{
|
||||
private:
|
||||
typedef std::vector<sub_match<BidiIterator>, Allocator> vector_type;
|
||||
public:
|
||||
typedef sub_match<BidiIterator> value_type;
|
||||
typedef typename std::allocator_traits<Allocator>::value_type const & const_reference;
|
||||
typedef const_reference reference;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
typedef const_iterator iterator;
|
||||
typedef typename std::iterator_traits<
|
||||
BidiIterator>::difference_type difference_type;
|
||||
typedef typename std::allocator_traits<Allocator>::size_type size_type;
|
||||
typedef Allocator allocator_type;
|
||||
typedef typename std::iterator_traits<
|
||||
BidiIterator>::value_type char_type;
|
||||
typedef std::basic_string<char_type> string_type;
|
||||
typedef BOOST_REGEX_DETAIL_NS::named_subexpressions named_sub_type;
|
||||
|
||||
// construct/copy/destroy:
|
||||
explicit match_results(const Allocator& a = Allocator())
|
||||
: m_subs(a), m_base(), m_null(), m_last_closed_paren(0), m_is_singular(true) {}
|
||||
//
|
||||
// IMPORTANT: in the code below, the crazy looking checks around m_is_singular are
|
||||
// all required because it is illegal to copy a singular iterator.
|
||||
// See https://svn.boost.org/trac/boost/ticket/3632.
|
||||
//
|
||||
match_results(const match_results& m)
|
||||
: m_subs(m.m_subs), m_base(), m_null(), m_named_subs(m.m_named_subs), m_last_closed_paren(m.m_last_closed_paren), m_is_singular(m.m_is_singular)
|
||||
{
|
||||
if(!m_is_singular)
|
||||
{
|
||||
m_base = m.m_base;
|
||||
m_null = m.m_null;
|
||||
}
|
||||
}
|
||||
match_results& operator=(const match_results& m)
|
||||
{
|
||||
m_subs = m.m_subs;
|
||||
m_named_subs = m.m_named_subs;
|
||||
m_last_closed_paren = m.m_last_closed_paren;
|
||||
m_is_singular = m.m_is_singular;
|
||||
if(!m_is_singular)
|
||||
{
|
||||
m_base = m.m_base;
|
||||
m_null = m.m_null;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~match_results(){}
|
||||
|
||||
// size:
|
||||
size_type size() const
|
||||
{ return empty() ? 0 : m_subs.size() - 2; }
|
||||
size_type max_size() const
|
||||
{ return m_subs.max_size(); }
|
||||
bool empty() const
|
||||
{ return m_subs.size() < 2; }
|
||||
// element access:
|
||||
difference_type length(int sub = 0) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
sub += 2;
|
||||
if((sub < (int)m_subs.size()) && (sub > 0))
|
||||
return m_subs[sub].length();
|
||||
return 0;
|
||||
}
|
||||
difference_type length(const char_type* sub) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
const char_type* sub_end = sub;
|
||||
while(*sub_end) ++sub_end;
|
||||
return length(named_subexpression_index(sub, sub_end));
|
||||
}
|
||||
template <class charT>
|
||||
difference_type length(const charT* sub) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
const charT* sub_end = sub;
|
||||
while(*sub_end) ++sub_end;
|
||||
return length(named_subexpression_index(sub, sub_end));
|
||||
}
|
||||
template <class charT, class Traits, class A>
|
||||
difference_type length(const std::basic_string<charT, Traits, A>& sub) const
|
||||
{
|
||||
return length(sub.c_str());
|
||||
}
|
||||
difference_type position(size_type sub = 0) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
sub += 2;
|
||||
if(sub < m_subs.size())
|
||||
{
|
||||
const sub_match<BidiIterator>& s = m_subs[sub];
|
||||
if(s.matched || (sub == 2))
|
||||
{
|
||||
return std::distance((BidiIterator)(m_base), (BidiIterator)(s.first));
|
||||
}
|
||||
}
|
||||
return ~static_cast<difference_type>(0);
|
||||
}
|
||||
difference_type position(const char_type* sub) const
|
||||
{
|
||||
const char_type* sub_end = sub;
|
||||
while(*sub_end) ++sub_end;
|
||||
return position(named_subexpression_index(sub, sub_end));
|
||||
}
|
||||
template <class charT>
|
||||
difference_type position(const charT* sub) const
|
||||
{
|
||||
const charT* sub_end = sub;
|
||||
while(*sub_end) ++sub_end;
|
||||
return position(named_subexpression_index(sub, sub_end));
|
||||
}
|
||||
template <class charT, class Traits, class A>
|
||||
difference_type position(const std::basic_string<charT, Traits, A>& sub) const
|
||||
{
|
||||
return position(sub.c_str());
|
||||
}
|
||||
string_type str(int sub = 0) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
sub += 2;
|
||||
string_type result;
|
||||
if(sub < (int)m_subs.size() && (sub > 0))
|
||||
{
|
||||
const sub_match<BidiIterator>& s = m_subs[sub];
|
||||
if(s.matched)
|
||||
{
|
||||
result = s.str();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
string_type str(const char_type* sub) const
|
||||
{
|
||||
return (*this)[sub].str();
|
||||
}
|
||||
template <class Traits, class A>
|
||||
string_type str(const std::basic_string<char_type, Traits, A>& sub) const
|
||||
{
|
||||
return (*this)[sub].str();
|
||||
}
|
||||
template <class charT>
|
||||
string_type str(const charT* sub) const
|
||||
{
|
||||
return (*this)[sub].str();
|
||||
}
|
||||
template <class charT, class Traits, class A>
|
||||
string_type str(const std::basic_string<charT, Traits, A>& sub) const
|
||||
{
|
||||
return (*this)[sub].str();
|
||||
}
|
||||
const_reference operator[](int sub) const
|
||||
{
|
||||
if(m_is_singular && m_subs.empty())
|
||||
raise_logic_error();
|
||||
sub += 2;
|
||||
if(sub < (int)m_subs.size() && (sub >= 0))
|
||||
{
|
||||
return m_subs[sub];
|
||||
}
|
||||
return m_null;
|
||||
}
|
||||
//
|
||||
// Named sub-expressions:
|
||||
//
|
||||
const_reference named_subexpression(const char_type* i, const char_type* j) const
|
||||
{
|
||||
//
|
||||
// Scan for the leftmost *matched* subexpression with the specified named:
|
||||
//
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type r = m_named_subs->equal_range(i, j);
|
||||
while((r.first != r.second) && ((*this)[r.first->index].matched == false))
|
||||
++r.first;
|
||||
return r.first != r.second ? (*this)[r.first->index] : m_null;
|
||||
}
|
||||
template <class charT>
|
||||
const_reference named_subexpression(const charT* i, const charT* j) const
|
||||
{
|
||||
static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
|
||||
if(i == j)
|
||||
return m_null;
|
||||
std::vector<char_type> s;
|
||||
while(i != j)
|
||||
s.insert(s.end(), *i++);
|
||||
return named_subexpression(&*s.begin(), &*s.begin() + s.size());
|
||||
}
|
||||
int named_subexpression_index(const char_type* i, const char_type* j) const
|
||||
{
|
||||
//
|
||||
// Scan for the leftmost *matched* subexpression with the specified named.
|
||||
// If none found then return the leftmost expression with that name,
|
||||
// otherwise an invalid index:
|
||||
//
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type s, r;
|
||||
s = r = m_named_subs->equal_range(i, j);
|
||||
while((r.first != r.second) && ((*this)[r.first->index].matched == false))
|
||||
++r.first;
|
||||
if(r.first == r.second)
|
||||
r = s;
|
||||
return r.first != r.second ? r.first->index : -20;
|
||||
}
|
||||
template <class charT>
|
||||
int named_subexpression_index(const charT* i, const charT* j) const
|
||||
{
|
||||
static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
|
||||
if(i == j)
|
||||
return -20;
|
||||
std::vector<char_type> s;
|
||||
while(i != j)
|
||||
s.insert(s.end(), *i++);
|
||||
return named_subexpression_index(&*s.begin(), &*s.begin() + s.size());
|
||||
}
|
||||
template <class Traits, class A>
|
||||
const_reference operator[](const std::basic_string<char_type, Traits, A>& s) const
|
||||
{
|
||||
return named_subexpression(s.c_str(), s.c_str() + s.size());
|
||||
}
|
||||
const_reference operator[](const char_type* p) const
|
||||
{
|
||||
const char_type* e = p;
|
||||
while(*e) ++e;
|
||||
return named_subexpression(p, e);
|
||||
}
|
||||
|
||||
template <class charT>
|
||||
const_reference operator[](const charT* p) const
|
||||
{
|
||||
static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
|
||||
if(*p == 0)
|
||||
return m_null;
|
||||
std::vector<char_type> s;
|
||||
while(*p)
|
||||
s.insert(s.end(), *p++);
|
||||
return named_subexpression(&*s.begin(), &*s.begin() + s.size());
|
||||
}
|
||||
template <class charT, class Traits, class A>
|
||||
const_reference operator[](const std::basic_string<charT, Traits, A>& ns) const
|
||||
{
|
||||
static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
|
||||
if(ns.empty())
|
||||
return m_null;
|
||||
std::vector<char_type> s;
|
||||
for(unsigned i = 0; i < ns.size(); ++i)
|
||||
s.insert(s.end(), ns[i]);
|
||||
return named_subexpression(&*s.begin(), &*s.begin() + s.size());
|
||||
}
|
||||
|
||||
const_reference prefix() const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
return (*this)[-1];
|
||||
}
|
||||
|
||||
const_reference suffix() const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
return (*this)[-2];
|
||||
}
|
||||
const_iterator begin() const
|
||||
{
|
||||
return (m_subs.size() > 2) ? (m_subs.begin() + 2) : m_subs.end();
|
||||
}
|
||||
const_iterator end() const
|
||||
{
|
||||
return m_subs.end();
|
||||
}
|
||||
// format:
|
||||
template <class OutputIterator, class Functor>
|
||||
OutputIterator format(OutputIterator out,
|
||||
Functor fmt,
|
||||
match_flag_type flags = format_default) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, OutputIterator>::type F;
|
||||
F func(fmt);
|
||||
return func(*this, out, flags);
|
||||
}
|
||||
template <class Functor>
|
||||
string_type format(Functor fmt, match_flag_type flags = format_default) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
std::basic_string<char_type> result;
|
||||
BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> > i(result);
|
||||
|
||||
typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> > >::type F;
|
||||
F func(fmt);
|
||||
|
||||
func(*this, i, flags);
|
||||
return result;
|
||||
}
|
||||
// format with locale:
|
||||
template <class OutputIterator, class Functor, class RegexT>
|
||||
OutputIterator format(OutputIterator out,
|
||||
Functor fmt,
|
||||
match_flag_type flags,
|
||||
const RegexT& re) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
typedef ::boost::regex_traits_wrapper<typename RegexT::traits_type> traits_type;
|
||||
typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, OutputIterator, traits_type>::type F;
|
||||
F func(fmt);
|
||||
return func(*this, out, flags, re.get_traits());
|
||||
}
|
||||
template <class RegexT, class Functor>
|
||||
string_type format(Functor fmt,
|
||||
match_flag_type flags,
|
||||
const RegexT& re) const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
typedef ::boost::regex_traits_wrapper<typename RegexT::traits_type> traits_type;
|
||||
std::basic_string<char_type> result;
|
||||
BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> > i(result);
|
||||
|
||||
typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> >, traits_type >::type F;
|
||||
F func(fmt);
|
||||
|
||||
func(*this, i, flags, re.get_traits());
|
||||
return result;
|
||||
}
|
||||
|
||||
const_reference get_last_closed_paren()const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
return m_last_closed_paren == 0 ? m_null : (*this)[m_last_closed_paren];
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const
|
||||
{
|
||||
return m_subs.get_allocator();
|
||||
}
|
||||
void swap(match_results& that)
|
||||
{
|
||||
std::swap(m_subs, that.m_subs);
|
||||
std::swap(m_named_subs, that.m_named_subs);
|
||||
std::swap(m_last_closed_paren, that.m_last_closed_paren);
|
||||
if(m_is_singular)
|
||||
{
|
||||
if(!that.m_is_singular)
|
||||
{
|
||||
m_base = that.m_base;
|
||||
m_null = that.m_null;
|
||||
}
|
||||
}
|
||||
else if(that.m_is_singular)
|
||||
{
|
||||
that.m_base = m_base;
|
||||
that.m_null = m_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::swap(m_base, that.m_base);
|
||||
std::swap(m_null, that.m_null);
|
||||
}
|
||||
std::swap(m_is_singular, that.m_is_singular);
|
||||
}
|
||||
bool operator==(const match_results& that)const
|
||||
{
|
||||
if(m_is_singular)
|
||||
{
|
||||
return that.m_is_singular;
|
||||
}
|
||||
else if(that.m_is_singular)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (m_subs == that.m_subs) && (m_base == that.m_base) && (m_last_closed_paren == that.m_last_closed_paren);
|
||||
}
|
||||
bool operator!=(const match_results& that)const
|
||||
{ return !(*this == that); }
|
||||
|
||||
#ifdef BOOST_REGEX_MATCH_EXTRA
|
||||
typedef typename sub_match<BidiIterator>::capture_sequence_type capture_sequence_type;
|
||||
|
||||
const capture_sequence_type& captures(int i)const
|
||||
{
|
||||
if(m_is_singular)
|
||||
raise_logic_error();
|
||||
return (*this)[i].captures();
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// private access functions:
|
||||
void set_second(BidiIterator i)
|
||||
{
|
||||
BOOST_REGEX_ASSERT(m_subs.size() > 2);
|
||||
m_subs[2].second = i;
|
||||
m_subs[2].matched = true;
|
||||
m_subs[0].first = i;
|
||||
m_subs[0].matched = (m_subs[0].first != m_subs[0].second);
|
||||
m_null.first = i;
|
||||
m_null.second = i;
|
||||
m_null.matched = false;
|
||||
m_is_singular = false;
|
||||
}
|
||||
|
||||
void set_second(BidiIterator i, size_type pos, bool m = true, bool escape_k = false)
|
||||
{
|
||||
if(pos)
|
||||
m_last_closed_paren = static_cast<int>(pos);
|
||||
pos += 2;
|
||||
BOOST_REGEX_ASSERT(m_subs.size() > pos);
|
||||
m_subs[pos].second = i;
|
||||
m_subs[pos].matched = m;
|
||||
if((pos == 2) && !escape_k)
|
||||
{
|
||||
m_subs[0].first = i;
|
||||
m_subs[0].matched = (m_subs[0].first != m_subs[0].second);
|
||||
m_null.first = i;
|
||||
m_null.second = i;
|
||||
m_null.matched = false;
|
||||
m_is_singular = false;
|
||||
}
|
||||
}
|
||||
void set_size(size_type n, BidiIterator i, BidiIterator j)
|
||||
{
|
||||
value_type v(j);
|
||||
size_type len = m_subs.size();
|
||||
if(len > n + 2)
|
||||
{
|
||||
m_subs.erase(m_subs.begin()+n+2, m_subs.end());
|
||||
std::fill(m_subs.begin(), m_subs.end(), v);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill(m_subs.begin(), m_subs.end(), v);
|
||||
if(n+2 != len)
|
||||
m_subs.insert(m_subs.end(), n+2-len, v);
|
||||
}
|
||||
m_subs[1].first = i;
|
||||
m_last_closed_paren = 0;
|
||||
}
|
||||
void set_base(BidiIterator pos)
|
||||
{
|
||||
m_base = pos;
|
||||
}
|
||||
BidiIterator base()const
|
||||
{
|
||||
return m_base;
|
||||
}
|
||||
void set_first(BidiIterator i)
|
||||
{
|
||||
BOOST_REGEX_ASSERT(m_subs.size() > 2);
|
||||
// set up prefix:
|
||||
m_subs[1].second = i;
|
||||
m_subs[1].matched = (m_subs[1].first != i);
|
||||
// set up $0:
|
||||
m_subs[2].first = i;
|
||||
// zero out everything else:
|
||||
for(size_type n = 3; n < m_subs.size(); ++n)
|
||||
{
|
||||
m_subs[n].first = m_subs[n].second = m_subs[0].second;
|
||||
m_subs[n].matched = false;
|
||||
}
|
||||
}
|
||||
void set_first(BidiIterator i, size_type pos, bool escape_k = false)
|
||||
{
|
||||
BOOST_REGEX_ASSERT(pos+2 < m_subs.size());
|
||||
if(pos || escape_k)
|
||||
{
|
||||
m_subs[pos+2].first = i;
|
||||
if(escape_k)
|
||||
{
|
||||
m_subs[1].second = i;
|
||||
m_subs[1].matched = (m_subs[1].first != m_subs[1].second);
|
||||
}
|
||||
}
|
||||
else
|
||||
set_first(i);
|
||||
}
|
||||
void maybe_assign(const match_results<BidiIterator, Allocator>& m);
|
||||
|
||||
void set_named_subs(std::shared_ptr<named_sub_type> subs)
|
||||
{
|
||||
m_named_subs = subs;
|
||||
}
|
||||
|
||||
private:
|
||||
//
|
||||
// Error handler called when an uninitialized match_results is accessed:
|
||||
//
|
||||
static void raise_logic_error()
|
||||
{
|
||||
std::logic_error e("Attempt to access an uninitialized boost::match_results<> class.");
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
boost::throw_exception(e);
|
||||
#else
|
||||
throw e;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
vector_type m_subs; // subexpressions
|
||||
BidiIterator m_base; // where the search started from
|
||||
sub_match<BidiIterator> m_null; // a null match
|
||||
std::shared_ptr<named_sub_type> m_named_subs; // Shared copy of named subs in the regex object
|
||||
int m_last_closed_paren; // Last ) to be seen - used for formatting
|
||||
bool m_is_singular; // True if our stored iterators are singular
|
||||
};
|
||||
|
||||
template <class BidiIterator, class Allocator>
|
||||
void match_results<BidiIterator, Allocator>::maybe_assign(const match_results<BidiIterator, Allocator>& m)
|
||||
{
|
||||
if(m_is_singular)
|
||||
{
|
||||
*this = m;
|
||||
return;
|
||||
}
|
||||
const_iterator p1, p2;
|
||||
p1 = begin();
|
||||
p2 = m.begin();
|
||||
//
|
||||
// Distances are measured from the start of *this* match, unless this isn't
|
||||
// a valid match in which case we use the start of the whole sequence. Note that
|
||||
// no subsequent match-candidate can ever be to the left of the first match found.
|
||||
// This ensures that when we are using bidirectional iterators, that distances
|
||||
// measured are as short as possible, and therefore as efficient as possible
|
||||
// to compute. Finally note that we don't use the "matched" data member to test
|
||||
// whether a sub-expression is a valid match, because partial matches set this
|
||||
// to false for sub-expression 0.
|
||||
//
|
||||
BidiIterator l_end = this->suffix().second;
|
||||
BidiIterator l_base = (p1->first == l_end) ? this->prefix().first : (*this)[0].first;
|
||||
difference_type len1 = 0;
|
||||
difference_type len2 = 0;
|
||||
difference_type base1 = 0;
|
||||
difference_type base2 = 0;
|
||||
std::size_t i;
|
||||
for(i = 0; i < size(); ++i, ++p1, ++p2)
|
||||
{
|
||||
//
|
||||
// Leftmost takes priority over longest; handle special cases
|
||||
// where distances need not be computed first (an optimisation
|
||||
// for bidirectional iterators: ensure that we don't accidently
|
||||
// compute the length of the whole sequence, as this can be really
|
||||
// expensive).
|
||||
//
|
||||
if(p1->first == l_end)
|
||||
{
|
||||
if(p2->first != l_end)
|
||||
{
|
||||
// p2 must be better than p1, and no need to calculate
|
||||
// actual distances:
|
||||
base1 = 1;
|
||||
base2 = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// *p1 and *p2 are either unmatched or match end-of sequence,
|
||||
// either way no need to calculate distances:
|
||||
if((p1->matched == false) && (p2->matched == true))
|
||||
break;
|
||||
if((p1->matched == true) && (p2->matched == false))
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(p2->first == l_end)
|
||||
{
|
||||
// p1 better than p2, and no need to calculate distances:
|
||||
return;
|
||||
}
|
||||
base1 = std::distance(l_base, p1->first);
|
||||
base2 = std::distance(l_base, p2->first);
|
||||
BOOST_REGEX_ASSERT(base1 >= 0);
|
||||
BOOST_REGEX_ASSERT(base2 >= 0);
|
||||
if(base1 < base2) return;
|
||||
if(base2 < base1) break;
|
||||
|
||||
len1 = std::distance((BidiIterator)p1->first, (BidiIterator)p1->second);
|
||||
len2 = std::distance((BidiIterator)p2->first, (BidiIterator)p2->second);
|
||||
BOOST_REGEX_ASSERT(len1 >= 0);
|
||||
BOOST_REGEX_ASSERT(len2 >= 0);
|
||||
if((len1 != len2) || ((p1->matched == false) && (p2->matched == true)))
|
||||
break;
|
||||
if((p1->matched == true) && (p2->matched == false))
|
||||
return;
|
||||
}
|
||||
if(i == size())
|
||||
return;
|
||||
if(base2 < base1)
|
||||
*this = m;
|
||||
else if((len2 > len1) || ((p1->matched == false) && (p2->matched == true)) )
|
||||
*this = m;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator>
|
||||
void swap(match_results<BidiIterator, Allocator>& a, match_results<BidiIterator, Allocator>& b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template <class charT, class traits, class BidiIterator, class Allocator>
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator << (std::basic_ostream<charT, traits>& os,
|
||||
const match_results<BidiIterator, Allocator>& s)
|
||||
{
|
||||
return (os << s.str());
|
||||
}
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE mem_block_cache.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: memory block cache used by the non-recursive matcher.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_MEM_BLOCK_CACHE_HPP
|
||||
#define BOOST_REGEX_V5_MEM_BLOCK_CACHE_HPP
|
||||
|
||||
#include <new>
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_CXX11_HDR_ATOMIC
|
||||
#include <atomic>
|
||||
#if ATOMIC_POINTER_LOCK_FREE == 2
|
||||
#define BOOST_REGEX_MEM_BLOCK_CACHE_LOCK_FREE
|
||||
#define BOOST_REGEX_ATOMIC_POINTER std::atomic
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
#if BOOST_REGEX_MAX_CACHE_BLOCKS != 0
|
||||
#ifdef BOOST_REGEX_MEM_BLOCK_CACHE_LOCK_FREE /* lock free implementation */
|
||||
struct mem_block_cache
|
||||
{
|
||||
std::atomic<void*> cache[BOOST_REGEX_MAX_CACHE_BLOCKS];
|
||||
|
||||
~mem_block_cache()
|
||||
{
|
||||
for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) {
|
||||
if (cache[i].load()) ::operator delete(cache[i].load());
|
||||
}
|
||||
}
|
||||
void* get()
|
||||
{
|
||||
for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) {
|
||||
void* p = cache[i].load();
|
||||
if (p != NULL) {
|
||||
if (cache[i].compare_exchange_strong(p, NULL)) return p;
|
||||
}
|
||||
}
|
||||
return ::operator new(BOOST_REGEX_BLOCKSIZE);
|
||||
}
|
||||
void put(void* ptr)
|
||||
{
|
||||
for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) {
|
||||
void* p = cache[i].load();
|
||||
if (p == NULL) {
|
||||
if (cache[i].compare_exchange_strong(p, ptr)) return;
|
||||
}
|
||||
}
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
static mem_block_cache& instance()
|
||||
{
|
||||
static mem_block_cache block_cache = { { {nullptr} } };
|
||||
return block_cache;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#else /* lock-based implementation */
|
||||
|
||||
|
||||
struct mem_block_node
|
||||
{
|
||||
mem_block_node* next;
|
||||
};
|
||||
|
||||
struct mem_block_cache
|
||||
{
|
||||
// this member has to be statically initialsed:
|
||||
mem_block_node* next { nullptr };
|
||||
unsigned cached_blocks { 0 };
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
std::mutex mut;
|
||||
#endif
|
||||
|
||||
~mem_block_cache()
|
||||
{
|
||||
while(next)
|
||||
{
|
||||
mem_block_node* old = next;
|
||||
next = next->next;
|
||||
::operator delete(old);
|
||||
}
|
||||
}
|
||||
void* get()
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
std::lock_guard<std::mutex> g(mut);
|
||||
#endif
|
||||
if(next)
|
||||
{
|
||||
mem_block_node* result = next;
|
||||
next = next->next;
|
||||
--cached_blocks;
|
||||
return result;
|
||||
}
|
||||
return ::operator new(BOOST_REGEX_BLOCKSIZE);
|
||||
}
|
||||
void put(void* p)
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
std::lock_guard<std::mutex> g(mut);
|
||||
#endif
|
||||
if(cached_blocks >= BOOST_REGEX_MAX_CACHE_BLOCKS)
|
||||
{
|
||||
::operator delete(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_block_node* old = static_cast<mem_block_node*>(p);
|
||||
old->next = next;
|
||||
next = old;
|
||||
++cached_blocks;
|
||||
}
|
||||
}
|
||||
static mem_block_cache& instance()
|
||||
{
|
||||
static mem_block_cache block_cache;
|
||||
return block_cache;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_REGEX_MAX_CACHE_BLOCKS == 0
|
||||
|
||||
inline void* get_mem_block()
|
||||
{
|
||||
return ::operator new(BOOST_REGEX_BLOCKSIZE);
|
||||
}
|
||||
|
||||
inline void put_mem_block(void* p)
|
||||
{
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline void* get_mem_block()
|
||||
{
|
||||
return mem_block_cache::instance().get();
|
||||
}
|
||||
|
||||
inline void put_mem_block(void* p)
|
||||
{
|
||||
mem_block_cache::instance().put(p);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2004
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE object_cache.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Implements a generic object cache.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_OBJECT_CACHE_HPP
|
||||
#define BOOST_REGEX_OBJECT_CACHE_HPP
|
||||
|
||||
#include <boost/regex/config.hpp>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <class Key, class Object>
|
||||
class object_cache
|
||||
{
|
||||
public:
|
||||
typedef std::pair< ::std::shared_ptr<Object const>, Key const*> value_type;
|
||||
typedef std::list<value_type> list_type;
|
||||
typedef typename list_type::iterator list_iterator;
|
||||
typedef std::map<Key, list_iterator> map_type;
|
||||
typedef typename map_type::iterator map_iterator;
|
||||
typedef typename list_type::size_type size_type;
|
||||
static std::shared_ptr<Object const> get(const Key& k, size_type l_max_cache_size);
|
||||
|
||||
private:
|
||||
static std::shared_ptr<Object const> do_get(const Key& k, size_type l_max_cache_size);
|
||||
|
||||
struct data
|
||||
{
|
||||
list_type cont;
|
||||
map_type index;
|
||||
};
|
||||
|
||||
// Needed by compilers not implementing the resolution to DR45. For reference,
|
||||
// see http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45.
|
||||
friend struct data;
|
||||
};
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4702)
|
||||
#endif
|
||||
template <class Key, class Object>
|
||||
std::shared_ptr<Object const> object_cache<Key, Object>::get(const Key& k, size_type l_max_cache_size)
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
static std::mutex mut;
|
||||
std::lock_guard<std::mutex> l(mut);
|
||||
return do_get(k, l_max_cache_size);
|
||||
#else
|
||||
return do_get(k, l_max_cache_size);
|
||||
#endif
|
||||
}
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class Key, class Object>
|
||||
std::shared_ptr<Object const> object_cache<Key, Object>::do_get(const Key& k, size_type l_max_cache_size)
|
||||
{
|
||||
typedef typename object_cache<Key, Object>::data object_data;
|
||||
typedef typename map_type::size_type map_size_type;
|
||||
static object_data s_data;
|
||||
|
||||
//
|
||||
// see if the object is already in the cache:
|
||||
//
|
||||
map_iterator mpos = s_data.index.find(k);
|
||||
if(mpos != s_data.index.end())
|
||||
{
|
||||
//
|
||||
// Eureka!
|
||||
// We have a cached item, bump it up the list and return it:
|
||||
//
|
||||
if(--(s_data.cont.end()) != mpos->second)
|
||||
{
|
||||
// splice out the item we want to move:
|
||||
list_type temp;
|
||||
temp.splice(temp.end(), s_data.cont, mpos->second);
|
||||
// and now place it at the end of the list:
|
||||
s_data.cont.splice(s_data.cont.end(), temp, temp.begin());
|
||||
BOOST_REGEX_ASSERT(*(s_data.cont.back().second) == k);
|
||||
// update index with new position:
|
||||
mpos->second = --(s_data.cont.end());
|
||||
BOOST_REGEX_ASSERT(&(mpos->first) == mpos->second->second);
|
||||
BOOST_REGEX_ASSERT(&(mpos->first) == s_data.cont.back().second);
|
||||
}
|
||||
return s_data.cont.back().first;
|
||||
}
|
||||
//
|
||||
// if we get here then the item is not in the cache,
|
||||
// so create it:
|
||||
//
|
||||
std::shared_ptr<Object const> result(new Object(k));
|
||||
//
|
||||
// Add it to the list, and index it:
|
||||
//
|
||||
s_data.cont.push_back(value_type(result, static_cast<Key const*>(0)));
|
||||
s_data.index.insert(std::make_pair(k, --(s_data.cont.end())));
|
||||
s_data.cont.back().second = &(s_data.index.find(k)->first);
|
||||
map_size_type s = s_data.index.size();
|
||||
BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get());
|
||||
BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second);
|
||||
BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k);
|
||||
if(s > l_max_cache_size)
|
||||
{
|
||||
//
|
||||
// We have too many items in the list, so we need to start
|
||||
// popping them off the back of the list, but only if they're
|
||||
// being held uniquely by us:
|
||||
//
|
||||
list_iterator pos = s_data.cont.begin();
|
||||
list_iterator last = s_data.cont.end();
|
||||
while((pos != last) && (s > l_max_cache_size))
|
||||
{
|
||||
if(pos->first.use_count() == 1)
|
||||
{
|
||||
list_iterator condemmed(pos);
|
||||
++pos;
|
||||
// now remove the items from our containers,
|
||||
// then order has to be as follows:
|
||||
BOOST_REGEX_ASSERT(s_data.index.find(*(condemmed->second)) != s_data.index.end());
|
||||
s_data.index.erase(*(condemmed->second));
|
||||
s_data.cont.erase(condemmed);
|
||||
--s;
|
||||
}
|
||||
else
|
||||
++pos;
|
||||
}
|
||||
BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get());
|
||||
BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second);
|
||||
BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE pattern_except.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares pattern-matching exception classes.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_V5_PAT_EXCEPT_HPP
|
||||
#define BOOST_RE_V5_PAT_EXCEPT_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <boost/regex/v5/error_type.hpp>
|
||||
#include <boost/regex/v5/regex_traits_defaults.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4275)
|
||||
#if BOOST_REGEX_MSVC >= 1800
|
||||
#pragma warning(disable : 26812 4459)
|
||||
#endif
|
||||
#endif
|
||||
class regex_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit regex_error(const std::string& s, regex_constants::error_type err = regex_constants::error_unknown, std::ptrdiff_t pos = 0)
|
||||
: std::runtime_error(s)
|
||||
, m_error_code(err)
|
||||
, m_position(pos)
|
||||
{
|
||||
}
|
||||
explicit regex_error(regex_constants::error_type err)
|
||||
: std::runtime_error(::boost::BOOST_REGEX_DETAIL_NS::get_default_error_string(err))
|
||||
, m_error_code(err)
|
||||
, m_position(0)
|
||||
{
|
||||
}
|
||||
~regex_error() noexcept override {}
|
||||
regex_constants::error_type code()const
|
||||
{ return m_error_code; }
|
||||
std::ptrdiff_t position()const
|
||||
{ return m_position; }
|
||||
void raise()const
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
::boost::throw_exception(*this);
|
||||
#else
|
||||
throw* this;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
private:
|
||||
regex_constants::error_type m_error_code;
|
||||
std::ptrdiff_t m_position;
|
||||
};
|
||||
|
||||
typedef regex_error bad_pattern;
|
||||
typedef regex_error bad_expression;
|
||||
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
template <class E>
|
||||
inline void raise_runtime_error(const E& ex)
|
||||
{
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
::boost::throw_exception(ex);
|
||||
#else
|
||||
throw ex;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class traits>
|
||||
void raise_error(const traits& t, regex_constants::error_type code)
|
||||
{
|
||||
(void)t; // warning suppression
|
||||
regex_error e(t.error_string(code), code, 0);
|
||||
::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -1,576 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_MATCHER_HPP
|
||||
#define BOOST_REGEX_MATCHER_HPP
|
||||
|
||||
#include <boost/regex/v5/iterator_category.hpp>
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(push)
|
||||
#pragma warning(disable : 4251 4459)
|
||||
#if BOOST_REGEX_MSVC < 1700
|
||||
# pragma warning(disable : 4231)
|
||||
#endif
|
||||
# if BOOST_REGEX_MSVC < 1600
|
||||
# pragma warning(disable : 4660)
|
||||
# endif
|
||||
#if BOOST_REGEX_MSVC < 1910
|
||||
#pragma warning(disable:4800)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
//
|
||||
// error checking API:
|
||||
//
|
||||
inline void verify_options(boost::regex_constants::syntax_option_type, match_flag_type mf)
|
||||
{
|
||||
//
|
||||
// can't mix match_extra with POSIX matching rules:
|
||||
//
|
||||
if ((mf & match_extra) && (mf & match_posix))
|
||||
{
|
||||
std::logic_error msg("Usage Error: Can't mix regular expression captures with POSIX matching rules");
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
throw_exception(msg);
|
||||
#else
|
||||
throw msg;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//
|
||||
// function can_start:
|
||||
//
|
||||
template <class charT>
|
||||
inline bool can_start(charT c, const unsigned char* map, unsigned char mask)
|
||||
{
|
||||
return ((c < static_cast<charT>(0)) ? true : ((c >= static_cast<charT>(1 << CHAR_BIT)) ? true : map[c] & mask));
|
||||
}
|
||||
inline bool can_start(char c, const unsigned char* map, unsigned char mask)
|
||||
{
|
||||
return map[(unsigned char)c] & mask;
|
||||
}
|
||||
inline bool can_start(signed char c, const unsigned char* map, unsigned char mask)
|
||||
{
|
||||
return map[(unsigned char)c] & mask;
|
||||
}
|
||||
inline bool can_start(unsigned char c, const unsigned char* map, unsigned char mask)
|
||||
{
|
||||
return map[c] & mask;
|
||||
}
|
||||
inline bool can_start(unsigned short c, const unsigned char* map, unsigned char mask)
|
||||
{
|
||||
return ((c >= (1 << CHAR_BIT)) ? true : map[c] & mask);
|
||||
}
|
||||
#if defined(WCHAR_MIN) && (WCHAR_MIN == 0) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
inline bool can_start(wchar_t c, const unsigned char* map, unsigned char mask)
|
||||
{
|
||||
return ((c >= static_cast<wchar_t>(1u << CHAR_BIT)) ? true : map[c] & mask);
|
||||
}
|
||||
#endif
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
inline bool can_start(unsigned int c, const unsigned char* map, unsigned char mask)
|
||||
{
|
||||
return (((c >= static_cast<unsigned int>(1u << CHAR_BIT)) ? true : map[c] & mask));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class C, class T, class A>
|
||||
inline int string_compare(const std::basic_string<C,T,A>& s, const C* p)
|
||||
{
|
||||
if(0 == *p)
|
||||
{
|
||||
if(s.empty() || ((s.size() == 1) && (s[0] == 0)))
|
||||
return 0;
|
||||
}
|
||||
return s.compare(p);
|
||||
}
|
||||
template <class Seq, class C>
|
||||
inline int string_compare(const Seq& s, const C* p)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while((i < s.size()) && (p[i] == s[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
return (i == s.size()) ? -(int)p[i] : (int)s[i] - (int)p[i];
|
||||
}
|
||||
# define STR_COMP(s,p) string_compare(s,p)
|
||||
|
||||
template<class charT>
|
||||
inline const charT* re_skip_past_null(const charT* p)
|
||||
{
|
||||
while (*p != static_cast<charT>(0)) ++p;
|
||||
return ++p;
|
||||
}
|
||||
|
||||
template <class iterator, class charT, class traits_type, class char_classT>
|
||||
iterator re_is_set_member(iterator next,
|
||||
iterator last,
|
||||
const re_set_long<char_classT>* set_,
|
||||
const regex_data<charT, traits_type>& e, bool icase)
|
||||
{
|
||||
const charT* p = reinterpret_cast<const charT*>(set_+1);
|
||||
iterator ptr;
|
||||
unsigned int i;
|
||||
//bool icase = e.m_flags & regex_constants::icase;
|
||||
|
||||
if(next == last) return next;
|
||||
|
||||
typedef typename traits_type::string_type traits_string_type;
|
||||
const ::boost::regex_traits_wrapper<traits_type>& traits_inst = *(e.m_ptraits);
|
||||
|
||||
// dwa 9/13/00 suppress incorrect MSVC warning - it claims this is never
|
||||
// referenced
|
||||
(void)traits_inst;
|
||||
|
||||
// try and match a single character, could be a multi-character
|
||||
// collating element...
|
||||
for(i = 0; i < set_->csingles; ++i)
|
||||
{
|
||||
ptr = next;
|
||||
if(*p == static_cast<charT>(0))
|
||||
{
|
||||
// treat null string as special case:
|
||||
if(traits_inst.translate(*ptr, icase))
|
||||
{
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
return set_->isnot ? next : (ptr == next) ? ++next : ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(*p && (ptr != last))
|
||||
{
|
||||
if(traits_inst.translate(*ptr, icase) != *p)
|
||||
break;
|
||||
++p;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
if(*p == static_cast<charT>(0)) // if null we've matched
|
||||
return set_->isnot ? next : (ptr == next) ? ++next : ptr;
|
||||
|
||||
p = re_skip_past_null(p); // skip null
|
||||
}
|
||||
}
|
||||
|
||||
charT col = traits_inst.translate(*next, icase);
|
||||
|
||||
|
||||
if(set_->cranges || set_->cequivalents)
|
||||
{
|
||||
traits_string_type s1;
|
||||
//
|
||||
// try and match a range, NB only a single character can match
|
||||
if(set_->cranges)
|
||||
{
|
||||
if((e.m_flags & regex_constants::collate) == 0)
|
||||
s1.assign(1, col);
|
||||
else
|
||||
{
|
||||
charT a[2] = { col, charT(0), };
|
||||
s1 = traits_inst.transform(a, a + 1);
|
||||
}
|
||||
for(i = 0; i < set_->cranges; ++i)
|
||||
{
|
||||
if(STR_COMP(s1, p) >= 0)
|
||||
{
|
||||
do{ ++p; }while(*p);
|
||||
++p;
|
||||
if(STR_COMP(s1, p) <= 0)
|
||||
return set_->isnot ? next : ++next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip first string
|
||||
do{ ++p; }while(*p);
|
||||
++p;
|
||||
}
|
||||
// skip second string
|
||||
do{ ++p; }while(*p);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
//
|
||||
// try and match an equivalence class, NB only a single character can match
|
||||
if(set_->cequivalents)
|
||||
{
|
||||
charT a[2] = { col, charT(0), };
|
||||
s1 = traits_inst.transform_primary(a, a +1);
|
||||
for(i = 0; i < set_->cequivalents; ++i)
|
||||
{
|
||||
if(STR_COMP(s1, p) == 0)
|
||||
return set_->isnot ? next : ++next;
|
||||
// skip string
|
||||
do{ ++p; }while(*p);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(traits_inst.isctype(col, set_->cclasses) == true)
|
||||
return set_->isnot ? next : ++next;
|
||||
if((set_->cnclasses != 0) && (traits_inst.isctype(col, set_->cnclasses) == false))
|
||||
return set_->isnot ? next : ++next;
|
||||
return set_->isnot ? ++next : next;
|
||||
}
|
||||
|
||||
template <class BidiIterator>
|
||||
class repeater_count
|
||||
{
|
||||
repeater_count** stack;
|
||||
repeater_count* next;
|
||||
int state_id;
|
||||
std::size_t count; // the number of iterations so far
|
||||
BidiIterator start_pos; // where the last repeat started
|
||||
|
||||
repeater_count* unwind_until(int n, repeater_count* p, int current_recursion_id)
|
||||
{
|
||||
while(p && (p->state_id != n))
|
||||
{
|
||||
if(-2 - current_recursion_id == p->state_id)
|
||||
return 0;
|
||||
p = p->next;
|
||||
if(p && (p->state_id < 0))
|
||||
{
|
||||
p = unwind_until(p->state_id, p, current_recursion_id);
|
||||
if(!p)
|
||||
return p;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
public:
|
||||
repeater_count(repeater_count** s) : stack(s), next(0), state_id(-1), count(0), start_pos() {}
|
||||
|
||||
repeater_count(int i, repeater_count** s, BidiIterator start, int current_recursion_id)
|
||||
: start_pos(start)
|
||||
{
|
||||
state_id = i;
|
||||
stack = s;
|
||||
next = *stack;
|
||||
*stack = this;
|
||||
if((state_id > next->state_id) && (next->state_id >= 0))
|
||||
count = 0;
|
||||
else
|
||||
{
|
||||
repeater_count* p = next;
|
||||
p = unwind_until(state_id, p, current_recursion_id);
|
||||
if(p)
|
||||
{
|
||||
count = p->count;
|
||||
start_pos = p->start_pos;
|
||||
}
|
||||
else
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
~repeater_count()
|
||||
{
|
||||
if(next)
|
||||
*stack = next;
|
||||
}
|
||||
std::size_t get_count() { return count; }
|
||||
int get_id() { return state_id; }
|
||||
std::size_t operator++() { return ++count; }
|
||||
bool check_null_repeat(const BidiIterator& pos, std::size_t max)
|
||||
{
|
||||
// this is called when we are about to start a new repeat,
|
||||
// if the last one was NULL move our count to max,
|
||||
// otherwise save the current position.
|
||||
bool result = (count == 0) ? false : (pos == start_pos);
|
||||
if(result)
|
||||
count = max;
|
||||
else
|
||||
start_pos = pos;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct saved_state;
|
||||
|
||||
enum saved_state_type
|
||||
{
|
||||
saved_type_end = 0,
|
||||
saved_type_paren = 1,
|
||||
saved_type_recurse = 2,
|
||||
saved_type_assertion = 3,
|
||||
saved_state_alt = 4,
|
||||
saved_state_repeater_count = 5,
|
||||
saved_state_extra_block = 6,
|
||||
saved_state_greedy_single_repeat = 7,
|
||||
saved_state_rep_slow_dot = 8,
|
||||
saved_state_rep_fast_dot = 9,
|
||||
saved_state_rep_char = 10,
|
||||
saved_state_rep_short_set = 11,
|
||||
saved_state_rep_long_set = 12,
|
||||
saved_state_non_greedy_long_repeat = 13,
|
||||
saved_state_count = 14
|
||||
};
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(push)
|
||||
#if BOOST_REGEX_MSVC >= 1800
|
||||
#pragma warning(disable:26495)
|
||||
#endif
|
||||
#endif
|
||||
template <class Results>
|
||||
struct recursion_info
|
||||
{
|
||||
typedef typename Results::value_type value_type;
|
||||
typedef typename value_type::iterator iterator;
|
||||
int idx;
|
||||
const re_syntax_base* preturn_address;
|
||||
Results results;
|
||||
repeater_count<iterator>* repeater_stack;
|
||||
iterator location_of_start;
|
||||
};
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
class perl_matcher
|
||||
{
|
||||
public:
|
||||
typedef typename traits::char_type char_type;
|
||||
typedef perl_matcher<BidiIterator, Allocator, traits> self_type;
|
||||
typedef bool (self_type::*matcher_proc_type)();
|
||||
typedef std::size_t traits_size_type;
|
||||
typedef typename is_byte<char_type>::width_type width_type;
|
||||
typedef typename std::iterator_traits<BidiIterator>::difference_type difference_type;
|
||||
typedef match_results<BidiIterator, Allocator> results_type;
|
||||
|
||||
perl_matcher(BidiIterator first, BidiIterator end,
|
||||
match_results<BidiIterator, Allocator>& what,
|
||||
const basic_regex<char_type, traits>& e,
|
||||
match_flag_type f,
|
||||
BidiIterator l_base)
|
||||
: m_result(what), base(first), last(end),
|
||||
position(first), backstop(l_base), re(e), traits_inst(e.get_traits()),
|
||||
m_independent(false), next_count(&rep_obj), rep_obj(&next_count)
|
||||
, m_recursions(0)
|
||||
{
|
||||
construct_init(e, f);
|
||||
}
|
||||
|
||||
bool match();
|
||||
bool find();
|
||||
|
||||
void setf(match_flag_type f)
|
||||
{ m_match_flags |= f; }
|
||||
void unsetf(match_flag_type f)
|
||||
{ m_match_flags &= ~f; }
|
||||
|
||||
private:
|
||||
void construct_init(const basic_regex<char_type, traits>& e, match_flag_type f);
|
||||
|
||||
bool find_imp();
|
||||
bool match_imp();
|
||||
void estimate_max_state_count(std::random_access_iterator_tag*);
|
||||
void estimate_max_state_count(void*);
|
||||
bool match_prefix();
|
||||
bool match_all_states();
|
||||
|
||||
// match procs, stored in s_match_vtable:
|
||||
bool match_startmark();
|
||||
bool match_endmark();
|
||||
bool match_literal();
|
||||
bool match_start_line();
|
||||
bool match_end_line();
|
||||
bool match_wild();
|
||||
bool match_match();
|
||||
bool match_word_boundary();
|
||||
bool match_within_word();
|
||||
bool match_word_start();
|
||||
bool match_word_end();
|
||||
bool match_buffer_start();
|
||||
bool match_buffer_end();
|
||||
bool match_backref();
|
||||
bool match_long_set();
|
||||
bool match_set();
|
||||
bool match_jump();
|
||||
bool match_alt();
|
||||
bool match_rep();
|
||||
bool match_combining();
|
||||
bool match_soft_buffer_end();
|
||||
bool match_restart_continue();
|
||||
bool match_long_set_repeat();
|
||||
bool match_set_repeat();
|
||||
bool match_char_repeat();
|
||||
bool match_dot_repeat_fast();
|
||||
bool match_dot_repeat_slow();
|
||||
bool match_dot_repeat_dispatch()
|
||||
{
|
||||
return ::boost::is_random_access_iterator<BidiIterator>::value ? match_dot_repeat_fast() : match_dot_repeat_slow();
|
||||
}
|
||||
bool match_backstep();
|
||||
bool match_assert_backref();
|
||||
bool match_toggle_case();
|
||||
bool match_recursion();
|
||||
bool match_fail();
|
||||
bool match_accept();
|
||||
bool match_commit();
|
||||
bool match_then();
|
||||
bool skip_until_paren(int index, bool match = true);
|
||||
|
||||
// find procs stored in s_find_vtable:
|
||||
bool find_restart_any();
|
||||
bool find_restart_word();
|
||||
bool find_restart_line();
|
||||
bool find_restart_buf();
|
||||
bool find_restart_lit();
|
||||
|
||||
private:
|
||||
// final result structure to be filled in:
|
||||
match_results<BidiIterator, Allocator>& m_result;
|
||||
// temporary result for POSIX matches:
|
||||
std::unique_ptr<match_results<BidiIterator, Allocator> > m_temp_match;
|
||||
// pointer to actual result structure to fill in:
|
||||
match_results<BidiIterator, Allocator>* m_presult;
|
||||
// start of sequence being searched:
|
||||
BidiIterator base;
|
||||
// end of sequence being searched:
|
||||
BidiIterator last;
|
||||
// current character being examined:
|
||||
BidiIterator position;
|
||||
// where to restart next search after failed match attempt:
|
||||
BidiIterator restart;
|
||||
// where the current search started from, acts as base for $` during grep:
|
||||
BidiIterator search_base;
|
||||
// how far we can go back when matching lookbehind:
|
||||
BidiIterator backstop;
|
||||
// the expression being examined:
|
||||
const basic_regex<char_type, traits>& re;
|
||||
// the expression's traits class:
|
||||
const ::boost::regex_traits_wrapper<traits>& traits_inst;
|
||||
// the next state in the machine being matched:
|
||||
const re_syntax_base* pstate;
|
||||
// matching flags in use:
|
||||
match_flag_type m_match_flags;
|
||||
// how many states we have examined so far:
|
||||
std::ptrdiff_t state_count;
|
||||
// max number of states to examine before giving up:
|
||||
std::ptrdiff_t max_state_count;
|
||||
// whether we should ignore case or not:
|
||||
bool icase;
|
||||
// set to true when (position == last), indicates that we may have a partial match:
|
||||
bool m_has_partial_match;
|
||||
// set to true whenever we get a match:
|
||||
bool m_has_found_match;
|
||||
// set to true whenever we're inside an independent sub-expression:
|
||||
bool m_independent;
|
||||
// the current repeat being examined:
|
||||
repeater_count<BidiIterator>* next_count;
|
||||
// the first repeat being examined (top of linked list):
|
||||
repeater_count<BidiIterator> rep_obj;
|
||||
// the mask to pass when matching word boundaries:
|
||||
typename traits::char_class_type m_word_mask;
|
||||
// the bitmask to use when determining whether a match_any matches a newline or not:
|
||||
unsigned char match_any_mask;
|
||||
// recursion information:
|
||||
std::vector<recursion_info<results_type> > recursion_stack;
|
||||
//
|
||||
// additional members for non-recursive version:
|
||||
//
|
||||
typedef bool (self_type::*unwind_proc_type)(bool);
|
||||
|
||||
void extend_stack();
|
||||
bool unwind(bool);
|
||||
bool unwind_end(bool);
|
||||
bool unwind_paren(bool);
|
||||
bool unwind_recursion_stopper(bool);
|
||||
bool unwind_assertion(bool);
|
||||
bool unwind_alt(bool);
|
||||
bool unwind_repeater_counter(bool);
|
||||
bool unwind_extra_block(bool);
|
||||
bool unwind_greedy_single_repeat(bool);
|
||||
bool unwind_slow_dot_repeat(bool);
|
||||
bool unwind_fast_dot_repeat(bool);
|
||||
bool unwind_char_repeat(bool);
|
||||
bool unwind_short_set_repeat(bool);
|
||||
bool unwind_long_set_repeat(bool);
|
||||
bool unwind_non_greedy_repeat(bool);
|
||||
bool unwind_recursion(bool);
|
||||
bool unwind_recursion_pop(bool);
|
||||
bool unwind_commit(bool);
|
||||
bool unwind_then(bool);
|
||||
bool unwind_case(bool);
|
||||
void destroy_single_repeat();
|
||||
void push_matched_paren(int index, const sub_match<BidiIterator>& sub);
|
||||
void push_recursion_stopper();
|
||||
void push_assertion(const re_syntax_base* ps, bool positive);
|
||||
void push_alt(const re_syntax_base* ps);
|
||||
void push_repeater_count(int i, repeater_count<BidiIterator>** s);
|
||||
void push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int state_id);
|
||||
void push_non_greedy_repeat(const re_syntax_base* ps);
|
||||
void push_recursion(int idx, const re_syntax_base* p, results_type* presults, results_type* presults2);
|
||||
void push_recursion_pop();
|
||||
void push_case_change(bool);
|
||||
|
||||
// pointer to base of stack:
|
||||
saved_state* m_stack_base;
|
||||
// pointer to current stack position:
|
||||
saved_state* m_backup_state;
|
||||
// how many memory blocks have we used up?:
|
||||
unsigned used_block_count;
|
||||
// determines what value to return when unwinding from recursion,
|
||||
// allows for mixed recursive/non-recursive algorithm:
|
||||
bool m_recursive_result;
|
||||
// We have unwound to a lookahead/lookbehind, used by COMMIT/PRUNE/SKIP:
|
||||
bool m_unwound_lookahead;
|
||||
// We have unwound to an alternative, used by THEN:
|
||||
bool m_unwound_alt;
|
||||
// We are unwinding a commit - used by independent subs to determine whether to stop there or carry on unwinding:
|
||||
//bool m_unwind_commit;
|
||||
// Recursion limit:
|
||||
unsigned m_recursions;
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(push)
|
||||
#if BOOST_REGEX_MSVC >= 1800
|
||||
#pragma warning(disable:26495)
|
||||
#endif
|
||||
#endif
|
||||
// these operations aren't allowed, so are declared private,
|
||||
// bodies are provided to keep explicit-instantiation requests happy:
|
||||
perl_matcher& operator=(const perl_matcher&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
perl_matcher(const perl_matcher& that)
|
||||
: m_result(that.m_result), re(that.re), traits_inst(that.traits_inst), rep_obj(0) {}
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace BOOST_REGEX_DETAIL_NS
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
//
|
||||
// include the implementation of perl_matcher:
|
||||
//
|
||||
#include <boost/regex/v5/perl_matcher_non_recursive.hpp>
|
||||
// this one has to be last:
|
||||
#include <boost/regex/v5/perl_matcher_common.hpp>
|
||||
|
||||
#endif
|
||||
@@ -1,921 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE perl_matcher_common.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Definitions of perl_matcher member functions that are
|
||||
* common to both the recursive and non-recursive versions.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_PERL_MATCHER_COMMON_HPP
|
||||
#define BOOST_REGEX_V5_PERL_MATCHER_COMMON_HPP
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(push)
|
||||
#pragma warning(disable:4459)
|
||||
#if BOOST_REGEX_MSVC < 1910
|
||||
#pragma warning(disable:4800)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(push)
|
||||
#pragma warning(disable:26812)
|
||||
#endif
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
void perl_matcher<BidiIterator, Allocator, traits>::construct_init(const basic_regex<char_type, traits>& e, match_flag_type f)
|
||||
{
|
||||
typedef typename std::iterator_traits<BidiIterator>::iterator_category category;
|
||||
typedef typename basic_regex<char_type, traits>::flag_type expression_flag_type;
|
||||
|
||||
if(e.empty())
|
||||
{
|
||||
// precondition failure: e is not a valid regex.
|
||||
std::invalid_argument ex("Invalid regular expression object");
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
boost::throw_exception(ex);
|
||||
#else
|
||||
throw e;
|
||||
#endif
|
||||
}
|
||||
pstate = 0;
|
||||
m_match_flags = f;
|
||||
estimate_max_state_count(static_cast<category*>(0));
|
||||
expression_flag_type re_f = re.flags();
|
||||
icase = re_f & regex_constants::icase;
|
||||
if(!(m_match_flags & (match_perl|match_posix)))
|
||||
{
|
||||
if((re_f & (regbase::main_option_type|regbase::no_perl_ex)) == 0)
|
||||
m_match_flags |= match_perl;
|
||||
else if((re_f & (regbase::main_option_type|regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex))
|
||||
m_match_flags |= match_perl;
|
||||
else if((re_f & (regbase::main_option_type|regbase::literal)) == (regbase::literal))
|
||||
m_match_flags |= match_perl;
|
||||
else
|
||||
m_match_flags |= match_posix;
|
||||
}
|
||||
if(m_match_flags & match_posix)
|
||||
{
|
||||
m_temp_match.reset(new match_results<BidiIterator, Allocator>());
|
||||
m_presult = m_temp_match.get();
|
||||
}
|
||||
else
|
||||
m_presult = &m_result;
|
||||
m_stack_base = 0;
|
||||
m_backup_state = 0;
|
||||
// find the value to use for matching word boundaries:
|
||||
m_word_mask = re.get_data().m_word_mask;
|
||||
// find bitmask to use for matching '.':
|
||||
match_any_mask = static_cast<unsigned char>((f & match_not_dot_newline) ? BOOST_REGEX_DETAIL_NS::test_not_newline : BOOST_REGEX_DETAIL_NS::test_newline);
|
||||
// Disable match_any if requested in the state machine:
|
||||
if(e.get_data().m_disable_match_any)
|
||||
m_match_flags &= regex_constants::match_not_any;
|
||||
}
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(std::random_access_iterator_tag*)
|
||||
{
|
||||
//
|
||||
// How many states should we allow our machine to visit before giving up?
|
||||
// This is a heuristic: it takes the greater of O(N^2) and O(NS^2)
|
||||
// where N is the length of the string, and S is the number of states
|
||||
// in the machine. It's tempting to up this to O(N^2S) or even O(N^2S^2)
|
||||
// but these take unreasonably amounts of time to bale out in pathological
|
||||
// cases.
|
||||
//
|
||||
// Calculate NS^2 first:
|
||||
//
|
||||
static const std::ptrdiff_t k = 100000;
|
||||
std::ptrdiff_t dist = std::distance(base, last);
|
||||
if(dist == 0)
|
||||
dist = 1;
|
||||
std::ptrdiff_t states = re.size();
|
||||
if(states == 0)
|
||||
states = 1;
|
||||
if ((std::numeric_limits<std::ptrdiff_t>::max)() / states < states)
|
||||
{
|
||||
max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
|
||||
return;
|
||||
}
|
||||
states *= states;
|
||||
if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
|
||||
{
|
||||
max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
|
||||
return;
|
||||
}
|
||||
states *= dist;
|
||||
if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
|
||||
{
|
||||
max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
|
||||
return;
|
||||
}
|
||||
states += k;
|
||||
|
||||
max_state_count = states;
|
||||
|
||||
//
|
||||
// Now calculate N^2:
|
||||
//
|
||||
states = dist;
|
||||
if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
|
||||
{
|
||||
max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
|
||||
return;
|
||||
}
|
||||
states *= dist;
|
||||
if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
|
||||
{
|
||||
max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
|
||||
return;
|
||||
}
|
||||
states += k;
|
||||
//
|
||||
// N^2 can be a very large number indeed, to prevent things getting out
|
||||
// of control, cap the max states:
|
||||
//
|
||||
if(states > BOOST_REGEX_MAX_STATE_COUNT)
|
||||
states = BOOST_REGEX_MAX_STATE_COUNT;
|
||||
//
|
||||
// If (the possibly capped) N^2 is larger than our first estimate,
|
||||
// use this instead:
|
||||
//
|
||||
if(states > max_state_count)
|
||||
max_state_count = states;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
inline void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(void*)
|
||||
{
|
||||
// we don't know how long the sequence is:
|
||||
max_state_count = BOOST_REGEX_MAX_STATE_COUNT;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
inline bool perl_matcher<BidiIterator, Allocator, traits>::match()
|
||||
{
|
||||
return match_imp();
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_imp()
|
||||
{
|
||||
// initialise our stack if we are non-recursive:
|
||||
save_state_init init(&m_stack_base, &m_backup_state);
|
||||
used_block_count = BOOST_REGEX_MAX_BLOCKS;
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
try{
|
||||
#endif
|
||||
|
||||
// reset our state machine:
|
||||
position = base;
|
||||
search_base = base;
|
||||
state_count = 0;
|
||||
m_match_flags |= regex_constants::match_all;
|
||||
m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), search_base, last);
|
||||
m_presult->set_base(base);
|
||||
m_presult->set_named_subs(this->re.get_named_subs());
|
||||
if(m_match_flags & match_posix)
|
||||
m_result = *m_presult;
|
||||
verify_options(re.flags(), m_match_flags);
|
||||
if(0 == match_prefix())
|
||||
return false;
|
||||
return (m_result[0].second == last) && (m_result[0].first == base);
|
||||
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// unwind all pushed states, apart from anything else this
|
||||
// ensures that all the states are correctly destructed
|
||||
// not just the memory freed.
|
||||
while(unwind(true)){}
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
inline bool perl_matcher<BidiIterator, Allocator, traits>::find()
|
||||
{
|
||||
return find_imp();
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::find_imp()
|
||||
{
|
||||
static matcher_proc_type const s_find_vtable[7] =
|
||||
{
|
||||
&perl_matcher<BidiIterator, Allocator, traits>::find_restart_any,
|
||||
&perl_matcher<BidiIterator, Allocator, traits>::find_restart_word,
|
||||
&perl_matcher<BidiIterator, Allocator, traits>::find_restart_line,
|
||||
&perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf,
|
||||
&perl_matcher<BidiIterator, Allocator, traits>::match_prefix,
|
||||
&perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
|
||||
&perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
|
||||
};
|
||||
|
||||
// initialise our stack if we are non-recursive:
|
||||
save_state_init init(&m_stack_base, &m_backup_state);
|
||||
used_block_count = BOOST_REGEX_MAX_BLOCKS;
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
try{
|
||||
#endif
|
||||
|
||||
state_count = 0;
|
||||
if((m_match_flags & regex_constants::match_init) == 0)
|
||||
{
|
||||
// reset our state machine:
|
||||
search_base = position = base;
|
||||
pstate = re.get_first_state();
|
||||
m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), base, last);
|
||||
m_presult->set_base(base);
|
||||
m_presult->set_named_subs(this->re.get_named_subs());
|
||||
m_match_flags |= regex_constants::match_init;
|
||||
}
|
||||
else
|
||||
{
|
||||
// start again:
|
||||
search_base = position = m_result[0].second;
|
||||
// If last match was null and match_not_null was not set then increment
|
||||
// our start position, otherwise we go into an infinite loop:
|
||||
if(((m_match_flags & match_not_null) == 0) && (m_result.length() == 0))
|
||||
{
|
||||
if(position == last)
|
||||
return false;
|
||||
else
|
||||
++position;
|
||||
}
|
||||
// reset $` start:
|
||||
m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), search_base, last);
|
||||
//if((base != search_base) && (base == backstop))
|
||||
// m_match_flags |= match_prev_avail;
|
||||
}
|
||||
if(m_match_flags & match_posix)
|
||||
{
|
||||
m_result.set_size(static_cast<typename results_type::size_type>(1u + re.mark_count()), base, last);
|
||||
m_result.set_base(base);
|
||||
}
|
||||
|
||||
verify_options(re.flags(), m_match_flags);
|
||||
// find out what kind of expression we have:
|
||||
unsigned type = (m_match_flags & match_continuous) ?
|
||||
static_cast<unsigned int>(regbase::restart_continue)
|
||||
: static_cast<unsigned int>(re.get_restart_type());
|
||||
|
||||
// call the appropriate search routine:
|
||||
matcher_proc_type proc = s_find_vtable[type];
|
||||
return (this->*proc)();
|
||||
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// unwind all pushed states, apart from anything else this
|
||||
// ensures that all the states are correctly destructed
|
||||
// not just the memory freed.
|
||||
while(unwind(true)){}
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_prefix()
|
||||
{
|
||||
m_has_partial_match = false;
|
||||
m_has_found_match = false;
|
||||
pstate = re.get_first_state();
|
||||
m_presult->set_first(position);
|
||||
restart = position;
|
||||
match_all_states();
|
||||
if(!m_has_found_match && m_has_partial_match && (m_match_flags & match_partial))
|
||||
{
|
||||
m_has_found_match = true;
|
||||
m_presult->set_second(last, 0, false);
|
||||
position = last;
|
||||
if((m_match_flags & match_posix) == match_posix)
|
||||
{
|
||||
m_result.maybe_assign(*m_presult);
|
||||
}
|
||||
}
|
||||
#ifdef BOOST_REGEX_MATCH_EXTRA
|
||||
if(m_has_found_match && (match_extra & m_match_flags))
|
||||
{
|
||||
//
|
||||
// we have a match, reverse the capture information:
|
||||
//
|
||||
for(unsigned i = 0; i < m_presult->size(); ++i)
|
||||
{
|
||||
typename sub_match<BidiIterator>::capture_sequence_type & seq = ((*m_presult)[i]).get_captures();
|
||||
std::reverse(seq.begin(), seq.end());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(!m_has_found_match)
|
||||
position = restart; // reset search postion
|
||||
return m_has_found_match;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_literal()
|
||||
{
|
||||
unsigned int len = static_cast<const re_literal*>(pstate)->length;
|
||||
const char_type* what = reinterpret_cast<const char_type*>(static_cast<const re_literal*>(pstate) + 1);
|
||||
//
|
||||
// compare string with what we stored in
|
||||
// our records:
|
||||
for(unsigned int i = 0; i < len; ++i, ++position)
|
||||
{
|
||||
if((position == last) || (traits_inst.translate(*position, icase) != what[i]))
|
||||
return false;
|
||||
}
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_start_line()
|
||||
{
|
||||
if(position == backstop)
|
||||
{
|
||||
if((m_match_flags & match_prev_avail) == 0)
|
||||
{
|
||||
if((m_match_flags & match_not_bol) == 0)
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(m_match_flags & match_single_line)
|
||||
return false;
|
||||
|
||||
// check the previous value character:
|
||||
BidiIterator t(position);
|
||||
--t;
|
||||
if(position != last)
|
||||
{
|
||||
if(is_separator(*t) && !((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n'))) )
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(is_separator(*t))
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_end_line()
|
||||
{
|
||||
if(position != last)
|
||||
{
|
||||
if(m_match_flags & match_single_line)
|
||||
return false;
|
||||
// we're not yet at the end so *first is always valid:
|
||||
if(is_separator(*position))
|
||||
{
|
||||
if((position != backstop) || (m_match_flags & match_prev_avail))
|
||||
{
|
||||
// check that we're not in the middle of \r\n sequence
|
||||
BidiIterator t(position);
|
||||
--t;
|
||||
if((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if((m_match_flags & match_not_eol) == 0)
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_wild()
|
||||
{
|
||||
if(position == last)
|
||||
return false;
|
||||
if(is_separator(*position) && ((match_any_mask & static_cast<const re_dot*>(pstate)->mask) == 0))
|
||||
return false;
|
||||
if((*position == char_type(0)) && (m_match_flags & match_not_dot_null))
|
||||
return false;
|
||||
pstate = pstate->next.p;
|
||||
++position;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_word_boundary()
|
||||
{
|
||||
bool b; // indcates whether next character is a word character
|
||||
if(position != last)
|
||||
{
|
||||
// prev and this character must be opposites:
|
||||
b = traits_inst.isctype(*position, m_word_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_match_flags & match_not_eow)
|
||||
return false;
|
||||
b = false;
|
||||
}
|
||||
if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
|
||||
{
|
||||
if(m_match_flags & match_not_bow)
|
||||
return false;
|
||||
else
|
||||
b ^= false;
|
||||
}
|
||||
else
|
||||
{
|
||||
--position;
|
||||
b ^= traits_inst.isctype(*position, m_word_mask);
|
||||
++position;
|
||||
}
|
||||
if(b)
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
return false; // no match if we get to here...
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_within_word()
|
||||
{
|
||||
bool b = !match_word_boundary();
|
||||
if(b)
|
||||
pstate = pstate->next.p;
|
||||
return b;
|
||||
/*
|
||||
if(position == last)
|
||||
return false;
|
||||
// both prev and this character must be m_word_mask:
|
||||
bool prev = traits_inst.isctype(*position, m_word_mask);
|
||||
{
|
||||
bool b;
|
||||
if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
--position;
|
||||
b = traits_inst.isctype(*position, m_word_mask);
|
||||
++position;
|
||||
}
|
||||
if(b == prev)
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_word_start()
|
||||
{
|
||||
if(position == last)
|
||||
return false; // can't be starting a word if we're already at the end of input
|
||||
if(!traits_inst.isctype(*position, m_word_mask))
|
||||
return false; // next character isn't a word character
|
||||
if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
|
||||
{
|
||||
if(m_match_flags & match_not_bow)
|
||||
return false; // no previous input
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise inside buffer:
|
||||
BidiIterator t(position);
|
||||
--t;
|
||||
if(traits_inst.isctype(*t, m_word_mask))
|
||||
return false; // previous character not non-word
|
||||
}
|
||||
// OK we have a match:
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_word_end()
|
||||
{
|
||||
if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
|
||||
return false; // start of buffer can't be end of word
|
||||
BidiIterator t(position);
|
||||
--t;
|
||||
if(traits_inst.isctype(*t, m_word_mask) == false)
|
||||
return false; // previous character wasn't a word character
|
||||
|
||||
if(position == last)
|
||||
{
|
||||
if(m_match_flags & match_not_eow)
|
||||
return false; // end of buffer but not end of word
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise inside buffer:
|
||||
if(traits_inst.isctype(*position, m_word_mask))
|
||||
return false; // next character is a word character
|
||||
}
|
||||
pstate = pstate->next.p;
|
||||
return true; // if we fall through to here then we've succeeded
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_start()
|
||||
{
|
||||
if((position != backstop) || (m_match_flags & match_not_bob))
|
||||
return false;
|
||||
// OK match:
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_end()
|
||||
{
|
||||
if((position != last) || (m_match_flags & match_not_eob))
|
||||
return false;
|
||||
// OK match:
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_backref()
|
||||
{
|
||||
//
|
||||
// Compare with what we previously matched.
|
||||
// Note that this succeeds if the backref did not partisipate
|
||||
// in the match, this is in line with ECMAScript, but not Perl
|
||||
// or PCRE.
|
||||
//
|
||||
int index = static_cast<const re_brace*>(pstate)->index;
|
||||
if(index >= hash_value_mask)
|
||||
{
|
||||
named_subexpressions::range_type r = re.get_data().equal_range(index);
|
||||
BOOST_REGEX_ASSERT(r.first != r.second);
|
||||
do
|
||||
{
|
||||
index = r.first->index;
|
||||
++r.first;
|
||||
}while((r.first != r.second) && ((*m_presult)[index].matched != true));
|
||||
}
|
||||
|
||||
if((m_match_flags & match_perl) && !(*m_presult)[index].matched)
|
||||
return false;
|
||||
|
||||
BidiIterator i = (*m_presult)[index].first;
|
||||
BidiIterator j = (*m_presult)[index].second;
|
||||
while(i != j)
|
||||
{
|
||||
if((position == last) || (traits_inst.translate(*position, icase) != traits_inst.translate(*i, icase)))
|
||||
return false;
|
||||
++i;
|
||||
++position;
|
||||
}
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_long_set()
|
||||
{
|
||||
typedef typename traits::char_class_type char_class_type;
|
||||
// let the traits class do the work:
|
||||
if(position == last)
|
||||
return false;
|
||||
BidiIterator t = re_is_set_member(position, last, static_cast<const re_set_long<char_class_type>*>(pstate), re.get_data(), icase);
|
||||
if(t != position)
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
position = t;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_set()
|
||||
{
|
||||
if(position == last)
|
||||
return false;
|
||||
if(static_cast<const re_set*>(pstate)->_map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
++position;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_jump()
|
||||
{
|
||||
pstate = static_cast<const re_jump*>(pstate)->alt.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_combining()
|
||||
{
|
||||
if(position == last)
|
||||
return false;
|
||||
if(is_combining(traits_inst.translate(*position, icase)))
|
||||
return false;
|
||||
++position;
|
||||
while((position != last) && is_combining(traits_inst.translate(*position, icase)))
|
||||
++position;
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_soft_buffer_end()
|
||||
{
|
||||
if(m_match_flags & match_not_eob)
|
||||
return false;
|
||||
BidiIterator p(position);
|
||||
while((p != last) && is_separator(traits_inst.translate(*p, icase)))++p;
|
||||
if(p != last)
|
||||
return false;
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_restart_continue()
|
||||
{
|
||||
if(position == search_base)
|
||||
{
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_backstep()
|
||||
{
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
if( ::boost::is_random_access_iterator<BidiIterator>::value)
|
||||
{
|
||||
std::ptrdiff_t maxlen = std::distance(backstop, position);
|
||||
if(maxlen < static_cast<const re_brace*>(pstate)->index)
|
||||
return false;
|
||||
std::advance(position, -static_cast<const re_brace*>(pstate)->index);
|
||||
}
|
||||
else
|
||||
{
|
||||
int c = static_cast<const re_brace*>(pstate)->index;
|
||||
while(c--)
|
||||
{
|
||||
if(position == backstop)
|
||||
return false;
|
||||
--position;
|
||||
}
|
||||
}
|
||||
pstate = pstate->next.p;
|
||||
return true;
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
inline bool perl_matcher<BidiIterator, Allocator, traits>::match_assert_backref()
|
||||
{
|
||||
// return true if marked sub-expression N has been matched:
|
||||
int index = static_cast<const re_brace*>(pstate)->index;
|
||||
bool result = false;
|
||||
if(index == 9999)
|
||||
{
|
||||
// Magic value for a (DEFINE) block:
|
||||
return false;
|
||||
}
|
||||
else if(index > 0)
|
||||
{
|
||||
// Have we matched subexpression "index"?
|
||||
// Check if index is a hash value:
|
||||
if(index >= hash_value_mask)
|
||||
{
|
||||
named_subexpressions::range_type r = re.get_data().equal_range(index);
|
||||
while(r.first != r.second)
|
||||
{
|
||||
if((*m_presult)[r.first->index].matched)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
++r.first;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (*m_presult)[index].matched;
|
||||
}
|
||||
pstate = pstate->next.p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Have we recursed into subexpression "index"?
|
||||
// If index == 0 then check for any recursion at all, otherwise for recursion to -index-1.
|
||||
int idx = -(index+1);
|
||||
if(idx >= hash_value_mask)
|
||||
{
|
||||
named_subexpressions::range_type r = re.get_data().equal_range(idx);
|
||||
int stack_index = recursion_stack.empty() ? -1 : recursion_stack.back().idx;
|
||||
while(r.first != r.second)
|
||||
{
|
||||
result |= (stack_index == r.first->index);
|
||||
if(result)break;
|
||||
++r.first;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = !recursion_stack.empty() && ((recursion_stack.back().idx == idx) || (index == 0));
|
||||
}
|
||||
pstate = pstate->next.p;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_fail()
|
||||
{
|
||||
// Just force a backtrack:
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::match_accept()
|
||||
{
|
||||
if(!recursion_stack.empty())
|
||||
{
|
||||
return skip_until_paren(recursion_stack.back().idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
return skip_until_paren(INT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_any()
|
||||
{
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
const unsigned char* _map = re.get_map();
|
||||
while(true)
|
||||
{
|
||||
// skip everything we can't match:
|
||||
while((position != last) && !can_start(*position, _map, (unsigned char)mask_any) )
|
||||
++position;
|
||||
if(position == last)
|
||||
{
|
||||
// run out of characters, try a null match if possible:
|
||||
if(re.can_be_null())
|
||||
return match_prefix();
|
||||
break;
|
||||
}
|
||||
// now try and obtain a match:
|
||||
if(match_prefix())
|
||||
return true;
|
||||
if(position == last)
|
||||
return false;
|
||||
++position;
|
||||
}
|
||||
return false;
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_word()
|
||||
{
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
// do search optimised for word starts:
|
||||
const unsigned char* _map = re.get_map();
|
||||
if((m_match_flags & match_prev_avail) || (position != base))
|
||||
--position;
|
||||
else if(match_prefix())
|
||||
return true;
|
||||
do
|
||||
{
|
||||
while((position != last) && traits_inst.isctype(*position, m_word_mask))
|
||||
++position;
|
||||
while((position != last) && !traits_inst.isctype(*position, m_word_mask))
|
||||
++position;
|
||||
if(position == last)
|
||||
break;
|
||||
|
||||
if(can_start(*position, _map, (unsigned char)mask_any) )
|
||||
{
|
||||
if(match_prefix())
|
||||
return true;
|
||||
}
|
||||
if(position == last)
|
||||
break;
|
||||
} while(true);
|
||||
return false;
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_line()
|
||||
{
|
||||
// do search optimised for line starts:
|
||||
const unsigned char* _map = re.get_map();
|
||||
if(match_prefix())
|
||||
return true;
|
||||
while(position != last)
|
||||
{
|
||||
while((position != last) && !is_separator(*position))
|
||||
++position;
|
||||
if(position == last)
|
||||
return false;
|
||||
++position;
|
||||
if(position == last)
|
||||
{
|
||||
if(re.can_be_null() && match_prefix())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( can_start(*position, _map, (unsigned char)mask_any) )
|
||||
{
|
||||
if(match_prefix())
|
||||
return true;
|
||||
}
|
||||
if(position == last)
|
||||
return false;
|
||||
//++position;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf()
|
||||
{
|
||||
if((position == base) && ((m_match_flags & match_not_bob) == 0))
|
||||
return match_prefix();
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class traits>
|
||||
bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace BOOST_REGEX_DETAIL_NS
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE: primary_transform.hpp
|
||||
* VERSION: see <boost/version.hpp>
|
||||
* DESCRIPTION: Heuristically determines the sort string format in use
|
||||
* by the current locale.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_PRIMARY_TRANSFORM
|
||||
#define BOOST_REGEX_PRIMARY_TRANSFORM
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
|
||||
enum{
|
||||
sort_C,
|
||||
sort_fixed,
|
||||
sort_delim,
|
||||
sort_unknown
|
||||
};
|
||||
|
||||
template <class S, class charT>
|
||||
unsigned count_chars(const S& s, charT c)
|
||||
{
|
||||
//
|
||||
// Count how many occurrences of character c occur
|
||||
// in string s: if c is a delimeter between collation
|
||||
// fields, then this should be the same value for all
|
||||
// sort keys:
|
||||
//
|
||||
unsigned int count = 0;
|
||||
for(unsigned pos = 0; pos < s.size(); ++pos)
|
||||
{
|
||||
if(s[pos] == c) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
template <class traits, class charT>
|
||||
unsigned find_sort_syntax(const traits* pt, charT* delim)
|
||||
{
|
||||
//
|
||||
// compare 'a' with 'A' to see how similar they are,
|
||||
// should really use a-accute but we can't portably do that,
|
||||
//
|
||||
typedef typename traits::string_type string_type;
|
||||
typedef typename traits::char_type char_type;
|
||||
|
||||
// Suppress incorrect warning for MSVC
|
||||
(void)pt;
|
||||
|
||||
char_type a[2] = {'a', '\0', };
|
||||
string_type sa(pt->transform(a, a+1));
|
||||
if(sa == a)
|
||||
{
|
||||
*delim = 0;
|
||||
return sort_C;
|
||||
}
|
||||
char_type A[2] = { 'A', '\0', };
|
||||
string_type sA(pt->transform(A, A+1));
|
||||
char_type c[2] = { ';', '\0', };
|
||||
string_type sc(pt->transform(c, c+1));
|
||||
|
||||
int pos = 0;
|
||||
while((pos <= static_cast<int>(sa.size())) && (pos <= static_cast<int>(sA.size())) && (sa[pos] == sA[pos])) ++pos;
|
||||
--pos;
|
||||
if(pos < 0)
|
||||
{
|
||||
*delim = 0;
|
||||
return sort_unknown;
|
||||
}
|
||||
//
|
||||
// at this point sa[pos] is either the end of a fixed width field
|
||||
// or the character that acts as a delimiter:
|
||||
//
|
||||
charT maybe_delim = sa[pos];
|
||||
if((pos != 0) && (count_chars(sa, maybe_delim) == count_chars(sA, maybe_delim)) && (count_chars(sa, maybe_delim) == count_chars(sc, maybe_delim)))
|
||||
{
|
||||
*delim = maybe_delim;
|
||||
return sort_delim;
|
||||
}
|
||||
//
|
||||
// OK doen't look like a delimiter, try for fixed width field:
|
||||
//
|
||||
if((sa.size() == sA.size()) && (sa.size() == sc.size()))
|
||||
{
|
||||
// note assumes that the fixed width field is less than
|
||||
// (numeric_limits<charT>::max)(), should be true for all types
|
||||
// I can't imagine 127 character fields...
|
||||
*delim = static_cast<charT>(++pos);
|
||||
return sort_fixed;
|
||||
}
|
||||
//
|
||||
// don't know what it is:
|
||||
//
|
||||
*delim = 0;
|
||||
return sort_unknown;
|
||||
}
|
||||
|
||||
|
||||
} // namespace BOOST_REGEX_DETAIL_NS
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regbase.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares class regbase.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_REGBASE_HPP
|
||||
#define BOOST_REGEX_V5_REGBASE_HPP
|
||||
|
||||
namespace boost{
|
||||
//
|
||||
// class regbase
|
||||
// handles error codes and flags
|
||||
//
|
||||
class regbase
|
||||
{
|
||||
public:
|
||||
enum flag_type_
|
||||
{
|
||||
//
|
||||
// Divide the flags up into logical groups:
|
||||
// bits 0-7 indicate main synatx type.
|
||||
// bits 8-15 indicate syntax subtype.
|
||||
// bits 16-31 indicate options that are common to all
|
||||
// regex syntaxes.
|
||||
// In all cases the default is 0.
|
||||
//
|
||||
// Main synatx group:
|
||||
//
|
||||
perl_syntax_group = 0, // default
|
||||
basic_syntax_group = 1, // POSIX basic
|
||||
literal = 2, // all characters are literals
|
||||
main_option_type = literal | basic_syntax_group | perl_syntax_group, // everything!
|
||||
//
|
||||
// options specific to perl group:
|
||||
//
|
||||
no_bk_refs = 1 << 8, // \d not allowed
|
||||
no_perl_ex = 1 << 9, // disable perl extensions
|
||||
no_mod_m = 1 << 10, // disable Perl m modifier
|
||||
mod_x = 1 << 11, // Perl x modifier
|
||||
mod_s = 1 << 12, // force s modifier on (overrides match_not_dot_newline)
|
||||
no_mod_s = 1 << 13, // force s modifier off (overrides match_not_dot_newline)
|
||||
|
||||
//
|
||||
// options specific to basic group:
|
||||
//
|
||||
no_char_classes = 1 << 8, // [[:CLASS:]] not allowed
|
||||
no_intervals = 1 << 9, // {x,y} not allowed
|
||||
bk_plus_qm = 1 << 10, // uses \+ and \?
|
||||
bk_vbar = 1 << 11, // use \| for alternatives
|
||||
emacs_ex = 1 << 12, // enables emacs extensions
|
||||
|
||||
//
|
||||
// options common to all groups:
|
||||
//
|
||||
no_escape_in_lists = 1 << 16, // '\' not special inside [...]
|
||||
newline_alt = 1 << 17, // \n is the same as |
|
||||
no_except = 1 << 18, // no exception on error
|
||||
failbit = 1 << 19, // error flag
|
||||
icase = 1 << 20, // characters are matched regardless of case
|
||||
nocollate = 0, // don't use locale specific collation (deprecated)
|
||||
collate = 1 << 21, // use locale specific collation
|
||||
nosubs = 1 << 22, // don't mark sub-expressions
|
||||
save_subexpression_location = 1 << 23, // save subexpression locations
|
||||
no_empty_expressions = 1 << 24, // no empty expressions allowed
|
||||
optimize = 0, // not really supported
|
||||
|
||||
|
||||
|
||||
basic = basic_syntax_group | collate | no_escape_in_lists,
|
||||
extended = no_bk_refs | collate | no_perl_ex | no_escape_in_lists,
|
||||
normal = 0,
|
||||
emacs = basic_syntax_group | collate | emacs_ex | bk_vbar,
|
||||
awk = no_bk_refs | collate | no_perl_ex,
|
||||
grep = basic | newline_alt,
|
||||
egrep = extended | newline_alt,
|
||||
sed = basic,
|
||||
perl = normal,
|
||||
ECMAScript = normal,
|
||||
JavaScript = normal,
|
||||
JScript = normal
|
||||
};
|
||||
typedef unsigned int flag_type;
|
||||
|
||||
enum restart_info
|
||||
{
|
||||
restart_any = 0,
|
||||
restart_word = 1,
|
||||
restart_line = 2,
|
||||
restart_buf = 3,
|
||||
restart_continue = 4,
|
||||
restart_lit = 5,
|
||||
restart_fixed_lit = 6,
|
||||
restart_count = 7
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// provide std lib proposal compatible constants:
|
||||
//
|
||||
namespace regex_constants{
|
||||
|
||||
enum flag_type_
|
||||
{
|
||||
|
||||
no_except = ::boost::regbase::no_except,
|
||||
failbit = ::boost::regbase::failbit,
|
||||
literal = ::boost::regbase::literal,
|
||||
icase = ::boost::regbase::icase,
|
||||
nocollate = ::boost::regbase::nocollate,
|
||||
collate = ::boost::regbase::collate,
|
||||
nosubs = ::boost::regbase::nosubs,
|
||||
optimize = ::boost::regbase::optimize,
|
||||
bk_plus_qm = ::boost::regbase::bk_plus_qm,
|
||||
bk_vbar = ::boost::regbase::bk_vbar,
|
||||
no_intervals = ::boost::regbase::no_intervals,
|
||||
no_char_classes = ::boost::regbase::no_char_classes,
|
||||
no_escape_in_lists = ::boost::regbase::no_escape_in_lists,
|
||||
no_mod_m = ::boost::regbase::no_mod_m,
|
||||
mod_x = ::boost::regbase::mod_x,
|
||||
mod_s = ::boost::regbase::mod_s,
|
||||
no_mod_s = ::boost::regbase::no_mod_s,
|
||||
save_subexpression_location = ::boost::regbase::save_subexpression_location,
|
||||
no_empty_expressions = ::boost::regbase::no_empty_expressions,
|
||||
|
||||
basic = ::boost::regbase::basic,
|
||||
extended = ::boost::regbase::extended,
|
||||
normal = ::boost::regbase::normal,
|
||||
emacs = ::boost::regbase::emacs,
|
||||
awk = ::boost::regbase::awk,
|
||||
grep = ::boost::regbase::grep,
|
||||
egrep = ::boost::regbase::egrep,
|
||||
sed = basic,
|
||||
perl = normal,
|
||||
ECMAScript = normal,
|
||||
JavaScript = normal,
|
||||
JScript = normal
|
||||
};
|
||||
typedef ::boost::regbase::flag_type syntax_option_type;
|
||||
|
||||
} // namespace regex_constants
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares boost::basic_regex<> and associated
|
||||
* functions and classes. This header is the main
|
||||
* entry point for the template regex code.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_REGEX_HPP_INCLUDED
|
||||
#define BOOST_RE_REGEX_HPP_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// what follows is all C++ don't include in C builds!!
|
||||
|
||||
#include <boost/regex/config.hpp>
|
||||
#include <boost/regex/v5/regex_workaround.hpp>
|
||||
#include <boost/regex_fwd.hpp>
|
||||
#include <boost/regex/regex_traits.hpp>
|
||||
#include <boost/regex/v5/error_type.hpp>
|
||||
#include <boost/regex/v5/match_flags.hpp>
|
||||
#include <boost/regex/v5/regex_raw_buffer.hpp>
|
||||
#include <boost/regex/pattern_except.hpp>
|
||||
#include <boost/regex/v5/char_regex_traits.hpp>
|
||||
#include <boost/regex/v5/states.hpp>
|
||||
#include <boost/regex/v5/regbase.hpp>
|
||||
#include <boost/regex/v5/basic_regex.hpp>
|
||||
#include <boost/regex/v5/basic_regex_creator.hpp>
|
||||
#include <boost/regex/v5/basic_regex_parser.hpp>
|
||||
#include <boost/regex/v5/sub_match.hpp>
|
||||
#include <boost/regex/v5/regex_format.hpp>
|
||||
#include <boost/regex/v5/match_results.hpp>
|
||||
#include <boost/regex/v5/perl_matcher.hpp>
|
||||
|
||||
namespace boost{
|
||||
#ifdef BOOST_REGEX_NO_FWD
|
||||
typedef basic_regex<char, regex_traits<char> > regex;
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
typedef basic_regex<wchar_t, regex_traits<wchar_t> > wregex;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef match_results<const char*> cmatch;
|
||||
typedef match_results<std::string::const_iterator> smatch;
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
typedef match_results<const wchar_t*> wcmatch;
|
||||
typedef match_results<std::wstring::const_iterator> wsmatch;
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/regex/v5/regex_match.hpp>
|
||||
#include <boost/regex/v5/regex_search.hpp>
|
||||
#include <boost/regex/v5/regex_iterator.hpp>
|
||||
#include <boost/regex/v5/regex_token_iterator.hpp>
|
||||
#include <boost/regex/v5/regex_grep.hpp>
|
||||
#include <boost/regex/v5/regex_replace.hpp>
|
||||
#include <boost/regex/v5/regex_merge.hpp>
|
||||
#include <boost/regex/v5/regex_split.hpp>
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // include
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_fwd.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Forward declares boost::basic_regex<> and
|
||||
* associated typedefs.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_FWD_HPP_INCLUDED
|
||||
#define BOOST_REGEX_FWD_HPP_INCLUDED
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
//
|
||||
// define BOOST_REGEX_NO_FWD if this
|
||||
// header doesn't work!
|
||||
//
|
||||
#ifdef BOOST_REGEX_NO_FWD
|
||||
# ifndef BOOST_RE_REGEX_HPP
|
||||
# include <boost/regex.hpp>
|
||||
# endif
|
||||
#else
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <class charT>
|
||||
class cpp_regex_traits;
|
||||
template <class charT>
|
||||
struct c_regex_traits;
|
||||
template <class charT>
|
||||
class w32_regex_traits;
|
||||
|
||||
#ifdef BOOST_REGEX_USE_WIN32_LOCALE
|
||||
template <class charT, class implementationT = w32_regex_traits<charT> >
|
||||
struct regex_traits;
|
||||
#elif defined(BOOST_REGEX_USE_CPP_LOCALE)
|
||||
template <class charT, class implementationT = cpp_regex_traits<charT> >
|
||||
struct regex_traits;
|
||||
#else
|
||||
template <class charT, class implementationT = c_regex_traits<charT> >
|
||||
struct regex_traits;
|
||||
#endif
|
||||
|
||||
template <class charT, class traits = regex_traits<charT> >
|
||||
class basic_regex;
|
||||
|
||||
typedef basic_regex<char, regex_traits<char> > regex;
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
typedef basic_regex<wchar_t, regex_traits<wchar_t> > wregex;
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REGEX_NO_FWD
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_grep.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Provides regex_grep implementation.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_REGEX_GREP_HPP
|
||||
#define BOOST_REGEX_V5_REGEX_GREP_HPP
|
||||
|
||||
|
||||
namespace boost{
|
||||
|
||||
//
|
||||
// regex_grep:
|
||||
// find all non-overlapping matches within the sequence first last:
|
||||
//
|
||||
template <class Predicate, class BidiIterator, class charT, class traits>
|
||||
inline unsigned int regex_grep(Predicate foo,
|
||||
BidiIterator first,
|
||||
BidiIterator last,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
if(e.flags() & regex_constants::failbit)
|
||||
return false;
|
||||
|
||||
typedef typename match_results<BidiIterator>::allocator_type match_allocator_type;
|
||||
|
||||
match_results<BidiIterator> m;
|
||||
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, match_allocator_type, traits> matcher(first, last, m, e, flags, first);
|
||||
unsigned int count = 0;
|
||||
while(matcher.find())
|
||||
{
|
||||
++count;
|
||||
if(0 == foo(m))
|
||||
return count; // caller doesn't want to go on
|
||||
if(m[0].second == last)
|
||||
return count; // we've reached the end, don't try and find an extra null match.
|
||||
if(m.length() == 0)
|
||||
{
|
||||
if(m[0].second == last)
|
||||
return count;
|
||||
// we found a NULL-match, now try to find
|
||||
// a non-NULL one at the same position:
|
||||
match_results<BidiIterator, match_allocator_type> m2(m);
|
||||
matcher.setf(match_not_null | match_continuous);
|
||||
if(matcher.find())
|
||||
{
|
||||
++count;
|
||||
if(0 == foo(m))
|
||||
return count;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset match back to where it was:
|
||||
m = m2;
|
||||
}
|
||||
matcher.unsetf((match_not_null | match_continuous) & ~flags);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//
|
||||
// regex_grep convenience interfaces:
|
||||
//
|
||||
template <class Predicate, class charT, class traits>
|
||||
inline unsigned int regex_grep(Predicate foo, const charT* str,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_grep(foo, str, str + traits::length(str), e, flags);
|
||||
}
|
||||
|
||||
template <class Predicate, class ST, class SA, class charT, class traits>
|
||||
inline unsigned int regex_grep(Predicate foo, const std::basic_string<charT, ST, SA>& s,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_grep(foo, s.begin(), s.end(), e, flags);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REGEX_V5_REGEX_GREP_HPP
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2003
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_iterator.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Provides regex_iterator implementation.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_REGEX_ITERATOR_HPP
|
||||
#define BOOST_REGEX_V5_REGEX_ITERATOR_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <class BidirectionalIterator,
|
||||
class charT,
|
||||
class traits>
|
||||
class regex_iterator_implementation
|
||||
{
|
||||
typedef basic_regex<charT, traits> regex_type;
|
||||
|
||||
match_results<BidirectionalIterator> what; // current match
|
||||
BidirectionalIterator base; // start of sequence
|
||||
BidirectionalIterator end; // end of sequence
|
||||
const regex_type re; // the expression
|
||||
match_flag_type flags; // flags for matching
|
||||
|
||||
public:
|
||||
regex_iterator_implementation(const regex_type* p, BidirectionalIterator last, match_flag_type f)
|
||||
: base(), end(last), re(*p), flags(f){}
|
||||
regex_iterator_implementation(const regex_iterator_implementation& other)
|
||||
:what(other.what), base(other.base), end(other.end), re(other.re), flags(other.flags){}
|
||||
bool init(BidirectionalIterator first)
|
||||
{
|
||||
base = first;
|
||||
return regex_search(first, end, what, re, flags);
|
||||
}
|
||||
bool compare(const regex_iterator_implementation& that)
|
||||
{
|
||||
if(this == &that) return true;
|
||||
return (&re.get_data() == &that.re.get_data()) && (end == that.end) && (flags == that.flags) && (what[0].first == that.what[0].first) && (what[0].second == that.what[0].second);
|
||||
}
|
||||
const match_results<BidirectionalIterator>& get()
|
||||
{ return what; }
|
||||
bool next()
|
||||
{
|
||||
//if(what.prefix().first != what[0].second)
|
||||
// flags |= match_prev_avail;
|
||||
BidirectionalIterator next_start = what[0].second;
|
||||
match_flag_type f(flags);
|
||||
if(!what.length() || (f & regex_constants::match_posix))
|
||||
f |= regex_constants::match_not_initial_null;
|
||||
//if(base != next_start)
|
||||
// f |= regex_constants::match_not_bob;
|
||||
bool result = regex_search(next_start, end, what, re, f, base);
|
||||
if(result)
|
||||
what.set_base(base);
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
regex_iterator_implementation& operator=(const regex_iterator_implementation&);
|
||||
};
|
||||
|
||||
template <class BidirectionalIterator,
|
||||
class charT = typename std::iterator_traits<BidirectionalIterator>::value_type,
|
||||
class traits = regex_traits<charT> >
|
||||
class regex_iterator
|
||||
{
|
||||
private:
|
||||
typedef regex_iterator_implementation<BidirectionalIterator, charT, traits> impl;
|
||||
typedef std::shared_ptr<impl> pimpl;
|
||||
public:
|
||||
typedef basic_regex<charT, traits> regex_type;
|
||||
typedef match_results<BidirectionalIterator> value_type;
|
||||
typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
|
||||
difference_type;
|
||||
typedef const value_type* pointer;
|
||||
typedef const value_type& reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
regex_iterator(){}
|
||||
regex_iterator(BidirectionalIterator a, BidirectionalIterator b,
|
||||
const regex_type& re,
|
||||
match_flag_type m = match_default)
|
||||
: pdata(new impl(&re, b, m))
|
||||
{
|
||||
if(!pdata->init(a))
|
||||
{
|
||||
pdata.reset();
|
||||
}
|
||||
}
|
||||
regex_iterator(const regex_iterator& that)
|
||||
: pdata(that.pdata) {}
|
||||
regex_iterator& operator=(const regex_iterator& that)
|
||||
{
|
||||
pdata = that.pdata;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const regex_iterator& that)const
|
||||
{
|
||||
if((pdata.get() == 0) || (that.pdata.get() == 0))
|
||||
return pdata.get() == that.pdata.get();
|
||||
return pdata->compare(*(that.pdata.get()));
|
||||
}
|
||||
bool operator!=(const regex_iterator& that)const
|
||||
{ return !(*this == that); }
|
||||
const value_type& operator*()const
|
||||
{ return pdata->get(); }
|
||||
const value_type* operator->()const
|
||||
{ return &(pdata->get()); }
|
||||
regex_iterator& operator++()
|
||||
{
|
||||
cow();
|
||||
if(0 == pdata->next())
|
||||
{
|
||||
pdata.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
regex_iterator operator++(int)
|
||||
{
|
||||
regex_iterator result(*this);
|
||||
++(*this);
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
|
||||
pimpl pdata;
|
||||
|
||||
void cow()
|
||||
{
|
||||
// copy-on-write
|
||||
if(pdata.get() && (pdata.use_count() > 1))
|
||||
{
|
||||
pdata.reset(new impl(*(pdata.get())));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef regex_iterator<const char*> cregex_iterator;
|
||||
typedef regex_iterator<std::string::const_iterator> sregex_iterator;
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
typedef regex_iterator<const wchar_t*> wcregex_iterator;
|
||||
typedef regex_iterator<std::wstring::const_iterator> wsregex_iterator;
|
||||
#endif
|
||||
|
||||
// make_regex_iterator:
|
||||
template <class charT, class traits>
|
||||
inline regex_iterator<const charT*, charT, traits> make_regex_iterator(const charT* p, const basic_regex<charT, traits>& e, regex_constants::match_flag_type m = regex_constants::match_default)
|
||||
{
|
||||
return regex_iterator<const charT*, charT, traits>(p, p+traits::length(p), e, m);
|
||||
}
|
||||
template <class charT, class traits, class ST, class SA>
|
||||
inline regex_iterator<typename std::basic_string<charT, ST, SA>::const_iterator, charT, traits> make_regex_iterator(const std::basic_string<charT, ST, SA>& p, const basic_regex<charT, traits>& e, regex_constants::match_flag_type m = regex_constants::match_default)
|
||||
{
|
||||
return regex_iterator<typename std::basic_string<charT, ST, SA>::const_iterator, charT, traits>(p.begin(), p.end(), e, m);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REGEX_V5_REGEX_ITERATOR_HPP
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_match.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Regular expression matching algorithms.
|
||||
* Note this is an internal header file included
|
||||
* by regex.hpp, do not include on its own.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_REGEX_MATCH_HPP
|
||||
#define BOOST_REGEX_MATCH_HPP
|
||||
|
||||
namespace boost{
|
||||
|
||||
//
|
||||
// proc regex_match
|
||||
// returns true if the specified regular expression matches
|
||||
// the whole of the input. Fills in what matched in m.
|
||||
//
|
||||
template <class BidiIterator, class Allocator, class charT, class traits>
|
||||
bool regex_match(BidiIterator first, BidiIterator last,
|
||||
match_results<BidiIterator, Allocator>& m,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, Allocator, traits> matcher(first, last, m, e, flags, first);
|
||||
return matcher.match();
|
||||
}
|
||||
template <class iterator, class charT, class traits>
|
||||
bool regex_match(iterator first, iterator last,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
match_results<iterator> m;
|
||||
return regex_match(first, last, m, e, flags | regex_constants::match_any);
|
||||
}
|
||||
//
|
||||
// query_match convenience interfaces:
|
||||
//
|
||||
template <class charT, class Allocator, class traits>
|
||||
inline bool regex_match(const charT* str,
|
||||
match_results<const charT*, Allocator>& m,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_match(str, str + traits::length(str), m, e, flags);
|
||||
}
|
||||
|
||||
template <class ST, class SA, class Allocator, class charT, class traits>
|
||||
inline bool regex_match(const std::basic_string<charT, ST, SA>& s,
|
||||
match_results<typename std::basic_string<charT, ST, SA>::const_iterator, Allocator>& m,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_match(s.begin(), s.end(), m, e, flags);
|
||||
}
|
||||
template <class charT, class traits>
|
||||
inline bool regex_match(const charT* str,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
match_results<const charT*> m;
|
||||
return regex_match(str, str + traits::length(str), m, e, flags | regex_constants::match_any);
|
||||
}
|
||||
|
||||
template <class ST, class SA, class charT, class traits>
|
||||
inline bool regex_match(const std::basic_string<charT, ST, SA>& s,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
typedef typename std::basic_string<charT, ST, SA>::const_iterator iterator;
|
||||
match_results<iterator> m;
|
||||
return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any);
|
||||
}
|
||||
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REGEX_MATCH_HPP
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_format.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Provides formatting output routines for search and replace
|
||||
* operations. Note this is an internal header file included
|
||||
* by regex.hpp, do not include on its own.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_REGEX_MERGE_HPP
|
||||
#define BOOST_REGEX_V5_REGEX_MERGE_HPP
|
||||
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <class OutputIterator, class Iterator, class traits, class charT>
|
||||
inline OutputIterator regex_merge(OutputIterator out,
|
||||
Iterator first,
|
||||
Iterator last,
|
||||
const basic_regex<charT, traits>& e,
|
||||
const charT* fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_replace(out, first, last, e, fmt, flags);
|
||||
}
|
||||
|
||||
template <class OutputIterator, class Iterator, class traits, class charT>
|
||||
inline OutputIterator regex_merge(OutputIterator out,
|
||||
Iterator first,
|
||||
Iterator last,
|
||||
const basic_regex<charT, traits>& e,
|
||||
const std::basic_string<charT>& fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_merge(out, first, last, e, fmt.c_str(), flags);
|
||||
}
|
||||
|
||||
template <class traits, class charT>
|
||||
inline std::basic_string<charT> regex_merge(const std::basic_string<charT>& s,
|
||||
const basic_regex<charT, traits>& e,
|
||||
const charT* fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_replace(s, e, fmt, flags);
|
||||
}
|
||||
|
||||
template <class traits, class charT>
|
||||
inline std::basic_string<charT> regex_merge(const std::basic_string<charT>& s,
|
||||
const basic_regex<charT, traits>& e,
|
||||
const std::basic_string<charT>& fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_replace(s, e, fmt, flags);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REGEX_V5_REGEX_MERGE_HPP
|
||||
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_raw_buffer.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Raw character buffer for regex code.
|
||||
* Note this is an internal header file included
|
||||
* by regex.hpp, do not include on its own.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_RAW_BUFFER_HPP
|
||||
#define BOOST_REGEX_RAW_BUFFER_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
struct empty_padding{};
|
||||
|
||||
union padding
|
||||
{
|
||||
void* p;
|
||||
unsigned int i;
|
||||
};
|
||||
|
||||
template <int N>
|
||||
struct padding3
|
||||
{
|
||||
enum{
|
||||
padding_size = 8,
|
||||
padding_mask = 7
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct padding3<2>
|
||||
{
|
||||
enum{
|
||||
padding_size = 2,
|
||||
padding_mask = 1
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct padding3<4>
|
||||
{
|
||||
enum{
|
||||
padding_size = 4,
|
||||
padding_mask = 3
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct padding3<8>
|
||||
{
|
||||
enum{
|
||||
padding_size = 8,
|
||||
padding_mask = 7
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct padding3<16>
|
||||
{
|
||||
enum{
|
||||
padding_size = 16,
|
||||
padding_mask = 15
|
||||
};
|
||||
};
|
||||
|
||||
enum{
|
||||
padding_size = padding3<sizeof(padding)>::padding_size,
|
||||
padding_mask = padding3<sizeof(padding)>::padding_mask
|
||||
};
|
||||
|
||||
//
|
||||
// class raw_storage
|
||||
// basically this is a simplified vector<unsigned char>
|
||||
// this is used by basic_regex for expression storage
|
||||
//
|
||||
|
||||
class raw_storage
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef unsigned char* pointer;
|
||||
private:
|
||||
pointer last, start, end;
|
||||
public:
|
||||
|
||||
raw_storage();
|
||||
raw_storage(size_type n);
|
||||
|
||||
~raw_storage()
|
||||
{
|
||||
::operator delete(start);
|
||||
}
|
||||
|
||||
void resize(size_type n)
|
||||
{
|
||||
size_type newsize = start ? last - start : 1024;
|
||||
while (newsize < n)
|
||||
newsize *= 2;
|
||||
size_type datasize = end - start;
|
||||
// extend newsize to WORD/DWORD boundary:
|
||||
newsize = (newsize + padding_mask) & ~(padding_mask);
|
||||
|
||||
// allocate and copy data:
|
||||
pointer ptr = static_cast<pointer>(::operator new(newsize));
|
||||
BOOST_REGEX_NOEH_ASSERT(ptr)
|
||||
if (start)
|
||||
std::memcpy(ptr, start, datasize);
|
||||
|
||||
// get rid of old buffer:
|
||||
::operator delete(start);
|
||||
|
||||
// and set up pointers:
|
||||
start = ptr;
|
||||
end = ptr + datasize;
|
||||
last = ptr + newsize;
|
||||
}
|
||||
|
||||
void* extend(size_type n)
|
||||
{
|
||||
if(size_type(last - end) < n)
|
||||
resize(n + (end - start));
|
||||
pointer result = end;
|
||||
end += n;
|
||||
return result;
|
||||
}
|
||||
|
||||
void* insert(size_type pos, size_type n)
|
||||
{
|
||||
BOOST_REGEX_ASSERT(pos <= size_type(end - start));
|
||||
if (size_type(last - end) < n)
|
||||
resize(n + (end - start));
|
||||
void* result = start + pos;
|
||||
std::memmove(start + pos + n, start + pos, (end - start) - pos);
|
||||
end += n;
|
||||
return result;
|
||||
}
|
||||
|
||||
size_type size()
|
||||
{
|
||||
return size_type(end - start);
|
||||
}
|
||||
|
||||
size_type capacity()
|
||||
{
|
||||
return size_type(last - start);
|
||||
}
|
||||
|
||||
void* data()const
|
||||
{
|
||||
return start;
|
||||
}
|
||||
|
||||
size_type index(void* ptr)
|
||||
{
|
||||
return size_type(static_cast<pointer>(ptr) - static_cast<pointer>(data()));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
end = start;
|
||||
}
|
||||
|
||||
void align()
|
||||
{
|
||||
// move end up to a boundary:
|
||||
end = start + (((end - start) + padding_mask) & ~padding_mask);
|
||||
}
|
||||
void swap(raw_storage& that)
|
||||
{
|
||||
std::swap(start, that.start);
|
||||
std::swap(end, that.end);
|
||||
std::swap(last, that.last);
|
||||
}
|
||||
};
|
||||
|
||||
inline raw_storage::raw_storage()
|
||||
{
|
||||
last = start = end = 0;
|
||||
}
|
||||
|
||||
inline raw_storage::raw_storage(size_type n)
|
||||
{
|
||||
start = end = static_cast<pointer>(::operator new(n));
|
||||
BOOST_REGEX_NOEH_ASSERT(start)
|
||||
last = start + n;
|
||||
}
|
||||
|
||||
} // namespace BOOST_REGEX_DETAIL_NS
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2009
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_format.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Provides formatting output routines for search and replace
|
||||
* operations. Note this is an internal header file included
|
||||
* by regex.hpp, do not include on its own.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_REGEX_REPLACE_HPP
|
||||
#define BOOST_REGEX_V5_REGEX_REPLACE_HPP
|
||||
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <class OutputIterator, class BidirectionalIterator, class traits, class charT, class Formatter>
|
||||
OutputIterator regex_replace(OutputIterator out,
|
||||
BidirectionalIterator first,
|
||||
BidirectionalIterator last,
|
||||
const basic_regex<charT, traits>& e,
|
||||
Formatter fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
regex_iterator<BidirectionalIterator, charT, traits> i(first, last, e, flags);
|
||||
regex_iterator<BidirectionalIterator, charT, traits> j;
|
||||
if(i == j)
|
||||
{
|
||||
if(!(flags & regex_constants::format_no_copy))
|
||||
out = BOOST_REGEX_DETAIL_NS::copy(first, last, out);
|
||||
}
|
||||
else
|
||||
{
|
||||
BidirectionalIterator last_m(first);
|
||||
while(i != j)
|
||||
{
|
||||
if(!(flags & regex_constants::format_no_copy))
|
||||
out = BOOST_REGEX_DETAIL_NS::copy(i->prefix().first, i->prefix().second, out);
|
||||
out = i->format(out, fmt, flags, e);
|
||||
last_m = (*i)[0].second;
|
||||
if(flags & regex_constants::format_first_only)
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
if(!(flags & regex_constants::format_no_copy))
|
||||
out = BOOST_REGEX_DETAIL_NS::copy(last_m, last, out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class traits, class charT, class Formatter>
|
||||
std::basic_string<charT> regex_replace(const std::basic_string<charT>& s,
|
||||
const basic_regex<charT, traits>& e,
|
||||
Formatter fmt,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
std::basic_string<charT> result;
|
||||
BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<charT> > i(result);
|
||||
regex_replace(i, s.begin(), s.end(), e, fmt, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REGEX_V5_REGEX_REPLACE_HPP
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_search.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Provides regex_search implementation.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_V5_REGEX_SEARCH_HPP
|
||||
#define BOOST_REGEX_V5_REGEX_SEARCH_HPP
|
||||
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <class BidiIterator, class Allocator, class charT, class traits>
|
||||
bool regex_search(BidiIterator first, BidiIterator last,
|
||||
match_results<BidiIterator, Allocator>& m,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_search(first, last, m, e, flags, first);
|
||||
}
|
||||
|
||||
template <class BidiIterator, class Allocator, class charT, class traits>
|
||||
bool regex_search(BidiIterator first, BidiIterator last,
|
||||
match_results<BidiIterator, Allocator>& m,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags,
|
||||
BidiIterator base)
|
||||
{
|
||||
if(e.flags() & regex_constants::failbit)
|
||||
return false;
|
||||
|
||||
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, Allocator, traits> matcher(first, last, m, e, flags, base);
|
||||
return matcher.find();
|
||||
}
|
||||
|
||||
//
|
||||
// regex_search convenience interfaces:
|
||||
//
|
||||
template <class charT, class Allocator, class traits>
|
||||
inline bool regex_search(const charT* str,
|
||||
match_results<const charT*, Allocator>& m,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_search(str, str + traits::length(str), m, e, flags);
|
||||
}
|
||||
|
||||
template <class ST, class SA, class Allocator, class charT, class traits>
|
||||
inline bool regex_search(const std::basic_string<charT, ST, SA>& s,
|
||||
match_results<typename std::basic_string<charT, ST, SA>::const_iterator, Allocator>& m,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_search(s.begin(), s.end(), m, e, flags);
|
||||
}
|
||||
|
||||
template <class BidiIterator, class charT, class traits>
|
||||
bool regex_search(BidiIterator first, BidiIterator last,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
if(e.flags() & regex_constants::failbit)
|
||||
return false;
|
||||
|
||||
match_results<BidiIterator> m;
|
||||
typedef typename match_results<BidiIterator>::allocator_type match_alloc_type;
|
||||
BOOST_REGEX_DETAIL_NS::perl_matcher<BidiIterator, match_alloc_type, traits> matcher(first, last, m, e, flags | regex_constants::match_any, first);
|
||||
return matcher.find();
|
||||
}
|
||||
|
||||
template <class charT, class traits>
|
||||
inline bool regex_search(const charT* str,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_search(str, str + traits::length(str), e, flags);
|
||||
}
|
||||
|
||||
template <class ST, class SA, class charT, class traits>
|
||||
inline bool regex_search(const std::basic_string<charT, ST, SA>& s,
|
||||
const basic_regex<charT, traits>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_search(s.begin(), s.end(), e, flags);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_REGEX_V5_REGEX_SEARCH_HPP
|
||||
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE regex_split.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Implements regex_split and associated functions.
|
||||
* Note this is an internal header file included
|
||||
* by regex.hpp, do not include on its own.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_SPLIT_HPP
|
||||
#define BOOST_REGEX_SPLIT_HPP
|
||||
|
||||
namespace boost{
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(push)
|
||||
#if BOOST_REGEX_MSVC < 1910
|
||||
#pragma warning(disable:4800)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
template <class charT>
|
||||
const basic_regex<charT>& get_default_expression(charT)
|
||||
{
|
||||
static const charT expression_text[4] = { '\\', 's', '+', '\00', };
|
||||
static const basic_regex<charT> e(expression_text);
|
||||
return e;
|
||||
}
|
||||
|
||||
template <class OutputIterator, class charT, class Traits1, class Alloc1>
|
||||
class split_pred
|
||||
{
|
||||
typedef std::basic_string<charT, Traits1, Alloc1> string_type;
|
||||
typedef typename string_type::const_iterator iterator_type;
|
||||
iterator_type* p_last;
|
||||
OutputIterator* p_out;
|
||||
std::size_t* p_max;
|
||||
std::size_t initial_max;
|
||||
public:
|
||||
split_pred(iterator_type* a, OutputIterator* b, std::size_t* c)
|
||||
: p_last(a), p_out(b), p_max(c), initial_max(*c) {}
|
||||
|
||||
bool operator()(const match_results<iterator_type>& what);
|
||||
};
|
||||
|
||||
template <class OutputIterator, class charT, class Traits1, class Alloc1>
|
||||
bool split_pred<OutputIterator, charT, Traits1, Alloc1>::operator()
|
||||
(const match_results<iterator_type>& what)
|
||||
{
|
||||
*p_last = what[0].second;
|
||||
if(what.size() > 1)
|
||||
{
|
||||
// output sub-expressions only:
|
||||
for(unsigned i = 1; i < what.size(); ++i)
|
||||
{
|
||||
*(*p_out) = what.str(i);
|
||||
++(*p_out);
|
||||
if(0 == --*p_max) return false;
|
||||
}
|
||||
return *p_max != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// output $` only if it's not-null or not at the start of the input:
|
||||
const sub_match<iterator_type>& sub = what[-1];
|
||||
if((sub.first != sub.second) || (*p_max != initial_max))
|
||||
{
|
||||
*(*p_out) = sub.str();
|
||||
++(*p_out);
|
||||
return --*p_max;
|
||||
}
|
||||
}
|
||||
//
|
||||
// initial null, do nothing:
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace BOOST_REGEX_DETAIL_NS
|
||||
|
||||
template <class OutputIterator, class charT, class Traits1, class Alloc1, class Traits2>
|
||||
std::size_t regex_split(OutputIterator out,
|
||||
std::basic_string<charT, Traits1, Alloc1>& s,
|
||||
const basic_regex<charT, Traits2>& e,
|
||||
match_flag_type flags,
|
||||
std::size_t max_split)
|
||||
{
|
||||
typedef typename std::basic_string<charT, Traits1, Alloc1>::const_iterator ci_t;
|
||||
//typedef typename match_results<ci_t>::allocator_type match_allocator;
|
||||
ci_t last = s.begin();
|
||||
std::size_t init_size = max_split;
|
||||
BOOST_REGEX_DETAIL_NS::split_pred<OutputIterator, charT, Traits1, Alloc1> pred(&last, &out, &max_split);
|
||||
ci_t i, j;
|
||||
i = s.begin();
|
||||
j = s.end();
|
||||
regex_grep(pred, i, j, e, flags);
|
||||
//
|
||||
// if there is still input left, do a final push as long as max_split
|
||||
// is not exhausted, and we're not splitting sub-expressions rather
|
||||
// than whitespace:
|
||||
if(max_split && (last != s.end()) && (e.mark_count() == 0))
|
||||
{
|
||||
*out = std::basic_string<charT, Traits1, Alloc1>((ci_t)last, (ci_t)s.end());
|
||||
++out;
|
||||
last = s.end();
|
||||
--max_split;
|
||||
}
|
||||
//
|
||||
// delete from the string everything that has been processed so far:
|
||||
s.erase(0, last - s.begin());
|
||||
//
|
||||
// return the number of new records pushed:
|
||||
return init_size - max_split;
|
||||
}
|
||||
|
||||
template <class OutputIterator, class charT, class Traits1, class Alloc1, class Traits2>
|
||||
inline std::size_t regex_split(OutputIterator out,
|
||||
std::basic_string<charT, Traits1, Alloc1>& s,
|
||||
const basic_regex<charT, Traits2>& e,
|
||||
match_flag_type flags = match_default)
|
||||
{
|
||||
return regex_split(out, s, e, flags, UINT_MAX);
|
||||
}
|
||||
|
||||
template <class OutputIterator, class charT, class Traits1, class Alloc1>
|
||||
inline std::size_t regex_split(OutputIterator out,
|
||||
std::basic_string<charT, Traits1, Alloc1>& s)
|
||||
{
|
||||
return regex_split(out, s, BOOST_REGEX_DETAIL_NS::get_default_expression(charT(0)), match_default, UINT_MAX);
|
||||
}
|
||||
|
||||
#ifdef BOOST_REGEX_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user