Compare commits

..

435 Commits

Author SHA1 Message Date
Maarten L. Hekkelman
bc0222dc0e attempt two 2025-10-01 16:42:05 +02:00
Maarten L. Hekkelman
10a6b5649b Using fast float instead of home baked version 2025-10-01 16:14:07 +02:00
Maarten L. Hekkelman
743e2800f8 update changelog 2025-09-30 11:21:03 +02:00
Maarten L. Hekkelman
32ac884127 Do not stop on empty audit_conform fields 2025-09-29 10:34:29 +02:00
Maarten L. Hekkelman
bec69f7d07 Fix reconstruction when entity ID's are missing 2025-09-29 09:59:04 +02:00
Maarten L. Hekkelman
a99215ad6a version bump 2025-09-24 16:45:05 +02:00
Maarten L. Hekkelman
e3d2cbd044 Lower required catch2 version 2025-09-24 16:42:45 +02:00
Maarten L. Hekkelman
5fc965789d messages updated 2025-09-24 15:11:33 +02:00
Maarten L. Hekkelman
b4596902aa Add compile features for Catch2, required on Windows 2025-09-24 14:15:19 +02:00
Maarten L. Hekkelman
cbf8b52f62 Update catch2 usage 2025-09-24 13:25:56 +02:00
Maarten L. Hekkelman
4e0fa1c916 No complete jthread on macOS/CLang 2025-09-24 13:00:50 +02:00
Maarten L. Hekkelman
95b007d38f Merge branch 'trunk' into develop 2025-09-24 11:38:01 +02:00
Maarten L. Hekkelman
b66f7a30ce Progress bar using WriteConsole on Windows 2025-09-24 11:36:37 +02:00
Maarten L. Hekkelman
ec7287c503 remove warning 2025-09-24 11:32:12 +02:00
Maarten L. Hekkelman
a41c591f0c Restore order of imports, avoid reordering by clang-format 2025-09-24 10:51:53 +02:00
Maarten L. Hekkelman
3a6527cdd5 yet another update on progress bar 2025-09-24 10:23:58 +02:00
Maarten L. Hekkelman
5f21a094c0 added flush to progress bar 2025-09-24 10:14:03 +02:00
Maarten L. Hekkelman
2203a1855d improved progress bar 2025-09-24 09:49:28 +02:00
Maarten L. Hekkelman
7edd2ecc18 new progress bar 2025-09-23 15:53:55 +02:00
Maarten L. Hekkelman
1d2953c850 Fix reconstruction, version bump 2025-09-22 13:51:18 +02:00
Maarten L. Hekkelman
dbf59ce622 reconstruct better when entity ID's are missing 2025-09-22 12:59:16 +02:00
Maarten L. Hekkelman
1596db8499 Merge branch 'develop' of github.com:pdb-redo/libcifpp into develop 2025-09-16 13:29:57 +02:00
Maarten L. Hekkelman
bd1fb5c5cd Added model::create_link 2025-09-16 13:29:51 +02:00
Maarten L. Hekkelman
da500025c3 swap atoms should swap type_symbol as well 2025-09-10 17:16:22 +02:00
Maarten L. Hekkelman
60eeea9a93 more resilient loading of dictionary data 2025-09-10 15:06:06 +02:00
Maarten L. Hekkelman
1220f01f1e change location of mmcif_ma.dic 2025-09-10 14:22:52 +02:00
Maarten L. Hekkelman
ad0a34fe98 Update changelog 2025-09-10 12:49:43 +02:00
Maarten L. Hekkelman
a7425ff1a0 Optimise validation code 2025-09-10 12:40:01 +02:00
Maarten L. Hekkelman
1ce25f86ae better check anisotrop atoms 2025-09-10 12:19:56 +02:00
Maarten L. Hekkelman
cd93f72b96 Merge branch 'develop' into better-create-entity-ids 2025-09-10 09:28:50 +02:00
Maarten L. Hekkelman
23500bd303 Fix reconstruction of really bare files 2025-09-10 09:25:49 +02:00
Maarten L. Hekkelman
14b4753b4f test for null 2025-09-09 19:55:13 +02:00
Maarten L. Hekkelman
4c37d5db5f use rowhandles 2025-09-09 19:52:39 +02:00
Maarten L. Hekkelman
fc2c4b4172 fix map::at in reconstruct sequences 2025-09-09 10:51:31 +02:00
Maarten L. Hekkelman
3ac64de16b Version bump, update changelog 2025-09-03 14:55:20 +02:00
Maarten L. Hekkelman
45eecd72b0 using pkg-config, when available 2025-09-03 14:24:29 +02:00
Maarten L. Hekkelman
d1dd558cda as object lib 2025-09-03 14:00:22 +02:00
Maarten L. Hekkelman
d19e2c2196 Update pcre2s 2025-09-03 13:11:45 +02:00
Maarten L. Hekkelman
72c7aca074 revert to catch2 version 2, due to linker errors on Windows? 2025-09-03 13:04:13 +02:00
Maarten L. Hekkelman
683a1087d0 Install catch2 before testing 2025-09-03 12:28:06 +02:00
Maarten L. Hekkelman
35bc139deb Update pcre2s 2025-09-03 11:39:00 +02:00
Maarten L. Hekkelman
45ece2fa0d pcre2 is no longer a depends on Windows 2025-09-03 11:18:04 +02:00
Maarten L. Hekkelman
11c98f553f Update Catch2 to version 3
Updated pcre2s
2025-09-03 11:15:31 +02:00
Maarten L. Hekkelman
28aa9b1036 Using pcre2s 2025-09-03 11:07:02 +02:00
Maarten L. Hekkelman
d7b5c0a748 remove message 2025-09-02 15:21:04 +02:00
Maarten L. Hekkelman
065e7f5f18 added clang format file 2025-09-02 14:59:28 +02:00
Maarten L. Hekkelman
4b1623cfdc pcre2 again 2025-09-02 14:57:07 +02:00
Maarten L. Hekkelman
1de973ddcb Fix findpcre2 cmake file 2025-09-02 13:12:20 +02:00
Maarten L. Hekkelman
eecc801203 last remaining warning 2025-09-02 12:57:08 +02:00
Maarten L. Hekkelman
5c50154ea4 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2025-09-02 12:54:03 +02:00
Maarten L. Hekkelman
0fa3d6aa94 Removing warning using MSVC 2025-09-02 12:54:07 +02:00
Maarten L. Hekkelman
01f5242bfb Revert "Add formatting file"
This reverts commit af6d8d4f71.
2025-09-02 11:57:21 +02:00
Maarten L. Hekkelman
af6d8d4f71 Add formatting file 2025-09-02 11:47:50 +02:00
Maarten L. Hekkelman
fa8285fc0f use std::format anyway, even if __cpp_lib_format is not defined. 2025-09-02 10:23:00 +02:00
Maarten L. Hekkelman
2e7f6b8337 cross platform check for lib format 2025-09-02 10:03:36 +02:00
Maarten L. Hekkelman
a6a55020eb Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2025-09-01 10:54:09 +02:00
Maarten L. Hekkelman
0e84ea454d fmt fix 2025-09-01 10:53:29 +02:00
Maarten L. Hekkelman
f3bf211d45 pdb formatting 2025-09-01 09:34:07 +02:00
Maarten L. Hekkelman
f5ef44836c pdb formatting 2025-09-01 09:31:22 +02:00
Maarten L. Hekkelman
070124b6e1 fix cif2pdb 2025-08-29 14:00:27 +02:00
Maarten L. Hekkelman
c8a46fcdd9 Stop when element is missing in reading PDB input 2025-08-29 13:17:17 +02:00
Maarten L. Hekkelman
5306b59fd8 Do not write zero seq ID's in PDB files 2025-08-29 10:08:56 +02:00
Maarten L. Hekkelman
90c5df832a Check only first datablock 2025-08-29 09:49:27 +02:00
Maarten L. Hekkelman
2aa439d51f test for fmt 2025-08-28 08:48:20 +02:00
Maarten L. Hekkelman
ac2b68517c conditional fmt 2025-08-27 16:08:51 +02:00
Maarten L. Hekkelman
e56b568c42 use cif::format... sigh 2025-08-27 15:46:41 +02:00
Maarten L. Hekkelman
63c49b2e04 Fix writing pdb files 2025-08-27 15:20:20 +02:00
Maarten L. Hekkelman
559fd18a20 Fix std::format usage 2025-08-27 08:57:40 +02:00
Maarten L. Hekkelman
beb7585261 fix std::format usage 2025-08-27 08:24:07 +02:00
Maarten L. Hekkelman
8b0f92aa9a Merge remote-tracking branch 'github/using-fmt' into develop 2025-08-27 07:43:22 +02:00
Maarten L. Hekkelman
0d8beeae5b No longer needed 2025-08-26 16:04:31 +02:00
Maarten L. Hekkelman
e3da654e67 Speed up build when eigen3 is not available 2025-08-26 15:54:55 +02:00
Maarten L. Hekkelman
dc9e151d89 remove warning 2025-08-26 15:37:22 +02:00
Maarten L. Hekkelman
7cfaf051ba should now work on windows 2025-08-26 15:16:01 +02:00
Maarten L. Hekkelman
7920491309 hope to find pcre2.h 2025-08-26 14:07:47 +02:00
Maarten L. Hekkelman
0ee493a3fb implib? 2025-08-26 13:55:25 +02:00
Maarten L. Hekkelman
7e23bc0c0b finding pcre2 on windows 2025-08-26 13:46:03 +02:00
Maarten L. Hekkelman
579f859562 no find_packge for pcre2 2025-08-26 13:42:14 +02:00
Maarten L. Hekkelman
752938ca44 using find_package? 2025-08-26 13:38:37 +02:00
Maarten L. Hekkelman
fce58c02fe no pcre2grep please, no tests either 2025-08-26 13:34:43 +02:00
Maarten L. Hekkelman
924f7c1505 finding pcre2, yet another attempt 2025-08-26 13:31:12 +02:00
Maarten L. Hekkelman
8944906fd2 fix warning, pcre2 2025-08-26 12:41:08 +02:00
Maarten L. Hekkelman
cb02969604 Using std::format 2025-08-25 16:31:00 +02:00
Maarten L. Hekkelman
31090c6ec5 attempt 2 2025-08-25 11:25:10 +02:00
Maarten L. Hekkelman
9e30d2bc1a finding pcre2 2025-08-25 10:39:48 +02:00
Maarten L. Hekkelman
93d703f7a1 Do not buld pcre tests 2025-08-20 20:40:08 +02:00
Maarten L. Hekkelman
3c241048a5 do not install pcre 2025-08-20 17:02:40 +02:00
Maarten L. Hekkelman
2788536799 this should work 2025-08-20 16:58:52 +02:00
Maarten L. Hekkelman
314d435a18 Another way of importing pcre 2025-08-20 16:49:12 +02:00
Maarten L. Hekkelman
37edcd8666 Finding and optionally building pcre 2025-08-20 15:47:49 +02:00
Maarten L. Hekkelman
10e290fbdf pcre2 in github actions? 2025-08-20 14:40:50 +02:00
Maarten L. Hekkelman
58cda1241e cleanup 2025-08-20 13:41:45 +02:00
Maarten L. Hekkelman
3659aaabff remove unneeded allocations 2025-08-20 13:35:15 +02:00
Maarten L. Hekkelman
727a39cc54 Finishing up replacing boost with pcre 2025-08-20 13:28:24 +02:00
Maarten L. Hekkelman
fd9ccdfff9 Using pcre instead of boost::regex 2025-08-19 16:16:43 +02:00
Maarten L. Hekkelman
aabee270b3 update .gitignore 2025-08-19 14:28:51 +02:00
Maarten L. Hekkelman
647c58f8ec allow code to be built with older compilers... 2025-08-19 12:44:41 +02:00
Maarten L. Hekkelman
0b8024d19c Optimise query processing 2025-08-19 12:24:33 +02:00
Maarten L. Hekkelman
d59b0bf27f Remove wrong warnings 2025-08-13 11:30:53 +02:00
Maarten L. Hekkelman
398c16eac2 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2025-08-13 09:02:10 +02:00
Maarten L. Hekkelman
fa869bdc7d lightweight fixup 2025-08-13 09:01:50 +02:00
Maarten L. Hekkelman
c20d0d2a30 lightweight fixup 2025-08-12 16:45:19 +02:00
Maarten L. Hekkelman
000f2736c2 Merge branch 'develop' into clebreto-feature/enrich_structure_options 2025-08-11 10:13:20 +02:00
Maarten L. Hekkelman
cfcc81bb62 verbose messages 2025-08-11 10:13:07 +02:00
Maarten L. Hekkelman
82eae05868 changed b-factor options for structure loading 2025-06-11 14:17:50 +02:00
Maarten L. Hekkelman
e8fb53c49b Alternate implementation of structure_open_options 2025-06-11 13:35:58 +02:00
Maarten L. Hekkelman
604c97afe1 Merge branch 'develop' into clebreto-feature/enrich_structure_options 2025-06-11 11:43:01 +02:00
Maarten L. Hekkelman
7e60cdf272 remove redundant statement 2025-06-11 11:42:26 +02:00
Maarten L. Hekkelman
9ea7cfcc80 Remove test 2025-06-11 09:56:26 +02:00
Maarten L. Hekkelman
a7a4a16f79 remove debug code 2025-06-11 09:45:45 +02:00
Maarten L. Hekkelman
6717059934 Revert renaming compound_id to mon_id in residue 2025-06-11 09:41:49 +02:00
Maarten L. Hekkelman
714747c280 version bump 2025-06-11 09:32:36 +02:00
Maarten L. Hekkelman
81cd305c80 rename mm::polymer fields and methods to better match mmcif_pdbx naming.
fix building mm::structure using pdb_seq_num instead of auth_seq_num
2025-06-11 09:30:54 +02:00
Maarten L. Hekkelman
5de872bbb3 Version bump, update mmcif_pdbx.dic 2025-06-10 09:17:30 +02:00
Maarten L. Hekkelman
ce6a75a920 right... 2025-06-10 09:11:26 +02:00
Maarten L. Hekkelman
874a5cb2f2 missing code added 2025-06-02 15:09:49 +02:00
Maarten L. Hekkelman
6e2202d4f1 More verbose strip 2025-06-02 09:10:58 +02:00
Maarten L. Hekkelman
bcf33df701 Added strip, removed dangerous datablock::is_valid (non-const version) 2025-06-02 08:52:58 +02:00
Maarten L. Hekkelman
3bdcf21c69 Merge commit '4b36bdc' into develop 2025-05-29 16:14:15 +02:00
Maarten L. Hekkelman
4b36bdc58c work around incorrect mmcif_pdbx name 2025-05-29 16:13:28 +02:00
Maarten L. Hekkelman
6d9008ee8c Merge branch 'trunk' into develop 2025-05-29 15:15:41 +02:00
Maarten L. Hekkelman
ee93692707 comment formatting 2025-05-29 14:15:13 +02:00
Maarten L. Hekkelman
2bcc368bce reconstruct when audit_conform is missing 2025-05-29 14:07:45 +02:00
Maarten L. Hekkelman
6cc4467d53 options 2025-05-27 13:55:13 +02:00
Maarten L. Hekkelman
425f98dc07 No longer fail pdb conversion when missing compound info 2025-05-12 12:45:21 +02:00
Maarten L. Hekkelman
cf34a9f3ad Updated test file 2025-05-12 11:56:42 +02:00
Maarten L. Hekkelman
3b2f347428 Remove reconstruct test again 2025-05-12 11:46:16 +02:00
Maarten L. Hekkelman
bd82c3cc4f Only reconstruct when needed 2025-05-12 10:24:00 +02:00
Maarten L. Hekkelman
af319866c7 added get_atom_by_atom_id 2025-05-06 14:11:05 +02:00
Maarten L. Hekkelman
b6ab29398e Fix parsing PDB files 2025-04-15 09:56:51 +02:00
Maarten L. Hekkelman
a5bb1797c0 Merge branch 'trunk' of github.com:PDB-REDO/libcifpp into trunk 2025-04-15 09:17:44 +02:00
Maarten L. Hekkelman
a9647671c4 entity_poly.type is now by default 'other' 2025-04-15 09:17:37 +02:00
Maarten L. Hekkelman
63f784e7da Reconstruct branches, somewhat 2025-04-14 12:44:27 +02:00
Maarten L. Hekkelman
5da3379e0b Don't reconstruct invalid files, non-polymer should not have auth_seq_id 2025-04-14 11:06:36 +02:00
Maarten L. Hekkelman
2f3514689d Default value for b_iso_or_equiv, better sorting of atoms 2025-04-09 15:12:11 +02:00
Maarten L. Hekkelman
89a3ea4e24 update mmcif_pdbx.dic 2025-04-09 15:11:37 +02:00
Maarten L. Hekkelman
467e9555f4 remove duplicate test 2025-04-09 13:11:05 +02:00
Maarten L. Hekkelman
5b32ca15f7 Fix cleanup_empty_categories 2025-04-09 13:06:45 +02:00
Maarten L. Hekkelman
92402817d2 Merge branch 'trunk' into develop 2025-04-09 13:05:12 +02:00
Maarten L. Hekkelman
60ad3031d5 remove warning, hopefully fix docs action 2025-04-09 10:15:15 +02:00
Maarten L. Hekkelman
724cddb481 Merged develop manually 2025-04-09 09:20:53 +02:00
Maarten L. Hekkelman
41c0521480 Merge branch 'feature/enrich_structure_options' of github.com:clebreto/libcifpp into clebreto-feature/enrich_structure_options 2025-04-02 13:58:01 +02:00
Maarten L. Hekkelman
85ac2b1f63 Fix parsing bogus PDB files (with REMARK 001) 2025-04-02 11:29:25 +02:00
Maarten L. Hekkelman
13a97353aa fix test 2025-04-02 11:18:20 +02:00
Maarten L. Hekkelman
f49c166b9b Fix for MSVC 2025-03-31 12:52:26 +02:00
Maarten L. Hekkelman
fffa326f80 validator for multiple dictionaries 2025-03-31 12:38:28 +02:00
Maarten L. Hekkelman
da446adbb2 non compiling code 2025-03-28 16:15:58 +01:00
Maarten L. Hekkelman
617fec5c69 Close, but no cigar 2025-03-28 15:06:02 +01:00
Maarten L. Hekkelman
cfefa69c9c Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2025-03-27 11:40:42 +01:00
Maarten L. Hekkelman
00638a9e23 Fix loading coordinates from converted restraint files 2025-03-27 11:36:46 +01:00
Maarten L. Hekkelman
e241e03a15 Fix loading coordinates from converted restraint files 2025-03-27 11:26:30 +01:00
Maarten L. Hekkelman
b1faa3bd48 version bump 2025-03-10 13:58:34 +01:00
Maarten L. Hekkelman
6d28f487ec fix readme 2025-03-10 13:56:33 +01:00
Maarten L. Hekkelman
b231f92f76 Construct nonpoly_scheme 2025-03-10 13:55:25 +01:00
LE BRETON Come
7d33d56c0e Update docs 2025-03-07 15:59:19 +01:00
LE BRETON Come
f86f34e5e1 WIP Enrich StructureOpenOptions 2025-03-07 15:54:30 +01:00
Maarten L. Hekkelman
5e7b52b7de loading dictionaries 2025-02-17 12:57:08 +01:00
Maarten L. Hekkelman
0459d344e9 Fixes in error reporting 2025-02-17 12:32:14 +01:00
Maarten L. Hekkelman
71e525cd76 Refactored dictionary loading 2025-02-17 09:40:36 +01:00
Maarten L. Hekkelman
1480706d8b change for mingw 2025-02-05 16:05:08 +01:00
Maarten L. Hekkelman
96655b6d80 revert 2025-01-29 17:12:59 +01:00
Maarten L. Hekkelman
eed2aa0d0d better way to include eigen3 2025-01-29 17:01:44 +01:00
Maarten L. Hekkelman
de0c078a23 Update changelog 2025-01-29 16:08:55 +01:00
Maarten L. Hekkelman
321e995a54 Add some comments 2025-01-29 16:07:03 +01:00
Maarten L. Hekkelman
da9f1f81d7 Fix eigen3 problems on github? 2025-01-29 15:57:16 +01:00
Maarten L. Hekkelman
c6d4477a24 Using eigen quaternions 2025-01-29 15:37:57 +01:00
Maarten L. Hekkelman
523b073cdc own eigen 2025-01-29 14:25:28 +01:00
Maarten L. Hekkelman
2591bee21b test for github actions, own eigen library 2025-01-29 13:54:20 +01:00
Maarten L. Hekkelman
d881ca00c9 cleanup 2025-01-29 13:54:00 +01:00
Maarten L. Hekkelman
329dbff474 replace deprecated call 2025-01-29 13:42:37 +01:00
Maarten L. Hekkelman
d84a9fe6dc Deal with missing entity.type 2025-01-29 13:41:11 +01:00
Maarten L. Hekkelman
dcd812a996 Optimise text comparison routines 2025-01-29 11:39:08 +01:00
Maarten L. Hekkelman
6750194d9b Fixes for dictionary loading 2025-01-28 16:03:46 +01:00
Maarten L. Hekkelman
05865c3d9b Fixes for dictionary loading 2025-01-28 15:51:40 +01:00
Maarten L. Hekkelman
21e224bf00 Merge branch 'trunk' into develop 2025-01-15 14:25:57 +01:00
Maarten L. Hekkelman
f401d3fd0c Add way to load dictionary extensions along with main dictionary 2025-01-15 14:25:29 +01:00
Maarten L. Hekkelman
fd436871f1 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2024-12-24 12:55:48 +01:00
Maarten L. Hekkelman
fcf7864a4b Remove dead code 2024-12-24 12:55:44 +01:00
Maarten L. Hekkelman
c4003956d9 Only build tests when not included as subdirectory 2024-12-24 11:32:07 +01:00
Maarten L. Hekkelman
de622b6162 cmake policy for Boost 2024-12-16 08:54:47 +01:00
Maarten L. Hekkelman
41b4bdb90e update changelog 2024-11-19 08:57:00 +01:00
Maarten L. Hekkelman
af73cb3ad3 Version bump 2024-11-18 08:09:01 +01:00
Maarten L. Hekkelman
240b631963 Merge branch 'trunk' into develop 2024-11-18 08:08:30 +01:00
Maarten L. Hekkelman
c2a747af8c Fix remark 3 parser 2024-11-18 08:07:15 +01:00
Maarten L. Hekkelman
5959647826 three way comparison for point 2024-11-04 09:25:51 +01:00
Maarten L. Hekkelman
9542e211bc avoid cmake errors in windows? 2024-10-15 08:56:34 +02:00
Maarten L. Hekkelman
d07890db7f Set target property CIFPP_DATA_DIR 2024-10-07 11:24:10 +02:00
Maarten L. Hekkelman
ca241bd8f2 Fix linking to std::atomic 2024-09-23 09:14:04 +02:00
Charles Beattie
e444092711 and_condition_impl::combine_equal - Remove UB container modification. (#63)
* and_condition_impl::combine_equal - Remove UB container modification.

The container is modified while iterating it.
Switched to indexed based iteration to avoid UB.

* Update condition.cpp

Sorry missed this line.
2024-09-13 17:08:18 +02:00
Maarten L. Hekkelman
a96b1e07f4 Merge remote-tracking branch 'origin/develop' into trunk 2024-09-10 11:34:00 +02:00
Maarten L. Hekkelman
f48c31bcb5 Proposed fix for comparing floating points (needed on macOS) (#62)
* Proposed fix for comparing floating points (needed on macOS)

* Work around weird behaviour in testing floats using catch2

* Better from_chars implementation
2024-09-10 11:31:59 +02:00
Maarten L. Hekkelman
d85ab93a35 Fix swap for incomplete rows 2024-08-27 15:48:20 +02:00
Maarten L. Hekkelman
a6804b5aca test on macOS 2024-07-22 12:31:17 +02:00
Maarten L. Hekkelman
e4dcb211ee modify tests for macOS? 2024-07-22 11:41:05 +02:00
Maarten L. Hekkelman
a5a5f47f7a Add missing file 2024-07-16 12:44:43 +02:00
Maarten L. Hekkelman
25c900c387 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2024-07-16 12:08:59 +02:00
Maarten L. Hekkelman
4e95f7b83e restored find atomic 2024-07-16 12:08:43 +02:00
IdaDeVries
66ad3b0cee Use c++20 2024-07-15 09:54:17 +02:00
Maarten L. Hekkelman
e853cd1ca0 set_validator changes 2024-07-01 12:27:31 +02:00
Maarten L. Hekkelman
b9544033c6 Fix reconstruction 2024-07-01 12:16:11 +02:00
Maarten L. Hekkelman
17840cb8cc New dictionary 2024-07-01 12:15:39 +02:00
Maarten L. Hekkelman
f85b6d94b8 Attempt to get code compiling on msvc/macos 2024-06-12 10:25:23 +02:00
Maarten L. Hekkelman
6c32a9f198 Add operator != for optional type 2024-06-12 09:56:04 +02:00
Maarten L. Hekkelman
cefeebbfb8 fix rename in comment 2024-06-12 09:55:46 +02:00
Maarten L. Hekkelman
941a015b43 Do not stop when compound is missing 2024-05-15 09:05:01 +02:00
Maarten L. Hekkelman
ae0e9fbe77 fix cif::item constructor
fix ordering atoms
2024-04-29 12:06:50 +02:00
Maarten L. Hekkelman
3484c3dd2e Merge branch 'develop' of github.com:pdb-redo/libcifpp into develop 2024-04-29 08:34:19 +02:00
Maarten L. Hekkelman
5be8f749bd Fix validation error 2024-04-29 08:34:15 +02:00
Maarten L. Hekkelman
cf484707a0 Fix validation error 2024-04-29 08:30:11 +02:00
Maarten L. Hekkelman
f12e529c0b default alt id for new atoms 2024-04-24 13:21:32 +02:00
Maarten L. Hekkelman
01b90a2ba5 set occupancy of newly added atom 2024-04-23 15:42:55 +02:00
Maarten L. Hekkelman
cd1e952812 residue::create_new_atom 2024-04-23 13:50:25 +02:00
Maarten L. Hekkelman
996f1e4277 check existence of alternate for specific atoms 2024-04-17 16:49:37 +02:00
Maarten L. Hekkelman
2d84694f86 remove debug statement 2024-04-17 14:14:19 +02:00
Maarten L. Hekkelman
65718c64cc fix updating index for change in value in category 2024-04-17 12:54:58 +02:00
Maarten L. Hekkelman
6e30365f55 endl 2024-04-16 11:15:22 +02:00
Maarten L. Hekkelman
c0555b6d86 Export CIFPP_SHARE_DIR variable when included as sub directory 2024-04-10 11:38:23 +02:00
Maarten L. Hekkelman
1ff9b6c071 fix makefile 2024-04-08 10:32:35 +02:00
Maarten L. Hekkelman
c1a51a1dfa fix makefile 2024-04-08 10:31:08 +02:00
Maarten L. Hekkelman
bfbbeb90e7 fix makefile to create shared libraries when requested to do so
example should work when there is no components.cif file yet
2024-04-03 17:21:48 +02:00
Maarten L. Hekkelman
588e075325 Fix query generation when using constant numeric values
replace size_t with std::size_t to silence warnings
2024-04-03 14:01:51 +02:00
Maarten L. Hekkelman
66717fee68 take DESTDIR into account 2024-03-28 20:31:19 +01:00
Maarten L. Hekkelman
844f52c955 Merge branch 'develop' into trunk 2024-03-28 19:04:39 +01:00
Maarten L. Hekkelman
e679cd05c1 update changelog 2024-03-27 16:19:54 +01:00
Maarten L. Hekkelman
1e72ce4830 add missing header 2024-03-19 19:53:00 +01:00
Maarten L. Hekkelman
3bb21c5403 Try one more location to locate resources 2024-03-14 11:34:36 +01:00
Maarten L. Hekkelman
6d1be23ad0 oops 2024-03-14 11:12:39 +01:00
Maarten L. Hekkelman
0472b9a4a4 Merge branch 'trunk' into develop 2024-03-14 10:55:22 +01:00
Maarten L. Hekkelman
c9acff49f9 version bump, clean up makefile 2024-03-14 10:54:54 +01:00
Maarten L. Hekkelman
7cab560595 minimum requires cmake version 2024-03-14 07:37:50 +01:00
Maarten L. Hekkelman
ac98531a2f Fix writing exports file, version bump 2024-03-12 12:55:59 +01:00
Maarten L. Hekkelman
917e0ba79c Merge branch 'develop' of github.com:pdb-redo/libcifpp into develop 2024-03-12 10:12:55 +01:00
Maarten L. Hekkelman
3ebceb7522 do not number non-polymer residues 2024-03-12 10:12:50 +01:00
Maarten L. Hekkelman
92bd52da12 get that code compiling 2024-03-09 14:13:37 +01:00
Maarten L. Hekkelman
fb56a9cd6e version bump 2024-03-09 14:03:45 +01:00
Maarten L. Hekkelman
a4680f7d38 error_code should be checked differently? 2024-03-09 13:54:53 +01:00
Maarten L. Hekkelman
da8a72a8aa Merge branch 'develop' into trunk 2024-03-06 16:50:33 +01:00
Maarten L. Hekkelman
ac497932b5 Fix loading embedded restraint data 2024-03-06 16:50:12 +01:00
Maarten L. Hekkelman
9927b5061a Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2024-03-06 16:21:15 +01:00
Maarten L. Hekkelman
cedaab9642 load compound info from appended restraint info 2024-03-06 16:20:43 +01:00
Maarten L. Hekkelman
50bf2145ec Merge branch 'develop' into trunk 2024-03-06 15:54:56 +01:00
Maarten L. Hekkelman
dc77729f50 update changelog 2024-03-06 15:48:17 +01:00
Maarten L. Hekkelman
e3330d667a formatting 2024-03-06 13:22:00 +01:00
Maarten L. Hekkelman
9822f397a1 update libcifpp makefile 2024-03-06 12:58:50 +01:00
Maarten L. Hekkelman
a3b5ce9959 loading extra compound info changed
cif::file constructors
2024-03-06 12:33:58 +01:00
Maarten L. Hekkelman
9eb06e929a fixes in iterators 2024-03-05 15:52:36 +01:00
Maarten L. Hekkelman
629e06d647 write uncoloured text 2024-03-05 15:22:05 +01:00
Maarten L. Hekkelman
51ccb92184 small changes in constructors 2024-03-05 13:41:05 +01:00
Maarten L. Hekkelman
3cd27f13fd calculate formula_weight when missing 2024-03-05 13:02:31 +01:00
Maarten L. Hekkelman
ae668530c0 do not install files if they are not downloaded 2024-03-05 11:40:33 +01:00
Maarten L. Hekkelman
4a8b1c056c do not install files if they are not downloaded 2024-03-05 11:39:45 +01:00
Maarten L. Hekkelman
d7a5e598bc Merge branch 'develop' of github.com:pdb-redo/libcifpp into develop 2024-03-05 11:33:25 +01:00
Maarten L. Hekkelman
3f1ee32cc6 better trim 2024-03-05 11:33:19 +01:00
Maarten L. Hekkelman
725d6ead98 stupid typo 2024-02-29 14:56:45 +01:00
Maarten L. Hekkelman
baf70579de version bump 2024-02-27 15:23:51 +01:00
Maarten L. Hekkelman
cd28ab58a3 typo in error message 2024-02-27 14:40:56 +01:00
Maarten L. Hekkelman
a78fa0a81d reconstruction fixes 2024-02-27 13:36:45 +01:00
Maarten L. Hekkelman
82130be5f5 oops 2024-02-27 13:29:38 +01:00
Maarten L. Hekkelman
510ce62dfb reconstruction fixes 2024-02-27 13:24:53 +01:00
Maarten L. Hekkelman
93375a5087 Develop (#54)
* - renamed exists to contains
- fix compare for ints where item is empty

* - checking and optionally dropping ndb_poly_seq_scheme
- fix in iterator_proxy

* formatting data in reconstruction

* Version bump

* Attempt to get code compiling on macOS

* attempt 2 to build on macOS

* Added remove column

* Added rename_column
Added item_alias
Rename columns in reconstruct

* macOS...

* Fixed serious bug in emplace of both datablock and file.

* renaming field and column to item

* replace tag with item or item_name

* Fix validate pdbx

* version bump

* atom_site_anisotrop check

* - changed compound::is_known_peptide/is_know_base
- Add audit_conform only if file is really valid
- Added reconstruction code for PDBx

* pdb2cif work

* gcc diagnostics and clipper

* Fixing pdb2cif, and sequence checking

* work around bug in old gcc

* fix reconstruct sequence

* formatting

* some small optimisations

* Fix url in compound message

* Fix operator= for item_handle

* Fix operator= for item_handle

* new update_value in category

* test builds faster now

* Use Catch2 version 3 if installed

* catch22
2024-02-17 16:03:14 +01:00
Maarten L. Hekkelman
be738e7fb1 catch22 2024-02-17 15:37:53 +01:00
Maarten L. Hekkelman
9c78131df3 Use Catch2 version 3 if installed 2024-02-17 15:20:11 +01:00
Maarten L. Hekkelman
d94f6f4d19 test builds faster now 2024-02-05 13:01:28 +01:00
Maarten L. Hekkelman
9a3eced350 new update_value in category 2024-01-31 16:20:49 +01:00
Maarten L. Hekkelman
2fed7a76fb Fix operator= for item_handle 2024-01-30 16:51:12 +01:00
Maarten L. Hekkelman
f02e59df1b Fix operator= for item_handle 2024-01-30 16:40:02 +01:00
Maarten L. Hekkelman
04147a2fe9 Fix url in compound message 2024-01-30 16:39:32 +01:00
Maarten L. Hekkelman
0e83bc31dc some small optimisations 2024-01-30 16:29:22 +01:00
Maarten L. Hekkelman
75a5f7960f formatting 2024-01-30 11:12:29 +01:00
Maarten L. Hekkelman
3f93c27b07 fix reconstruct sequence 2024-01-29 17:40:24 +01:00
Maarten L. Hekkelman
ab781d4516 work around bug in old gcc 2024-01-29 16:33:53 +01:00
Maarten L. Hekkelman
446438bf8c Fixing pdb2cif, and sequence checking 2024-01-29 16:12:01 +01:00
Maarten L. Hekkelman
4e012cbd48 gcc diagnostics and clipper 2024-01-29 16:11:08 +01:00
Maarten L. Hekkelman
12ee4a792c pdb2cif work 2024-01-29 13:00:50 +01:00
Maarten L. Hekkelman
e59750386f - changed compound::is_known_peptide/is_know_base
- Add audit_conform only if file is really valid
- Added reconstruction code for PDBx
2024-01-24 16:14:08 +01:00
Maarten L. Hekkelman
4e19d54867 atom_site_anisotrop check 2024-01-23 14:08:25 +01:00
Maarten L. Hekkelman
db603e5438 version bump 2024-01-23 11:57:29 +01:00
Maarten L. Hekkelman
5320cb123a Fix validate pdbx 2024-01-23 11:57:21 +01:00
Maarten L. Hekkelman
30a2ebdbb4 Merge remote-tracking branch 'github/develop-cif2fasta' into develop 2024-01-23 11:42:12 +01:00
Maarten L. Hekkelman
a5d43998a3 replace tag with item or item_name 2024-01-23 11:41:13 +01:00
Maarten L. Hekkelman
2792caec70 renaming field and column to item 2024-01-23 11:23:20 +01:00
Maarten L. Hekkelman
fb2b1e984c Fixed serious bug in emplace of both datablock and file. 2024-01-22 16:04:57 +01:00
Maarten L. Hekkelman
13ab1caf95 macOS... 2024-01-22 15:33:43 +01:00
Maarten L. Hekkelman
5d4534fac4 Added rename_column
Added item_alias
Rename columns in reconstruct
2024-01-22 15:15:11 +01:00
Maarten L. Hekkelman
f450643861 Added remove column 2024-01-22 14:03:22 +01:00
Maarten L. Hekkelman
fc14a65511 attempt 2 to build on macOS 2024-01-22 13:08:25 +01:00
Maarten L. Hekkelman
bbd1e27c5e Attempt to get code compiling on macOS 2024-01-22 12:49:11 +01:00
Maarten L. Hekkelman
369a83b718 Version bump 2024-01-22 12:00:38 +01:00
Maarten L. Hekkelman
afc541b956 Merge remote-tracking branch 'github/develop-cif2fasta' into develop 2024-01-22 12:00:11 +01:00
Maarten L. Hekkelman
7e4d2ffb4d formatting data in reconstruction 2024-01-22 11:43:56 +01:00
Maarten L. Hekkelman
e09913a94f - checking and optionally dropping ndb_poly_seq_scheme
- fix in iterator_proxy
2024-01-22 11:18:00 +01:00
Maarten L. Hekkelman
b4d1c4cc04 - renamed exists to contains
- fix compare for ints where item is empty
2024-01-17 16:31:18 +01:00
Maarten L. Hekkelman
22537c0e7e Merge branch 'develop' into trunk 2024-01-09 16:45:46 +01:00
Maarten L. Hekkelman
39c0db8d6a Do not validate on copy category 2024-01-09 16:29:53 +01:00
Maarten L. Hekkelman
9db12761f7 Increase version to reflect changes 2024-01-04 13:14:36 +01:00
Maarten L. Hekkelman
0f8a7c4817 Fix design flaw in category_index (when moving categories) 2024-01-04 13:10:09 +01:00
Maarten L. Hekkelman
47e59a55c5 for compatibility with gcc 9.4 2024-01-03 12:35:22 +01:00
Maarten L. Hekkelman
b3496f4e5d fixes in pdbx validation, compound one letter code 2024-01-03 12:31:42 +01:00
Maarten L. Hekkelman
e866228afd In reconstruct, use embedded compound info 2024-01-03 09:43:13 +01:00
Maarten L. Hekkelman
4aeaa5251e revert change to string_view, not working on macOS 2024-01-03 09:26:32 +01:00
Maarten L. Hekkelman
b36988e64a update changelog 2024-01-03 09:18:08 +01:00
Maarten L. Hekkelman
393aefce8f small optimisation 2024-01-03 08:51:06 +01:00
Maarten L. Hekkelman
227ff1b8be sequence recovery and validation 2024-01-02 16:54:04 +01:00
Maarten L. Hekkelman
82086a93b0 PDBx validation and reconstruction code, take 1 2024-01-02 15:27:26 +01:00
Maarten L. Hekkelman
abd97cc1c9 Merge 2024-01-02 10:52:09 +01:00
Maarten L. Hekkelman
3315fae83e Merge branch 'cif2fasta-develop' into develop-cif2fasta 2024-01-02 10:51:11 +01:00
Maarten L. Hekkelman
d8c3c3f7f0 formatting 2024-01-02 10:44:17 +01:00
Maarten L. Hekkelman
23459879f8 export CIFPP_SHARE_DIR to parent scope in case we're included using sub_directory 2024-01-02 09:43:33 +01:00
Maarten L. Hekkelman
f1ca916d58 Merge remote-tracking branch 'origin/develop' into develop-cif2fasta 2023-12-27 14:10:25 +01:00
Maarten L. Hekkelman
6aae012ae5 Fix url in missing compound message 2023-12-27 09:55:35 +01:00
Maarten L. Hekkelman
516983427a Load inline compound info as restraints, not CCD info 2023-12-20 13:50:27 +01:00
Maarten L. Hekkelman
05d78c92f9 Update changelog 2023-12-20 11:52:49 +01:00
Maarten L. Hekkelman
dc57144472 delete garbage 2023-12-20 11:51:27 +01:00
Maarten L. Hekkelman
dd260ca45e Change order of categories in input and in output
- input matches order in file from now on
- output is ordered by parent/child relations
2023-12-20 11:51:15 +01:00
Maarten L. Hekkelman
3bc2fc4151 add missing get 2023-12-20 11:50:29 +01:00
Maarten L. Hekkelman
6c58eaa7e8 Update changelog 2023-12-13 16:28:37 +01:00
Maarten L. Hekkelman
e1a1c11a01 Add formula_weight to entity in pdb2cif 2023-12-13 16:27:41 +01:00
Maarten L. Hekkelman
95a6b4264d typo in doc 2023-12-12 09:50:04 +01:00
Maarten L. Hekkelman
4782a4e07d Merge branch 'develop' into trunk 2023-12-12 09:31:30 +01:00
Maarten L. Hekkelman
dbc14206dc New readme 2023-12-12 09:21:59 +01:00
Maarten L. Hekkelman
f4296d8858 docs ci 2023-12-12 08:26:44 +01:00
Maarten L. Hekkelman
75c4c2286d readme, docs ci 2023-12-12 08:08:40 +01:00
Maarten L. Hekkelman
b14237e8e6 Not nice 2023-12-05 16:01:20 +01:00
Maarten L. Hekkelman
df3263e4bd test 2023-12-05 15:57:51 +01:00
Maarten L. Hekkelman
ff7b413abf windows gunzip workaround 2023-12-05 15:43:52 +01:00
Maarten L. Hekkelman
07224779e6 find_program works a bit different than expected 2023-12-05 15:26:26 +01:00
Maarten L. Hekkelman
c031a3c24e Moved data file components.cif to rsrc 2023-12-05 11:53:39 +01:00
Maarten L. Hekkelman
1e74f7912c using eigen3 2023-12-05 08:59:10 +01:00
Maarten L. Hekkelman
d91f8d0876 Use fetchcontent for eigen, again 2023-12-04 18:59:03 +01:00
Maarten L. Hekkelman
43d4644fba fix license badge 2023-12-03 15:32:55 +01:00
Maarten L. Hekkelman
61a924d208 attempt to build documentation in github 2023-12-03 15:30:40 +01:00
Maarten L. Hekkelman
2692f2c1bf no update script for macOS
install with sudo in CI
2023-11-29 15:22:59 +01:00
Maarten L. Hekkelman
88b3c87bae fixes for automatic update of data 2023-11-29 14:37:28 +01:00
Maarten L. Hekkelman
7fd7dfd937 Work on WIN32 with or without CCP4 2023-11-29 13:11:13 +01:00
Maarten L. Hekkelman
9a76f02709 using gzip, now correct 2023-11-28 16:45:56 +01:00
Maarten L. Hekkelman
81cc1c73c1 use gzip if found 2023-11-28 16:24:18 +01:00
Maarten L. Hekkelman
eabda8f0f7 Fix downloading CCD file 2023-11-28 16:11:02 +01:00
Maarten L. Hekkelman
cb3917457b cleaning up ci file 2023-11-28 13:58:13 +01:00
Maarten L. Hekkelman
2c4f36a8f9 run CI on macOS 2023-11-28 13:47:53 +01:00
Maarten L. Hekkelman
d458be99bc finally read the documentation on cmake set 2023-11-28 11:41:52 +01:00
Maarten L. Hekkelman
a7f4531767 switched last test to Catch2 2023-11-28 11:14:00 +01:00
Maarten L. Hekkelman
08f5a1ad06 link to zlib::zlib
cache_dir may be undefined
2023-11-28 09:58:44 +01:00
Maarten L. Hekkelman
f2de24c851 for CI: install zlib in windows 2023-11-28 09:15:11 +01:00
Maarten L. Hekkelman
ed1eca8fb5 Build zlib if needed 2023-11-28 08:25:23 +01:00
Maarten L. Hekkelman
f792e6f13d correctly use boost::regex 2023-11-27 17:22:59 +01:00
Maarten L. Hekkelman
b1782b7a97 Merge branch 'with-catch2' into develop 2023-11-27 17:02:04 +01:00
Maarten L. Hekkelman
f3c3966e00 Merge branch 'with-catch2' of s4.hekkelman.net:git-repo/libcifpp into with-catch2 2023-11-27 17:01:43 +01:00
Maarten L. Hekkelman
8a9f72c96b boost regex standalone 2023-11-27 17:01:34 +01:00
Maarten L. Hekkelman
402d3a16ae option takes a default value, not type 2023-11-27 13:01:29 +01:00
Maarten L. Hekkelman
458e228b91 Start using postfix d for debug libraries. Rename cmake config files 2023-11-27 12:47:11 +01:00
Maarten L. Hekkelman
a817f09441 Stricter tests 2023-11-25 11:13:40 +01:00
Maarten L. Hekkelman
413ba85538 CI added 2023-11-23 09:42:12 +01:00
Maarten L. Hekkelman
c1807bf1c3 catch2 work 2023-11-23 09:41:49 +01:00
Maarten L. Hekkelman
09dd65499a Change testing framework to Catch2 2023-11-22 17:06:07 +01:00
Maarten L. Hekkelman
640552abad Remove dependency on libzeep 2023-11-22 14:48:23 +01:00
Maarten L. Hekkelman
faee1848e5 cleaner makefile 2023-11-22 14:35:32 +01:00
Maarten L. Hekkelman
c7a217fea7 cleaner makefile 2023-11-22 14:32:33 +01:00
Maarten L. Hekkelman
e4ae19a625 cleaner makefile 2023-11-22 14:30:21 +01:00
Maarten L. Hekkelman
24fe6ee583 Unused comparison result... tssk 2023-11-22 14:15:51 +01:00
Maarten L. Hekkelman
9cba754eb6 Unused comparison result... tssk 2023-11-22 14:12:45 +01:00
Maarten L. Hekkelman
9e6bb5e844 cleaner makefile 2023-11-22 14:08:06 +01:00
Maarten L. Hekkelman
a74ee255fb More info on missing compounds 2023-11-22 14:07:53 +01:00
Maarten L. Hekkelman
b9fc0c0365 Using FetchContent 2023-11-22 10:26:21 +01:00
Maarten L. Hekkelman
2ce16c74f7 Updating CMakeLists.txt 2023-11-22 09:49:09 +01:00
Maarten L. Hekkelman
6d0ea5c6f9 Drop using CCP4 monomers library
version bump
2023-11-21 14:48:51 +01:00
Maarten L. Hekkelman
b83ef112a9 Fix in structure::change_residue 2023-11-13 10:50:27 +01:00
Maarten L. Hekkelman
dd9110a3a8 Add option to not write data files 2023-11-07 16:48:44 +01:00
Maarten L. Hekkelman
88c23e1b0f Add option to not write data files 2023-11-07 16:38:47 +01:00
Maarten L. Hekkelman
dbe40e3ad6 No longer use mon_lib_list as check for existence of compound 2023-11-06 08:39:17 +01:00
Maarten L. Hekkelman
958d3b05c8 Correctly import Eigen3 2023-11-06 08:21:59 +01:00
Maarten L. Hekkelman
4e7b0baafb version bump 2023-11-02 14:29:05 +01:00
Maarten L. Hekkelman
b3dc38f2d8 update for WIN32 2023-11-02 14:12:17 +01:00
Maarten L. Hekkelman
6044d3dce3 Added cif::cell::get_volume() 2023-10-19 11:58:21 +02:00
Maarten L. Hekkelman
29446f2122 new cif::item constructors
version bump
2023-10-19 09:51:10 +02:00
Maarten L. Hekkelman
abb8673549 Better support for older cmake versions 2023-10-17 15:24:21 +02:00
Maarten L. Hekkelman
ffc8f9dcdf Better support for older cmake versions 2023-10-17 15:22:35 +02:00
Maarten L. Hekkelman
288b2bb720 update changelog 2023-10-17 12:23:59 +02:00
Maarten L. Hekkelman
fb3b7bda68 made data dir options more visible in cmake config
better error reporting in file::load
2023-10-10 13:39:13 +02:00
Maarten L. Hekkelman
6d5efe1cbd Merge branch 'trunk' of github.com:PDB-REDO/libcifpp into trunk 2023-09-26 14:40:44 +02:00
Maarten L. Hekkelman
1ceec22184 Better conversion from string to int 2023-09-26 14:40:38 +02:00
Maarten L. Hekkelman
951ff9b953 Better conversion from string to int 2023-09-26 14:39:26 +02:00
Maarten L. Hekkelman
641f06a7e7 sqrt is not constexpr on macOS 2023-09-22 09:37:15 +02:00
Maarten L. Hekkelman
915ba4ac21 describe download CCD 2023-09-18 10:49:08 +02:00
Maarten L. Hekkelman
824637d83f Update README.md, add link to documentation 2023-09-15 08:56:34 +02:00
Maarten L. Hekkelman
0871406fe3 Eigen dependency removed for clients
Typos fixed
Version bump
2023-09-14 16:03:00 +02:00
Maarten L. Hekkelman
1ad7e47b2e version bump, changelog 2023-09-14 12:53:07 +02:00
Maarten L. Hekkelman
f72a2c69d0 rename doxygen target 2023-09-14 11:14:38 +02:00
Maarten L. Hekkelman
84d9275cb8 update versionstring 2023-09-14 11:12:49 +02:00
Maarten L. Hekkelman
1b7c387c8b reintroduced get_terminal_width as an exported function 2023-09-14 09:52:52 +02:00
Maarten L. Hekkelman
2f1adbd22c clean up 2023-09-14 09:45:13 +02:00
Maarten L. Hekkelman
65031523a6 Merge branch 'trunk' of github.com:PDB-REDO/libcifpp into trunk 2023-09-14 09:15:07 +02:00
Maarten L. Hekkelman
02cc0fa0f6 Using CTest
Create docs/xml directory
2023-09-14 09:13:16 +02:00
Maarten L. Hekkelman
1e1afa023f Using CTest
Create docs/xml directory
2023-09-14 09:12:28 +02:00
Maarten L. Hekkelman
41f343c2cd Create the docs/xml directory in configure step 2023-09-13 17:01:43 +02:00
Maarten L. Hekkelman
a73c4deaca Revert changes in CMakeLists.txt for docs 2023-09-13 16:45:15 +02:00
Maarten L. Hekkelman
01a21aebc4 Fix install rules 2023-09-13 16:16:16 +02:00
Maarten L. Hekkelman
49434043f2 typo 2023-09-13 16:04:30 +02:00
Maarten L. Hekkelman
2e23877912 cleaning up a readthedocs.yaml file 2023-09-13 15:23:35 +02:00
Maarten L. Hekkelman
b737dd7df4 Even more documentation 2023-09-13 14:59:57 +02:00
Maarten L. Hekkelman
137ffaf768 Merge remote-tracking branch 'github/new-docs' into develop 2023-09-13 12:15:13 +02:00
Maarten L. Hekkelman
747c6d30d2 Added better support for std::optional in conditions 2023-09-13 12:14:04 +02:00
Maarten L. Hekkelman
4585968b11 fix point_type 2023-09-13 10:23:31 +02:00
Maarten L. Hekkelman
84af564aee More documentation
Version bump
2023-09-13 10:22:28 +02:00
Maarten L. Hekkelman
86d957675e documented last code 2023-09-12 10:25:18 +02:00
Maarten L. Hekkelman
bc33e608db better docs 2023-09-12 10:04:34 +02:00
Maarten L. Hekkelman
0b5d28338e replacing std::endl where appropriate
more docs
2023-09-12 09:06:45 +02:00
Maarten L. Hekkelman
bdbf22e705 more docs 2023-09-11 15:12:37 +02:00
Maarten L. Hekkelman
160f6016ee more docs 2023-09-11 14:31:13 +02:00
Maarten L. Hekkelman
0855965edf Documenting more
Fixed colouring output manipulators
2023-09-11 12:37:51 +02:00
Maarten L. Hekkelman
fe3cbdab78 refactoring PDB interface 2023-09-11 08:37:18 +02:00
Maarten L. Hekkelman
a8c25f910d new colouring of output 2023-09-08 10:22:08 +02:00
Maarten L. Hekkelman
cb82ec9b01 new colouring of output, first attempt 2023-09-08 09:23:01 +02:00
Maarten L. Hekkelman
e84282cb9a documenting symmetry and text 2023-09-06 17:01:53 +02:00
Maarten L. Hekkelman
8b2e02e1b0 documented row 2023-09-06 14:29:14 +02:00
Maarten L. Hekkelman
1addd2be89 documented point 2023-09-06 13:49:13 +02:00
Maarten L. Hekkelman
2aebfc29ac documenting parser 2023-09-06 11:22:17 +02:00
Maarten L. Hekkelman
26a5410b38 documenting model 2023-09-06 10:59:48 +02:00
Maarten L. Hekkelman
f44e6d0948 backup of documentation 2023-09-05 16:43:24 +02:00
Maarten L. Hekkelman
d496ebf6dd backup of documentation 2023-09-05 15:40:53 +02:00
Maarten L. Hekkelman
1719ed6979 backup of documentation 2023-09-05 15:07:32 +02:00
Maarten L. Hekkelman
821895bb1b backup of documentation 2023-09-05 13:28:09 +02:00
Maarten L. Hekkelman
3f437277d1 accidentally deleted 2023-09-05 11:00:14 +02:00
Maarten L. Hekkelman
39fc56084a documentation backup 2023-09-05 10:42:11 +02:00
Maarten L. Hekkelman
e2fca07fad documenting more 2023-09-04 16:04:41 +02:00
Maarten L. Hekkelman
ec0d75ce95 documenting more 2023-09-04 13:41:21 +02:00
Maarten L. Hekkelman
877a64adaa documenting more 2023-09-04 11:28:33 +02:00
Maarten L. Hekkelman
0fcf9ed5ad documenting more 2023-09-04 09:44:36 +02:00
Maarten L. Hekkelman
c99de817fa documentation 2023-09-01 21:52:46 +02:00
Maarten L. Hekkelman
600c86a185 attempt to get some documentation 2023-09-01 17:12:54 +02:00
Maarten L. Hekkelman
1ae755b0a5 Start adding documentation 2023-08-31 14:31:41 +02:00
Maarten L. Hekkelman
7186057dd3 version bump 2023-08-22 13:45:08 +02:00
Maarten L. Hekkelman
768fec9c58 Merge branch 'develop' of github.com:PDB-REDO/libcifpp into develop 2023-08-22 13:36:52 +02:00
Maarten L. Hekkelman
7197dd877b remove pkgconfig support 2023-08-22 13:36:43 +02:00
Maarten L. Hekkelman
b7aa7eac9f remove pkgconfig support 2023-08-22 13:33:34 +02:00
Maarten L. Hekkelman
818dc2f952 Remove Dart 2023-08-22 13:32:11 +02:00
180 changed files with 51146 additions and 35789 deletions

22
.clang-format Normal file
View 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

View 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

View 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

10
.gitignore vendored
View File

@@ -2,9 +2,17 @@ build/
.vscode/
.vs/
tools/update-libcifpp-data
data/components.cif*
rsrc/components.cif*
CMakeSettings.json
msvc/
src/revision.hpp
test/test-create_sugar_?.cif
Testing/
include/cif++/exports.hpp
docs/api
docs/conf.py
build_ci/
data/components.cif
perf.data*
.cache/

22
.readthedocs.yaml Normal file
View File

@@ -0,0 +1,22 @@
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
apt_packages:
- doxygen
- cmake
jobs:
pre_build:
- cmake -S . -B build -DBUILD_DOCUMENTATION=ON
- cmake --build build --target Doxygen
# Build from the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Explicitly set the version of Python and its requirements
python:
install:
- requirements: docs/requirements.txt

View File

@@ -11,86 +11,91 @@
# 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.1.2 LANGUAGES CXX)
project(
libcifpp
VERSION 9.0.4
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(Dart)
include(GenerateExportHeader)
include(CTest)
include(ExternalProject)
include(FetchContent)
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)
# We do not want to write an export file for all our symbols...
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
# Build documentation?
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)
@@ -98,28 +103,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()
@@ -129,37 +140,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)
@@ -169,130 +152,216 @@ 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)
# First check if <format> is available
find_file(FMT NAME format)
find_package(Eigen3 REQUIRED)
if(FMT EQUAL "FMT-NOTFOUND")
if(NOT (fmt_FOUND OR TARGET fmt))
find_package(fmt REQUIRED)
message(FATAL_ERROR "cifpp: <format> not found and neither was libfmt, compiler too old, you're out of luck")
endif()
endif()
include(FindFilesystem)
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY})
# 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(FindAtomic)
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPATOMIC_LIBRARY})
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)
FetchContent_MakeAvailable(fastfloat)
endif()
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)
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()
# Create a revision file, containing the current git version info
include(VersionString)
write_version_header(${PROJECT_SOURCE_DIR}/src/ LIB_NAME "LibCIFPP")
write_version_header(${CMAKE_CURRENT_SOURCE_DIR}/src/ LIB_NAME "LibCIFPP")
# 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()
# 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/pdb2cif_remark_3.cpp
${PROJECT_SOURCE_DIR}/src/pdb/tls.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/cif2pdb.hpp
${PROJECT_SOURCE_DIR}/include/cif++/pdb/io.hpp
${PROJECT_SOURCE_DIR}/include/cif++/pdb/pdb2cif.hpp
${PROJECT_SOURCE_DIR}/include/cif++/pdb/pdb2cif_remark_3.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 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 PUBLIC FastFloat::fast_float)
endif()
if(fmt_FOUND)
target_link_libraries(cifpp PUBLIC fmt)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
@@ -300,200 +369,205 @@ 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)
set(REQUIRE_FMT ${fmt_FOUND})
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}
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)
# pkgconfig support
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix ${CMAKE_INSTALL_PREFIX})
set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libcifpp.pc.in
${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc.in @ONLY)
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc
INPUT ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc.in)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
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()
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)
if(BUILD_DOCUMENTATION)
add_subdirectory(docs)
endif()

199
README.md
View File

@@ -1,12 +1,38 @@
libcifpp
========
[![github CI](https://github.com/pdb-redo/libcifpp/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/pdb-redo/libcifpp/actions)
[![GitHub License](https://img.shields.io/github/license/pdb-redo/libcifpp)](https://github.com/pdb-redo/libcifpp/LICENSE)
This library contains code to work with mmCIF and 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,59 +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
--------
First you need to download the code:
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:
```bash
git clone https://github.com/PDB-REDO/libcifpp.git --recurse-submodules
```console
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
```

134
changelog
View File

@@ -1,3 +1,133 @@
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
- Removed the subdirectory cif++/pdb, there now is a single
header file pdb.hpp for I/O of legacy PDB files.
Version 5.1.3
- Dropped pkgconfig support
Version 5.1.2
- New version string code
- Added check for Eigen3 in cifppConfig.cmake
@@ -5,8 +135,8 @@ Version 5.1.2
Version 5.1.1
- Added missing include <compare> in symmetry.hpp
- Added empty() to matrix
- Fix for parsing PDB files with a last line that does not end with
a new line character.
- Fix for parsing legacy PDB files with a last line that does
not end with a new line character.
Version 5.1
- New parser, optimised for speed

View File

@@ -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")

View File

@@ -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
View 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})

11
cmake/FindSphinx.cmake Normal file
View File

@@ -0,0 +1,11 @@
#Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)

View File

@@ -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 has 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()

View File

@@ -0,0 +1,15 @@
@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)
if(@REQUIRE_FMT@)
find_dependency(fmt REQUIRED)
endif()
check_required_components(cifpp)

View File

@@ -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
View 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 &registered_main()
{
static version_info_ptr s_main = nullptr;
return s_main;
}
static version_info_ptr &registered_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
View 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;
}

View File

@@ -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) << std::endl;
std::cout << m.str(1).substr(0, 10) << std::endl;
return 0;
}

48
docs/CMakeLists.txt Normal file
View File

@@ -0,0 +1,48 @@
find_package(Doxygen REQUIRED)
find_package(Sphinx REQUIRED)
# Find all the public headers
# get_target_property(CIFPP_PUBLIC_HEADER_DIR libCIFPP INTERFACE_INCLUDE_DIRECTORIES)
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}/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
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
add_custom_command(
OUTPUT ${DOXYGEN_OUTPUT_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR})
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-${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
PATTERN .buildinfo EXCLUDE)

10
docs/Doxyfile.in Normal file
View File

@@ -0,0 +1,10 @@
EXCLUDE_SYMBOLS = cif::detail::*, std*
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
INPUT = @DOXYGEN_INPUT_DIR@

4
docs/_static/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

400
docs/basics.rst Normal file
View File

@@ -0,0 +1,400 @@
Basic usage
===========
This library, *libcifpp*, is a generic *CIF* library with some specific additions to work with *mmCIF* files. The main focus of this library is to make sure that files read or written are valid. That is, they are syntactically valid *and* their content is valid with respect to a CIF dictionary, if such a dictionary is available and specified.
Reading a file is as simple as:
.. code-block:: cpp
#include <cif++.hpp>
cif::file f("/path/to/file.cif");
The file may also be compressed using *gzip* which is detected automatically.
Writing out the file again is also simple, to write out the terminal you can do:
.. code-block:: cpp
std::cout << f;
// or
f.save(std::cout);
// or write a compressed file using gzip compression:
f.save("/tmp/f.cif.gz");
CIF files contain one or more datablocks. To print out the names of all datablocks in our file:
.. code-block:: cpp
for (auto &db : f)
std::cout << db.name() << '\n';
Most often *libcifpp* is used to read in structure files in mmCIF format. These files only contain one datablock and so you can safely use code like this:
.. code-block:: cpp
// get a reference to the first datablock in f
auto &db = f.front();
But if you know the name of the datablock, this also works:
.. code-block:: cpp
// get a reference to the datablock name '1CBS'
auto &db = f["1CBS"];
Now, each datablock contains categories. To print out all their names:
.. code-block:: cpp
for (auto &cat : db)
std::cout << cat.name() << '\n';
But you probably know what category you need to use, so lets fetch it by name:
.. _atom_site-label:
.. code-block:: cpp
// get a reference to the atom_site category in db
auto &atom_site = db["atom_site"];
// and make sure there's some data in it:
assert(not atom_site.empty());
.. note::
Note that we omit the leading underscore in the name of the category here.
Categories contain rows of data and each row has fields or items. Referencing a row in a category results in a :cpp:class:`cif::row_handle` object which you can use to request or manipulate item data.
.. code-block:: cpp
// Get the first row in atom_site
auto rh = atom_site.front();
// Get the label_atom_id value from this row handle as a std::string
std::string atom_id = rh["label_atom_id"].as<std::string>();
// Get the x, y and z coordinates using structered binding
const auto &[x, y, z] = rh.get<float,float,float>("Cartn_x", "Cartn_y", "Cartn_z");
// Assign a new value to the x coordinate or our atom
rh["Cartn_x"] = x + 1;
Querying
--------
Walking over the rows in a category is often not very useful. More often you are interested in specific rows in a category. The function :cpp:func:`cif::category::find` and friends are here to help.
What these functions have in common is that they return data based on a query implemented by :cpp:class:`cif::condition`. These condition objects are built in code using regular C++ syntax. The most basic example of a query is:
.. code-block:: cpp
cif::condition c = cif::key("id") == 1;
Here the condition is that all rows returned should have a value of 1 in there item named *id*. Likewise you can use other data types and even combine those. Oh, and I said we use regular C++ syntax for conditions, so you may as well use other operators to compare values:
.. code-block:: cpp
// condition for C-alpha atoms having an occupancy less than 1.0
cif::condition c = cif::key("occupancy") < 1.0f and cif::key("label_atom_id") == "CA";
Using the namespace *cif::literals* that code becomes a little less verbose:
.. code-block:: cpp
using namespace cif::literals;
cif::condition c = "occupancy"_key < 1.0f and "label_atom_id"_key == "CA";
Conditions can also be combined:
.. code-block:: cpp
cif::condition c = "occupancy"_key < 1.0f and "label_atom_id"_key == "CA";
// extend the condition by requiring the compound ID to be unequal to PRO
c = std::move(c) and "label_comp_id"_key != "PRO";
.. note::
Note the use of std::move here.
Using queries constructed in this way is simple:
.. code-block:: cpp
cif::condition c = ...
auto result = atom_site.find(std::move(c));
// or construct a condition inline:
auto result = atom_site.find("label_atom_id"_key == "CA");
In the example above the result is a range of :cpp:class:`cif::row_handle` objects. Often, using individual field values is more useful:
.. code-block:: cpp
// Requesting a single item:
for (auto id : atom_site.find<std::string>("label_atom_id"_key == "CA", "id"))
std::cout << "ID for CA: " << id << '\n';
// Requesting multiple items:
for (const auto &[id, x, y, z] : atom_site.find<std::string,float,float,float>("label_atom_id"_key == "CA",
"id", "Cartn_x", "Cartn_y", "Cartn_z"))
{
std::cout << "Atom " << id << " is at [" << x << ", " << y << ", " z << "]\n";
}
Returning a complete set if often not required, if you only want to have the first you can use :cpp:func:`cif::category::find_first` as shown here:
.. code-block:: cpp
// return the ID item for the first C-alpha atom
std::string v1 = atom_site.find_first<std::string>("label_atom_id"_key == "CA", "id");
// If you're not sure the row exists, use std::optional
auto v2 = atom_site.find_first<std::optional<std::string>>("label_atom_id"_key == "CA", "id");
if (v2.has_value())
...
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
----------
CIF files can have a dictionary attached. And based on such a dictionary a :cpp:class:`cif::validator` object can be constructed which in turn can be used to validate the content of the file.
A simple case:
.. code-block:: cpp
#include <cif++.hpp>
cif::file f("1cbs.cif.gz");
f.load_dictionary("mmcif_pdbx.dic");
if (not f.is_valid())
std::cout << "This file is not valid\n";
If you want to know why it is not valid, you should set the global variable :cpp:var:`cif::VERBOSE` to something higer than zero. Depending on the value more or less diagnostic output is sent to std::cerr.
In the case above we load a dictionary based on its name. You can of course also load dictionaries based on a specific file, that's a bit more work:
.. code-block:: cpp
std::filesystem::ifstream dictFile("/tmp/my-dictionary.dic");
auto &validator = cif::parse_dictionary("my-dictionary", dictFile);
cif::file f("1cbs.cif.gz");
// assign the validator
f.set_validator(&validator);
// alternatively, load it by name
f.load_dictionary("my-dictionary");
if (not f.is_valid())
std::cout << "This file is not valid\n";
Creating your own dictionary is a lot of work, especially if you are only extending an existing dictionary with a couple of new categories or items. So, what you can do is extend a loaded validator like this (code taken from DSSP):
.. code-block:: cpp
// db is a cif::datablock reference containing an mmCIF file with DSSP annotations
auto &validator = const_cast<cif::validator &>(*db.get_validator());
if (validator.get_validator_for_category("dssp_struct_summary") == nullptr)
{
auto dssp_extension = cif::load_resource("dssp-extension.dic");
if (dssp_extension)
cif::extend_dictionary(validator, *dssp_extension);
}
.. note::
In the example above we're loading the data using :doc:`/resources`. See the documentation on that for more information.
If a validator has been assigned to a file, assignments to items are checked for valid data. So the following code will throw an exception (see: :ref:`_atom_site-label`):
.. code-block:: cpp
auto rh = atom_site.front();
rh["Cartn_x"] = "foo";
Linking
-------
Based on information recorded in dictionary files (see :ref:`Validation`) you can locate linked records in parent or child categories.
To make this example not too complex, lets assume the following example file:
.. code-block:: cif
data_test
loop_
_cat_1.id
_cat_1.name
_cat_1.desc
1 aap Aap
2 noot Noot
3 mies Mies
loop_
_cat_2.id
_cat_2.name
_cat_2.num
_cat_2.desc
1 aap 1 'Een dier'
2 aap 2 'Een andere aap'
3 noot 1 'walnoot bijvoorbeeld'
And we have a dictionary containing the following link definition:
.. code-block:: cif
loop_
_pdbx_item_linked_group_list.parent_category_id
_pdbx_item_linked_group_list.link_group_id
_pdbx_item_linked_group_list.parent_name
_pdbx_item_linked_group_list.child_name
_pdbx_item_linked_group_list.child_category_id
cat_1 1 '_cat_1.name' '_cat_2.name' cat_2
So, there are links between *cat_1* and *cat_2* based on the value in items named *name*. Using this information, we can now locate children and parents:
.. code-block:: cpp
// Assuming the file was loaded in f:
auto &cat1 = f.front()["cat_1"];
auto &cat2 = f.front()["cat_2"];
auto &cat3 = f.front()["cat_3"];
// Loop over all ape's in cat2
for (auto r : cat1.get_children(cat1.find1("name"_key == "aap"), cat2))
std::cout << r.get<std::string>("desc") << '\n';
Updating a value in an item in a parent category will update the corresponding value in all related children:
.. code-block:: cpp
auto r1 = cat1.find1("id"_key == 1);
r1["name"] = "aapje";
auto rs1 = cat2.find("name"_key == "aapje");
assert(rs1.size() == 2);
However, changing a value in a child record will not update the parent. This may result in an invalid file since you may then have a child that has no parent:
.. code-block:: cpp
auto r2 = cat2.find1("id"_key == 3);
r2["name"] = "wim";
assert(f.is_valid() == false);
So you have to fix this yourself by inserting a new item in cat1 with the new value.
.. _splitting-rows:
Another situation is when you change a value in a parent and updating children might introduce a situation where you need to split a child. To give an example, consider this:
.. code-block:: cif
data_test
loop_
_cat_1.id
_cat_1.name
_cat_1.desc
1 aap Aap
2 noot Noot
3 mies Mies
loop_
_cat_2.id
_cat_2.name
_cat_2.num
_cat_2.desc
1 aap 1 'Een dier'
2 aap 2 'Een andere aap'
3 noot 1 'walnoot bijvoorbeeld'
loop_
_cat_3.id
_cat_3.name
_cat_3.num
1 aap 1
2 aap 2
And we have a dictionary containing the following link definition (reversed compared to the previous example):
.. code-block:: cif
loop_
_pdbx_item_linked_group_list.parent_category_id
_pdbx_item_linked_group_list.link_group_id
_pdbx_item_linked_group_list.parent_name
_pdbx_item_linked_group_list.child_name
_pdbx_item_linked_group_list.child_category_id
cat_2 1 '_cat_2.name' '_cat_1.name' cat_1
cat_3 1 '_cat_3.name' '_cat_2.name' cat_2
cat_3 1 '_cat_3.num' '_cat_2.num' cat_2
So *cat3* is a parent of *cat2* and *cat2* is a parent of *cat1*. Now, if you change the *name* value of the first row of *cat3* to 'aapje', the corresponding row in *cat2* is updated as well. But when you update *cat2* you have to update *cat1* too. And simply changing the name field in row 1 of *cat1* is wrong. The default behaviour in libcifpp is to split the record in *cat1* and have a new child with the new name whereas the other remains as is.
The new *cat1* will thus be like:
.. code-block:: cif
loop_
_cat_1.id
_cat_1.name
_cat_1.desc
1 aapje Aap
2 noot Noot
3 mies Mies
5 aap Aap

49
docs/bitsandpieces.rst Normal file
View 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
View 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*.

66
docs/conf.py.in Normal file
View File

@@ -0,0 +1,66 @@
project = '@PROJECT_NAME@'
copyright = '2023, Maarten L. Hekkelman'
author = 'Maarten L. Hekkelman'
release = '@PROJECT_VERSION@'
# -- General configuration ---------------------------------------------------
extensions = [
"breathe",
"exhale",
"myst_parser"
]
breathe_projects = {
"@PROJECT_NAME@": "../build/docs/xml"
}
myst_enable_extensions = [ "colon_fence" ]
breathe_default_project = "@PROJECT_NAME@"
# Setup the exhale extension
exhale_args = {
# These arguments are required
"containmentFolder": "./api",
"rootFileName": "library_root.rst",
"doxygenStripFromPath": "../include/",
# Heavily encouraged optional argument (see docs)
"rootFileTitle": "API Reference",
# Suggested optional arguments
# "createTreeView": True,
# TIP: if using the sphinx-bootstrap-theme, you need
# "treeViewIsBootstrap": True,
"exhaleExecutesDoxygen": False,
"contentsDirectives" : False,
"verboseBuild": False
}
# Tell sphinx what the primary language being documented is.
primary_domain = 'cpp'
# Tell sphinx what the pygments highlight language should be.
highlight_language = 'cpp'
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_theme_options = {
}
cpp_index_common_prefix = [
'cif::'
]

2
docs/genindex.rst Normal file
View File

@@ -0,0 +1,2 @@
Index
=====

46
docs/index.rst Normal file
View File

@@ -0,0 +1,46 @@
Introduction
============
Information on 3D structures of proteins originally came formatted in `PDB <http://www.wwpdb.org/documentation/file-format-content/format33/v3.3.html>`_ files. Although the specification for this format had some real restrictions like a mandatory HEADER and CRYST line, many programs implemented this very poorly often writing out only ATOM records. And users became used to this.
The legacy PDB format has some severe limitations rendering it useless for all but very small protein structures. A new format called `mmCIF <https://mmcif.wwpdb.org/>`_ has been around for decades and now is the default format for the Protein Data Bank.
The software developed in the `PDB-REDO <https://pdb-redo.eu/>`_ project aims at improving 3D models based on original experimental data. For this, the tools need to be able to work with both legacy PDB and mmCIF files. A decision was made to make mmCIF leading internally in all programs and convert legacy PDB directly into mmCIF before processing the data. A robust conversion had to be developed to make this possible since, as noted above, files can come with more or less information making it sometimes needed to do a sequence alignment to find out the exact residue numbers.
And so libcif++ came to life, a library to work with mmCIF files. Work on this library started early 2017 and has developed quite a bit since then. To reduce dependency on other libraries, some functionality was added that is not strictly related to reading and writing mmCIF files but may be useful nonetheless. This is mostly code that is used in 3D calculations and symmetry operations.
Design
------
The main part of the library is a set of classes that work with mmCIF files. They are:
* :cpp:class:`cif::file`
* :cpp:class:`cif::datablock`
* :cpp:class:`cif::category`
The :cpp:class:`cif::file` class encapsulates the contents of a mmCIF file. In such a file there are one or more :cpp:class:`cif::datablock` objects and each datablock contains one or more :cpp:class:`cif::category` objects.
Synopsis
--------
Using *libcifpp* is easy, if you are familiar with modern C++:
.. literalinclude:: ../README.md
:language: c++
:start-after: ```cpp
:end-before: ```
.. toctree::
:maxdepth: 2
:caption: Contents
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
View 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.

5
docs/requirements.in Normal file
View File

@@ -0,0 +1,5 @@
sphinx<5
exhale==0.3.6
myst-parser
breathe
sphinx_rtd_theme==1.3.0

93
docs/requirements.txt Normal file
View File

@@ -0,0 +1,93 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile --output-file=requirements.txt requirements.in
#
alabaster==0.7.13
# via sphinx
babel==2.12.1
# via sphinx
beautifulsoup4==4.12.2
# via exhale
breathe==4.35.0
# via
# -r requirements.in
# exhale
certifi==2023.7.22
# via requests
charset-normalizer==3.2.0
# via requests
docutils==0.17.1
# via
# breathe
# exhale
# myst-parser
# sphinx
# sphinx-rtd-theme
exhale==0.3.6
# via -r requirements.in
idna==3.4
# via requests
imagesize==1.4.1
# via sphinx
jinja2==3.1.2
# via
# myst-parser
# sphinx
lxml==4.9.3
# via exhale
markdown-it-py==2.2.0
# via
# mdit-py-plugins
# myst-parser
markupsafe==2.1.3
# via jinja2
mdit-py-plugins==0.3.5
# via myst-parser
mdurl==0.1.2
# via markdown-it-py
myst-parser==0.18.1
# via -r requirements.in
packaging==23.1
# via sphinx
pygments==2.16.1
# via sphinx
pyyaml==6.0.1
# via myst-parser
requests==2.31.0
# via sphinx
six==1.16.0
# via exhale
snowballstemmer==2.2.0
# via sphinx
soupsieve==2.4.1
# via beautifulsoup4
sphinx==4.5.0
# via
# -r requirements.in
# breathe
# exhale
# myst-parser
# sphinx-rtd-theme
# sphinxcontrib-jquery
sphinx-rtd-theme==1.3.0
# via -r requirements.in
sphinxcontrib-applehelp==1.0.4
# via sphinx
sphinxcontrib-devhelp==1.0.2
# via sphinx
sphinxcontrib-htmlhelp==2.0.1
# via sphinx
sphinxcontrib-jquery==4.1
# via sphinx-rtd-theme
sphinxcontrib-jsmath==1.0.1
# via sphinx
sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
typing-extensions==4.7.1
# via myst-parser
urllib3==2.0.4
# via requests

47
docs/resources.rst Normal file
View File

@@ -0,0 +1,47 @@
Resources
=========
Programs using libcifpp often need access to common data files. E.g. CIF dictionary files, CCP4 monomer restraints files or the CCD data file. In libcifpp these files are called resources. These files are often also based on external sources that are updated on a regular basis.
Resources can be compiled into the executable so that the resulting
application can be made portable to other machines. For this you
need to use `mrc <https://github.com/mhekkel/mrc.git>`_ which only works
on Un*x like systems using the ELF executable format or on MS Windows
But resources may also be located as files on the filesytem at
specific locations. And you can specify your own location for
files (a directory) or even override named resources with your
own data.
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 searched for is:
* Use the resource that was defined by calling :cpp:func:`cif::add_file_resource`
for this name.
* Search the paths specified by :cpp:func:`cif::add_data_directory`, last one
added is searched first
* Search the so-called *CACHE_DIR*. This location is defined
at compile time and based on the installation directory of
libcifpp. Usually it is */var/cache/libcifpp*.
It is in this directory where the cron job for libcifpp will
put the updated files weekly.
* If the *CCP4* environment is available, the
*$ENV{CCP4}/share/libcifpp* is searched.
* If the environment variable *LIBCIFPP_DATA_DIR* is set it
is searched
* The *DATA_DIR* is searched, this is also a variable defined
at compile time, also based on the installation directory
of libcifpp. It usually is */usr/share/libcifpp*
* As a last resort an attempt is made to load the data from
resources compiled by `mrc <https://github.com/mhekkel/mrc.git>`_.

108
docs/symmetry.rst Normal file
View File

@@ -0,0 +1,108 @@
Symmetry & Geometry
===================
Although not really a core *CIF* functionality, when working with *mmCIF* files you often need to work with symmetry information. And symmetry works on points in a certain space and thus geometry calculations are also something you need often. Former versions of *libcifpp* used to use `clipper <http://www.ysbl.york.ac.uk/~cowtan/clipper/doc/index.html>`_ to do many of these calculations, but that introduces a dependency and besides, the way clipper numbers symmetry operations is not completely compatible with the way this is done in the PDB.
Points
------
The most basic type in use is :cpp:type:`cif::point`. It can be thought of as a point in space with three coordinates, but it is also often used as a vector in 3d space. To keep the interface simple there's no separate vector type.
Many functions are available in :ref:`file_cif++_point.hpp` that work on points. There are functions to calculate the :cpp:func:`cif::distance` between two points and also function to calculate dot products, cross products and dihedral angles between sets of points.
Quaternions
-----------
All operations inside *libcifpp* that perform some kind of rotation use :cpp:type:`cif::quaternion`. The reason to use Quaternions is not only that they are cool, they are faster than multiplying with a matrix and the results also suffer less from numerical instability.
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
-------------------
Each basic symmetry operation in the crystallographic world consists of a matrix multiplication followed by a translation. To apply such an operation on a carthesian coordinate you first have to convert the point into a fractional coordinate with respect to the unit cell of the crystal, then apply the matrix and translation operations and then convert the result back into carthesian coordinates. This is all done by the proper routines in *libcifpp*.
Symmetry operations are encoded as a string in *mmCIF* PDBx files. The format is a string with the rotational number followed by an underscore and then the encoded translation in each direction where 5 means no translation. So, the identity operator is ``1_555`` meaning that we have rotational number 1 (which is always the identity rotation, point multiplied with the identity matrix) and a translation of zero in each direction.
To give an idea how this works, here's a piece of code copied from one of the unit tests in *libcifpp*. It takes the *struct_conn* records in a certain PDB file and checks wether the distances in each row correspond to what we can calculate.
.. 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();
// 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,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",
"ptnr2_label_asym_id", "ptnr2_label_seq_id", "ptnr2_auth_seq_id", "ptnr2_label_atom_id", "ptnr2_symmetry",
"pdbx_dist_value"
))
{
// 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");
// 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");
// 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));
// 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));
// The distance between these symmetry atoms should be equal to the distance in the struct_conn record
assert(cif::distance(sa1, sa2) == dist);
// 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);
// 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);
// Distance and symmetry operator string should also be the same
assert(d == dist);
assert(so.string() == symm2);
}

7
examples/CMakeLists.txt Normal file
View File

@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.15)
project(cifpp_example LANGUAGES CXX)
find_package(cifpp REQUIRED)
add_executable(example example.cpp)
target_link_libraries(example cifpp::cifpp)

View File

@@ -8,13 +8,16 @@ namespace fs = std::filesystem;
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cerr << "Usage: example <inputfile>\n";
exit(1);
}
cif::file file = cif::pdb::read(argv[1]);
cif::file file(argv[1]);
if (file.empty())
{
std::cerr << "Empty file" << std::endl;
std::cerr << "Empty file\n";
exit(1);
}
@@ -22,13 +25,13 @@ int main(int argc, char *argv[])
auto &atom_site = db["atom_site"];
auto n = atom_site.find(cif::key("label_atom_id") == "OXT").size();
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;
std::cout << "File contains " << atom_site.size() << " atoms of which " << n << (n == 1 ? " is" : " are") << " OXT\n"
<< "residues with an OXT are:\n";
for (const auto &[asym, comp, seqnr] : atom_site.find<std::string, std::string, int>(
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;

View File

@@ -1,8 +0,0 @@
CXX = c++ -std=c++17
CXXFLAGS = $(shell pkg-config --cflags libcifpp)
LIBS = $(shell pkg-config --libs libcifpp)
all: example
example: example.cpp
$(CXX) -o $@ $? $(CXXFLAGS) $(LIBS)

View File

@@ -37,5 +37,5 @@
#include "cif++/model.hpp"
#include "cif++/pdb/io.hpp"
#include "cif++/pdb.hpp"
#include "cif++/gzio.hpp"

View File

@@ -24,212 +24,259 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Lib for working with structures as contained in mmCIF and PDB files
/** \file atom_type.hpp
*
* This file contains information about all known elements
*/
#pragma once
#include "cif++/exports.hpp"
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <string>
namespace cif
{
/** Atom type as an integer. All known elements are available as a constant. */
enum atom_type : uint8_t
{
Nn = 0, // Unknown
Nn = 0, ///< Unknown
H = 1, // Hydro­gen
He = 2, // He­lium
H = 1, ///< Hydro­gen
He = 2, ///< He­lium
Li = 3, // Lith­ium
Be = 4, // Beryl­lium
B = 5, // Boron
C = 6, // Carbon
N = 7, // Nitro­gen
O = 8, // Oxy­gen
F = 9, // Fluor­ine
Ne = 10, // Neon
Li = 3, ///< Lith­ium
Be = 4, ///< Beryl­lium
B = 5, ///< Boron
C = 6, ///< Carbon
N = 7, ///< Nitro­gen
O = 8, ///< Oxy­gen
F = 9, ///< Fluor­ine
Ne = 10, ///< Neon
Na = 11, // So­dium
Mg = 12, // Magne­sium
Al = 13, // Alumin­ium
Si = 14, // Sili­con
P = 15, // Phos­phorus
S = 16, // Sulfur
Cl = 17, // Chlor­ine
Ar = 18, // Argon
Na = 11, ///< So­dium
Mg = 12, ///< Magne­sium
Al = 13, ///< Alumin­ium
Si = 14, ///< Sili­con
P = 15, ///< Phos­phorus
S = 16, ///< Sulfur
Cl = 17, ///< Chlor­ine
Ar = 18, ///< Argon
K = 19, // Potas­sium
Ca = 20, // Cal­cium
Sc = 21, // Scan­dium
Ti = 22, // Tita­nium
V = 23, // Vana­dium
Cr = 24, // Chrom­ium
Mn = 25, // Manga­nese
Fe = 26, // Iron
Co = 27, // Cobalt
Ni = 28, // Nickel
Cu = 29, // Copper
Zn = 30, // Zinc
Ga = 31, // Gallium
Ge = 32, // Germa­nium
As = 33, // Arsenic
Se = 34, // Sele­nium
Br = 35, // Bromine
Kr = 36, // Kryp­ton
K = 19, ///< Potas­sium
Ca = 20, ///< Cal­cium
Sc = 21, ///< Scan­dium
Ti = 22, ///< Tita­nium
V = 23, ///< Vana­dium
Cr = 24, ///< Chrom­ium
Mn = 25, ///< Manga­nese
Fe = 26, ///< Iron
Co = 27, ///< Cobalt
Ni = 28, ///< Nickel
Cu = 29, ///< Copper
Zn = 30, ///< Zinc
Ga = 31, ///< Gallium
Ge = 32, ///< Germa­nium
As = 33, ///< Arsenic
Se = 34, ///< Sele­nium
Br = 35, ///< Bromine
Kr = 36, ///< Kryp­ton
Rb = 37, // Rubid­ium
Sr = 38, // Stront­ium
Y = 39, // Yttrium
Zr = 40, // Zirco­nium
Nb = 41, // Nio­bium
Mo = 42, // Molyb­denum
Tc = 43, // Tech­netium
Ru = 44, // Ruthe­nium
Rh = 45, // Rho­dium
Pd = 46, // Pallad­ium
Ag = 47, // Silver
Cd = 48, // Cad­mium
In = 49, // Indium
Sn = 50, // Tin
Sb = 51, // Anti­mony
Te = 52, // Tellurium
I = 53, // Iodine
Xe = 54, // Xenon
Cs = 55, // Cae­sium
Ba = 56, // Ba­rium
La = 57, // Lan­thanum
Rb = 37, ///< Rubid­ium
Sr = 38, ///< Stront­ium
Y = 39, ///< Yttrium
Zr = 40, ///< Zirco­nium
Nb = 41, ///< Nio­bium
Mo = 42, ///< Molyb­denum
Tc = 43, ///< Tech­netium
Ru = 44, ///< Ruthe­nium
Rh = 45, ///< Rho­dium
Pd = 46, ///< Pallad­ium
Ag = 47, ///< Silver
Cd = 48, ///< Cad­mium
In = 49, ///< Indium
Sn = 50, ///< Tin
Sb = 51, ///< Anti­mony
Te = 52, ///< Tellurium
I = 53, ///< Iodine
Xe = 54, ///< Xenon
Cs = 55, ///< Cae­sium
Ba = 56, ///< Ba­rium
La = 57, ///< Lan­thanum
Hf = 72, // Haf­nium
Ta = 73, // Tanta­lum
W = 74, // Tung­sten
Re = 75, // Rhe­nium
Os = 76, // Os­mium
Ir = 77, // Iridium
Pt = 78, // Plat­inum
Au = 79, // Gold
Hg = 80, // Mer­cury
Tl = 81, // Thallium
Pb = 82, // Lead
Bi = 83, // Bis­muth
Po = 84, // Polo­nium
At = 85, // Asta­tine
Rn = 86, // Radon
Fr = 87, // Fran­cium
Ra = 88, // Ra­dium
Ac = 89, // Actin­ium
Hf = 72, ///< Haf­nium
Ta = 73, ///< Tanta­lum
W = 74, ///< Tung­sten
Re = 75, ///< Rhe­nium
Os = 76, ///< Os­mium
Ir = 77, ///< Iridium
Pt = 78, ///< Plat­inum
Au = 79, ///< Gold
Hg = 80, ///< Mer­cury
Tl = 81, ///< Thallium
Pb = 82, ///< Lead
Bi = 83, ///< Bis­muth
Po = 84, ///< Polo­nium
At = 85, ///< Asta­tine
Rn = 86, ///< Radon
Fr = 87, ///< Fran­cium
Ra = 88, ///< Ra­dium
Ac = 89, ///< Actin­ium
Rf = 104, // Ruther­fordium
Db = 105, // Dub­nium
Sg = 106, // Sea­borgium
Bh = 107, // Bohr­ium
Hs = 108, // Has­sium
Mt = 109, // Meit­nerium
Ds = 110, // Darm­stadtium
Rg = 111, // Roent­genium
Cn = 112, // Coper­nicium
Nh = 113, // Nihon­ium
Fl = 114, // Flerov­ium
Mc = 115, // Moscov­ium
Lv = 116, // Liver­morium
Ts = 117, // Tenness­ine
Og = 118, // Oga­nesson
Rf = 104, ///< Ruther­fordium
Db = 105, ///< Dub­nium
Sg = 106, ///< Sea­borgium
Bh = 107, ///< Bohr­ium
Hs = 108, ///< Has­sium
Mt = 109, ///< Meit­nerium
Ds = 110, ///< Darm­stadtium
Rg = 111, ///< Roent­genium
Cn = 112, ///< Coper­nicium
Nh = 113, ///< Nihon­ium
Fl = 114, ///< Flerov­ium
Mc = 115, ///< Moscov­ium
Lv = 116, ///< Liver­morium
Ts = 117, ///< Tenness­ine
Og = 118, ///< Oga­nesson
Ce = 58, // Cerium
Pr = 59, // Praseo­dymium
Nd = 60, // Neo­dymium
Pm = 61, // Prome­thium
Sm = 62, // Sama­rium
Eu = 63, // Europ­ium
Gd = 64, // Gadolin­ium
Tb = 65, // Ter­bium
Dy = 66, // Dyspro­sium
Ho = 67, // Hol­mium
Er = 68, // Erbium
Tm = 69, // Thulium
Yb = 70, // Ytter­bium
Lu = 71, // Lute­tium
Ce = 58, ///< Cerium
Pr = 59, ///< Praseo­dymium
Nd = 60, ///< Neo­dymium
Pm = 61, ///< Prome­thium
Sm = 62, ///< Sama­rium
Eu = 63, ///< Europ­ium
Gd = 64, ///< Gadolin­ium
Tb = 65, ///< Ter­bium
Dy = 66, ///< Dyspro­sium
Ho = 67, ///< Hol­mium
Er = 68, ///< Erbium
Tm = 69, ///< Thulium
Yb = 70, ///< Ytter­bium
Lu = 71, ///< Lute­tium
Th = 90, // Thor­ium
Pa = 91, // Protac­tinium
U = 92, // Ura­nium
Np = 93, // Neptu­nium
Pu = 94, // Pluto­nium
Am = 95, // Ameri­cium
Cm = 96, // Curium
Bk = 97, // Berkel­ium
Cf = 98, // Califor­nium
Es = 99, // Einstei­nium
Fm = 100, // Fer­mium
Md = 101, // Mende­levium
No = 102, // Nobel­ium
Lr = 103, // Lawren­cium
Th = 90, ///< Thor­ium
Pa = 91, ///< Protac­tinium
U = 92, ///< Ura­nium
Np = 93, ///< Neptu­nium
Pu = 94, ///< Pluto­nium
Am = 95, ///< Ameri­cium
Cm = 96, ///< Curium
Bk = 97, ///< Berkel­ium
Cf = 98, ///< Califor­nium
Es = 99, ///< Einstei­nium
Fm = 100, ///< Fer­mium
Md = 101, ///< Mende­levium
No = 102, ///< Nobel­ium
Lr = 103, ///< Lawren­cium
D = 119, // Deuterium
D = 119, ///< Deuterium
};
// --------------------------------------------------------------------
// atom_type_info
/// An enum used to select the desired radius for an atom.
/// All values are collected from the wikipedia pages on atom radii
enum class radius_type
{
calculated,
empirical,
calculated, ///< Calculated radius from theoretical models
empirical, ///< Empirically measured covalent radii
/// @deprecated It is a bit unclear where these values came from. So, better not use them
covalent_empirical,
single_bond,
double_bond,
triple_bond,
single_bond, ///< Bond length for a single covalent bond calculated using statistically analysis
double_bond, ///< Bond length for a double covalent bond calculated using statistically analysis
triple_bond, ///< Bond length for a triple covalent bond calculated using statistically analysis
van_der_waals,
van_der_waals, ///< Radius of an imaginary hard sphere representing the distance of closest approach for another atom
type_count
type_count ///< Number of radii
};
constexpr size_t kRadiusTypeCount = static_cast<size_t>(radius_type::type_count);
/// @brief The number of radii per element which can be requested from atom_type_info
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
enum class ionic_radius_type
{
effective, crystal
effective, ///< Based on distance between ions in a crystal structure as determined by X-ray crystallography
crystal ///< Calculated ion radius based on a function of ionic charge and spin
};
/// Requests for an unknown radius value return kNA
constexpr float kNA = std::numeric_limits<float>::quiet_NaN();
/// A struct holding the known information for all elements defined in atom_type
struct atom_type_info
{
/// The type as an atom_type
atom_type type;
/// The official name for this element
std::string name;
/// The official symbol for this element
std::string symbol;
/// The weight of this element
float weight;
/// A flag indicating whether the element is a metal
bool metal;
/// Array containing all known radii for this element. A value of kNA is
/// stored for unknown values
float radii[kRadiusTypeCount];
};
/// Array of atom_type_info struct for each of the defined elements in atom_type
extern CIFPP_EXPORT const atom_type_info kKnownAtoms[];
// --------------------------------------------------------------------
// AtomTypeTraits
/// A traits class to access information for known elements
class atom_type_traits
{
public:
/// Constructor taking an atom_type \a a
atom_type_traits(atom_type a);
/// Constructor based on the element as a string in \a symbol
atom_type_traits(const std::string &symbol);
atom_type type() const { return m_info->type; }
std::string name() const { return m_info->name; }
std::string symbol() const { return m_info->symbol; }
float weight() const { return m_info->weight; }
atom_type type() const { return m_info->type; } ///< Returns the atom_type
std::string name() const { return m_info->name; } ///< Returns the name of the element
std::string symbol() const { return m_info->symbol; } ///< Returns the symbol of the element
float weight() const { return m_info->weight; } ///< Returns the average weight of the element
bool is_metal() const { return m_info->metal; }
bool is_metal() const { return m_info->metal; } ///< Returns true if the element is a metal
/// Return true if the symbol in \a symbol actually exists in the list of known elements in atom_type
static bool is_element(const std::string &symbol);
/// Return true if the symbol in \a symbol exists and is a metal
static bool is_metal(const std::string &symbol);
/// @brief Return the radius for the element, use \a type to select which radius to return
/// @param type The selector for which radius to return
/// @return The requested radius or kNA if not known (or applicable)
float radius(radius_type type = radius_type::single_bond) const
{
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
@@ -247,35 +294,46 @@ class atom_type_traits
/// \brief Return the radius for a charged version of this atom, returns the effective radius by default
///
/// \param charge The charge of the ion
/// \param type The requested ion radius type
/// \return The radius of the ion
float ionic_radius(int charge, ionic_radius_type type = ionic_radius_type::effective) const
{
return type == ionic_radius_type::effective ? effective_ionic_radius(charge) : crystal_ionic_radius(charge);
}
// data type encapsulating the Waasmaier & Kirfel scattering factors
// in a simplified form (only a and b).
// Added the electrion scattering factors as well
/**
* @brief data type encapsulating the scattering factors
* in a simplified form (only a and b).
*/
struct SFData
{
/** @cond */
double a[6], b[6];
/** @endcond */
};
// to get the Cval and Siva values, use this constant as charge:
enum
{
kWKSFVal = -99
};
/// @brief to get the Cval and Siva scattering factor values, use this constant as charge:
static constexpr int kWKSFVal = -99;
/// @brief Return the Waasmaier & Kirfel scattering factor values for the element
///
/// The coefficients from Waasmaier & Kirfel (1995), Acta Cryst. A51, 416-431.
///
/// @param charge The charge for which the structure values should be returned, use kWSKFVal to return the *Cval* and *Siva* values
/// @return The scattering factors as a SFData struct
const SFData &wksf(int charge = 0) const;
/// @brief Return the electron scattering factor values for the element
///
/// @return The scattering factors as a SFData struct
const SFData &elsf() const;
// Clipper doesn't like atoms with charges that do not have a scattering factor. And
// rightly so, but we need to know in advance if this is the case
/// Clipper doesn't like atoms with charges that do not have a scattering factor. And
/// rightly so, but we need to know in advance if this is the case
bool has_sf(int charge) const;
private:
const struct atom_type_info *m_info;
};
} // namespace pdbx
} // namespace cif

File diff suppressed because it is too large Load Diff

View File

@@ -26,17 +26,28 @@
#pragma once
/// \file This file contains the definition for the class compound, encapsulating
/// the information found for compounds in the CCD.
#include "cif++/atom_type.hpp"
#include "cif++/datablock.hpp"
#include "cif++/exports.hpp"
#include "cif++/point.hpp"
#include "cif++/utilities.hpp"
#include <map>
#include <set>
#include <tuple>
#include <vector>
/// \file compound.hpp
/// This file contains the definition for the class compound, encapsulating
/// the information found for compounds in the CCD.
///
/// 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)
///
/// Note that since version 6 the CCP4 monomer library is no longer used.
/// See also :doc:`/compound` for more information.
namespace cif
{
@@ -46,21 +57,47 @@ class compound;
struct compound_atom;
class compound_factory_impl;
/// \brief The bond type as defined in the CCD, possible values taken from the mmcif_pdbx file
/// \brief The bond type or bond order as defined in the CCD, possible values taken from the mmcif_pdbx file
enum class bond_type
{
sing, // 'single bond'
doub, // 'double bond'
trip, // 'triple bond'
quad, // 'quadruple bond'
arom, // 'aromatic bond'
poly, // 'polymeric bond'
delo, // 'delocalized double bond'
pi, // 'pi bond'
sing, ///< single bond
doub, ///< double bond
trip, ///< triple bond
quad, ///< quadruple bond
arom, ///< aromatic bond
poly, ///< polymeric bond
delo, ///< delocalized double bond
pi, ///< pi bond
};
std::string to_string(bond_type bondType);
bond_type from_string(const std::string &bondType);
/// @brief return the string representation of @a bondType
std::string bond_type_to_string(bond_type bondType);
/// @brief return the cif::bond_type for the string representation @a bondType
bond_type parse_bond_type_from_string(const std::string &bondType);
/// \brief The possible stereo config values for a compound_atom.
///
/// As the site https://psiberg.com/r-s-nomenclature/ states:
///
/// > RS nomenclature is currently the preferred system for assigning absolute
/// > configuration to chiral molecules. The letters R and S come from the Latin
/// > words Rectus and Sinister meaning right and left. Molecules that
/// > rotate the plane of polarized light to right are referred to as R isomers
/// > and the molecules that rotate the plane of polarized light to left are
/// > referred to S isomers.
enum class stereo_config_type : uint8_t
{
N = 'N', ///< Not polarizing
R = 'R', ///< Rectus
S = 'S' ///< Sinister
};
/// @brief return the string representation of @a stereo_config
std::string to_string(stereo_config_type stereo_config);
/// @brief return the cif::stereo_config_type for the string representation @a stereo_config
stereo_config_type parse_stereo_config_from_string(const std::string &stereo_config);
/// --------------------------------------------------------------------
/// \brief struct containing information about an atom in a chemical compound.
@@ -68,14 +105,17 @@ bond_type from_string(const std::string &bondType);
struct compound_atom
{
std::string id;
atom_type type_symbol;
int charge = 0;
bool aromatic = false;
bool leaving_atom = false;
bool stereo_config = false;
float x, y, z;
std::string id; ///< Identifier for each atom in the chemical component
atom_type type_symbol; ///< The element type for each atom in the chemical component.
int charge = 0; ///< The formal charge assigned to each atom in the chemical component.
bool aromatic = false; ///< Defines atoms in an aromatic moiety
bool leaving_atom = false; ///< Flags atoms with "leaving" capability
stereo_config_type stereo_config = stereo_config_type::N; ///< Defines the stereochemical configuration of the chiral center atom.
float x, ///< The x component of the coordinates for each atom specified as orthogonal angstroms.
y, ///< The y component of the coordinates for each atom specified as orthogonal angstroms.
z; ///< The z component of the coordinates for each atom specified as orthogonal angstroms.
/// Return the location of the atom as a point
point get_location() const
{
return { x, y, z };
@@ -87,9 +127,10 @@ struct compound_atom
struct compound_bond
{
std::string atom_id[2];
bond_type type;
bool aromatic = false, stereo_config = false;
std::string atom_id[2]; ///< The ID's of the two atoms that define the bond.
bond_type type; ///< The bond order of the chemical bond associated with the specified atoms.
bool aromatic = false, ///< Defines aromatic bonds.
stereo_config = false; ///< Defines stereochemical bonds.
};
/// --------------------------------------------------------------------
@@ -97,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
@@ -105,40 +146,47 @@ class compound
public:
// accessors
std::string id() const { return m_id; }
std::string name() const { return m_name; }
std::string type() const { return m_type; }
std::string group() const { return m_group; }
std::string formula() const { return m_formula; }
float formula_weight() const { return m_formula_weight; }
int formal_charge() const { return m_formal_charge; }
std::string id() const { return m_id; } ///< Return the alphanumeric code for the chemical component.
std::string name() const { return m_name; } ///< Return the name of the chemical component.
std::string type() const { return m_type; } ///< Return the type of monomer.
std::string formula() const { return m_formula; } ///< Return the chemical formula of the chemical component.
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.
const std::vector<compound_atom> &atoms() const { return m_atoms; }
const std::vector<compound_bond> &bonds() const { return m_bonds; }
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
compound_atom get_atom_by_atom_id(const std::string &atom_id) const;
compound_atom get_atom_by_atom_id(const std::string &atom_id) const; ///< Return the atom with id @a atom_id
bool atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const;
float bond_length(const std::string &atomId_1, const std::string &atomId_2) const;
bool atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const; ///< Return true if @a atomId_1 is bonded to @a atomId_2
float bond_length(const std::string &atomId_1, const std::string &atomId_2) const; ///< Return the bond length between @a atomId_1 and @a atomId_2
bool is_water() const
bool is_water() const ///< Return if the compound is actually a water
{
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);
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;
@@ -148,6 +196,8 @@ class compound
// --------------------------------------------------------------------
// Factory class for compound and Link objects
/// Use the compound_factory singleton instance to create compound objects
class compound_factory
{
public:
@@ -159,27 +209,93 @@ class compound_factory
/// flag to true.
static void init(bool useThreadLocalInstanceOnly);
/// Return the singleton instance. If initialized with local threads, this is the
/// instance for the current thread.
static compound_factory &instance();
/// Delete and reset the singleton instance. If initialized with local threads, this is the
/// instance for the current thread.
static void clear();
/// Set the default dictionary file to @a inDictFile
void set_default_dictionary(const std::filesystem::path &inDictFile);
/// 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);
}
bool is_water(std::string_view res_name) const
{
return res_name == "HOH" or res_name == "H2O" or res_name == "WAT";
}
/// \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();
static CIFPP_EXPORT const std::map<std::string, char> kAAMap, kBaseMap;
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();
@@ -192,6 +308,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 cif::file &file)
{
cif::compound_factory::instance().push_dictionary(file);
}
~compound_source()
{
cif::compound_factory::instance().pop_dictionary();
}
};
} // namespace cif

File diff suppressed because it is too large Load Diff

View File

@@ -29,57 +29,209 @@
#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"
*/
namespace cif
{
// --------------------------------------------------------------------
/**
* @brief A datablock is a list of category objects with some additional features
*
*/
class datablock : public std::list<category>
{
public:
datablock() = default;
/**
* @brief Construct a new datablock object with name @a name
*
* @param name The name for the new datablock
*/
datablock(std::string_view name)
: m_name(name)
{
}
/** @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));
}
// --------------------------------------------------------------------
/**
* @brief Return the name of this datablock
*/
const std::string &name() const { return m_name; }
/**
* @brief Set the name of this datablock to @a name
*
* @param name The new name
*/
void set_name(std::string_view name)
{
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
*/
bool is_valid() const;
/**
* @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
*/
category &operator[](std::string_view name);
/**
* @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
*/
const category &operator[](std::string_view name) const;
/**
* @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
*/
category *get(std::string_view name);
/**
* @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
* created.
*/
std::tuple<iterator, bool> emplace(std::string_view name);
std::vector<std::string> get_tag_order() const;
void write(std::ostream &os) const;
void write(std::ostream &os, const std::vector<std::string> &tag_order);
/**
* @brief Get the preferred order of the categories when writing them
*/
[[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
*/
void write(std::ostream &os) const;
/**
* @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> &item_name_order);
/**
* @brief Friend operator<< to write datablock @a db to std::ostream @a os
*/
friend std::ostream &operator<<(std::ostream &os, const datablock &db)
{
db.write(os);
@@ -88,6 +240,9 @@ class datablock : public std::list<category>
// --------------------------------------------------------------------
/**
* @brief Comparison operator to compare two datablock for equal content
*/
bool operator==(const datablock &rhs) const;
private:
@@ -95,4 +250,4 @@ class datablock : public std::list<category>
const validator *m_validator = nullptr;
};
} // namespace cif
} // namespace cif

View File

@@ -28,10 +28,18 @@
#include "cif++/validate.hpp"
/**
* @file validate.hpp
*
* Functions to create and manipulate validator objects
*/
namespace cif
{
validator parse_dictionary(std::string_view name, std::istream &is);
void extend_dictionary(validator &v, std::istream &is);
/**
* @brief Parse the contents of @a is and place content in validator @a v
*/
void parse_dictionary(validator &v, std::istream &is);
} // namespace cif

View File

@@ -28,35 +28,68 @@
#include <list>
#include "cif++/exports.hpp"
#include "cif++/datablock.hpp"
#include "cif++/parser.hpp"
/** \file file.hpp
*
* The file class defined here encapsulates the contents of an mmCIF file
* It is mainly a list of @ref cif::datablock objects
*
* The class file has methods to load dictionaries. These dictionaries are
* loaded from resources (if available) or from disk from several locations.
*
* See the documentation on load_resource() in file: utilities.hpp for more
* information on how data is loaded.
*/
namespace cif
{
// --------------------------------------------------------------------
/**
* @brief The class file is actually a list of datablock objects
*
*/
class file : public std::list<datablock>
{
public:
file() = default;
/**
* @brief Construct a new file object using the data in the file @a p as content
*
* @param p Path to a file containing the data to load
*/
explicit file(const std::filesystem::path &p)
{
load(p);
}
/**
* @brief Construct a new file object using the data in the std::istream @a is
*
* @param is The istream containing the data to load
*/
explicit file(std::istream &is)
{
load(is);
}
explicit file(const char *data, size_t length)
/**
* @brief Construct a new file object with data in the constant string defined
* by @a data and @a length
*
* @param data The pointer to the character string with data to load
* @param length The length of the data
*/
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);
}
@@ -66,58 +99,131 @@ class file : public std::list<datablock>
load(is);
}
file(const file &) = default;
file(file &&) = default;
file &operator=(const file &) = default;
file &operator=(file &&) = default;
void set_validator(const validator *v);
const validator *get_validator() const
/** @cond */
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.
*
* Will throw an exception if there is no validator defined.
*
* If each category was valid, validate_links will also be called.
*
* @return true If the content is valid
* @return false If the content is not valid
*/
bool is_valid() const;
/**
* @brief Validate the content and return true if everything was valid.
*
* Will attempt to load the referenced dictionary if none was specified.
*
* If each category was valid, validate_links will also be called.
*
* @return true If the content is valid
* @return false If the content is not valid
*/
bool is_valid();
/**
* @brief Validate the links for all datablocks contained.
*
* Will throw an exception if no validator was specified.
*
* @return true If all links were valid
* @return false If all links were not valid
*/
bool validate_links() const;
void load_dictionary();
void load_dictionary(std::string_view name);
/**
* @brief Return true if a datablock with the name @a name is part of this file
*/
bool contains(std::string_view name) const;
/**
* @brief return a reference to the first datablock in the file
*/
datablock &front()
{
assert(not empty());
return std::list<datablock>::front();
}
/**
* @brief return a const reference to the first datablock in the file
*/
const datablock &front() const
{
assert(not empty());
return std::list<datablock>::front();
}
/**
* @brief return a reference to the datablock named @a name
*/
datablock &operator[](std::string_view name);
/**
* @brief return a const reference to the datablock named @a name
*/
const datablock &operator[](std::string_view name) const;
/**
* @brief Tries to find a datablock 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 datablock and a boolean indicating whether the datablock
* was created or not.
*
* @param name The name for the datablock
* @return std::tuple<iterator, bool> A tuple containing an iterator pointing
* at the datablock and a boolean indicating whether the datablock was newly
* created.
*/
std::tuple<iterator, bool> emplace(std::string_view name);
/** Load the data from the file specified by @a p */
void load(const std::filesystem::path &p);
/** 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;
/** Save the data to @a is */
void save(std::ostream &os) const;
/**
* @brief Friend operator<< to write file @a f to std::ostream @a os
*/
friend std::ostream &operator<<(std::ostream &os, const file &f)
{
f.save(os);
return os;
}
private:
const validator *m_validator = nullptr;
};
} // namespace cif
} // namespace cif

View File

@@ -26,117 +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.
/** \file format.hpp
*
* 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
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;
};
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
@@ -144,11 +55,20 @@ constexpr auto format(std::string_view fmt, Args... args)
class fill_out_streambuf : public std::streambuf
{
public:
/** @cond */
using base_type = std::streambuf;
using int_type = base_type::int_type;
using char_type = base_type::char_type;
using traits_type = base_type::traits_type;
/** @endcond */
/**
* @brief Construct a new fill out streambuf object based on ostream @a os and a
* width to fill out to of @a width
*/
fill_out_streambuf(std::ostream &os, int width = 80)
: m_os(os)
, m_upstream(os.rdbuf())
@@ -156,11 +76,21 @@ class fill_out_streambuf : public std::streambuf
{
}
/** @cond */
~fill_out_streambuf()
{
m_os.rdbuf(m_upstream);
}
/** @endcond */
/**
* @brief The magic happens here. Write out a couple of spaces when
* the last character to write is a newline to make the line as
* wide as the requested width.
*/
virtual int_type
overflow(int_type ic = traits_type::eof())
{
@@ -191,8 +121,10 @@ class fill_out_streambuf : public std::streambuf
return result;
}
/** Return the upstream streambuf */
std::streambuf *get_upstream() const { return m_upstream; }
/** Return how many lines have been written */
int get_line_count() const { return m_line_count; }
private:

View File

@@ -26,11 +26,16 @@
#pragma once
#include "cif++/exports.hpp"
#include <string>
#include <vector>
/**
* @file forward_decl.hpp
*
* File containing only forward declarations
*
*/
namespace cif
{

View File

@@ -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
@@ -13,28 +39,30 @@
#include <zlib.h>
/// \file gzio.hpp
///
/// Single header file for the implementation of stream classes
/// that can transparently read and write compressed files.
///
/// The gzio::istream_buf class sniffs the input and decides whether to use
/// a decompressor if a signature was recognized.
///
/// There's also an ifstream and ofstream class here that can
/// read and write compressed files. In this case the decission
/// whether to use a compressions/decompression algorithm is
/// based on the extension of the \a filename argument.
// This is a stripped down version of the gxrio library from
// https://github.com/mhekkel/gxrio.git
// Most notably, the lzma support has been removed since getting
// that to work in Windows proved to be too much work.
/** \file gzio.hpp
*
* Single header file for the implementation of stream classes
* that can transparently read and write compressed files.
*
* The gzio::istream_buf class sniffs the input and decides whether to use
* a decompressor if a signature was recognized.
*
* There's also an ifstream and ofstream class here that can
* read and write compressed files. In this case the decission
* whether to use a compressions/decompression algorithm is
* based on the extension of the \a filename argument.
*
* This is a stripped down version of the gxrio library from
* https://github.com/mhekkel/gxrio.git
* Most notably, the lzma support has been removed since getting
* that to work in Windows proved to be too much work.
*/
namespace cif::gzio
{
const size_t kDefaultBufferSize = 256;
/** The default buffer size to use */
const std::size_t kDefaultBufferSize = 256;
// --------------------------------------------------------------------
@@ -50,6 +78,8 @@ template <typename CharT, typename Traits>
class basic_streambuf : public std::basic_streambuf<CharT, Traits>
{
public:
/** @cond */
using char_type = CharT;
using traits_type = Traits;
@@ -77,14 +107,21 @@ class basic_streambuf : public std::basic_streambuf<CharT, Traits>
return *this;
}
/** @endcond */
/** Set the upstream streambuf to @a upstream */
void set_upstream(streambuf_type *upstream)
{
m_upstream = upstream;
}
/** @cond */
virtual basic_streambuf *init(streambuf_type *sb) = 0;
virtual basic_streambuf *close() = 0;
/** @endcond */
protected:
/// \brief The upstream streambuf object, usually this is a basic_filebuf
streambuf_type *m_upstream = nullptr;
@@ -101,10 +138,12 @@ 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:
/** @cond */
static_assert(sizeof(CharT) == 1, "Unfortunately, support for wide characters is not implemented yet.");
using char_type = CharT;
@@ -121,6 +160,8 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
basic_igzip_streambuf(const basic_igzip_streambuf &) = delete;
/** @endcond */
/// \brief Move constructor
basic_igzip_streambuf(basic_igzip_streambuf &&rhs)
: base_type(std::move(rhs))
@@ -141,6 +182,8 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
}
}
/** @cond */
basic_igzip_streambuf &operator=(const basic_igzip_streambuf &) = delete;
/// \brief Move operator= implementation
@@ -171,6 +214,8 @@ class basic_igzip_streambuf : public basic_streambuf<CharT, Traits>
close();
}
/** @endcond */
/// \brief This closes the zlib stream and sets the get pointers to null.
base_type *close() override
{
@@ -298,10 +343,12 @@ 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:
/** @cond */
static_assert(sizeof(CharT) == 1, "Unfortunately, support for wide characters is not implemented yet.");
using char_type = CharT;
@@ -332,6 +379,8 @@ class basic_ogzip_streambuf : public basic_streambuf<CharT, Traits>
basic_ogzip_streambuf &operator=(const basic_ogzip_streambuf &) = delete;
/** @endcond */
/// \brief Move operator=
basic_ogzip_streambuf &operator=(basic_ogzip_streambuf &&rhs)
{
@@ -487,6 +536,8 @@ template <typename CharT, typename Traits>
class basic_istream : public std::basic_istream<CharT, Traits>
{
public:
/** @cond */
using base_type = std::basic_istream<CharT, Traits>;
using traits_type = Traits;
@@ -498,6 +549,8 @@ class basic_istream : public std::basic_istream<CharT, Traits>
using gzip_streambuf_type = basic_igzip_streambuf<char_type, traits_type>;
/** @endcond */
/// \brief Regular move constructor
basic_istream(basic_istream &&rhs)
: base_type(std::move(rhs))
@@ -591,6 +644,8 @@ template <typename CharT, typename Traits>
class basic_ifstream : public basic_istream<CharT, Traits>
{
public:
/** @cond */
using base_type = basic_istream<CharT, Traits>;
using char_type = CharT;
@@ -608,6 +663,8 @@ class basic_ifstream : public basic_istream<CharT, Traits>
close();
}
/** @endcond */
/// \brief Construct an ifstream
/// \param filename Null terminated string specifying the file to open
/// \param mode The mode in which to open the file
@@ -647,10 +704,13 @@ class basic_ifstream : public basic_istream<CharT, Traits>
this->rdbuf(&m_filebuf);
}
/** @cond */
basic_ifstream(const basic_ifstream &) = delete;
basic_ifstream &operator=(const basic_ifstream &) = delete;
/** @endcond */
/// \brief Move version of operator=
basic_ifstream &operator=(basic_ifstream &&rhs)
{
@@ -777,6 +837,8 @@ template <typename CharT, typename Traits>
class basic_ostream : public std::basic_ostream<CharT, Traits>
{
public:
/** @cond */
using base_type = std::basic_ostream<CharT, Traits>;
using char_type = CharT;
@@ -785,6 +847,8 @@ class basic_ostream : public std::basic_ostream<CharT, Traits>
using z_streambuf_type = basic_streambuf<char_type, traits_type>;
using upstreambuf_type = std::basic_streambuf<char_type, traits_type>;
/** @endcond */
/// \brief Regular move constructor
basic_ostream(basic_ostream &&rhs)
: base_type(std::move(rhs))
@@ -846,6 +910,8 @@ template <typename CharT, typename Traits>
class basic_ofstream : public basic_ostream<CharT, Traits>
{
public:
/** @cond */
using base_type = basic_ostream<CharT, Traits>;
using char_type = CharT;
@@ -861,6 +927,8 @@ class basic_ofstream : public basic_ostream<CharT, Traits>
close();
}
/** @endcond */
/// \brief Construct an ofstream
/// \param filename Null terminated string specifying the file to open
/// \param mode The mode in which to open the file
@@ -899,10 +967,14 @@ class basic_ofstream : public basic_ostream<CharT, Traits>
this->rdbuf(&m_filebuf);
}
/** @cond */
basic_ofstream(const basic_ofstream &) = delete;
basic_ofstream &operator=(const basic_ofstream &) = delete;
/** @endcond */
/// \brief Move operator=
basic_ofstream &operator=(basic_ofstream &&rhs)
{
@@ -1032,11 +1104,13 @@ class basic_ofstream : public basic_ostream<CharT, Traits>
// --------------------------------------------------------------------
/// \brief Convenience typedefs
/// \brief Convenience typedef for a regular istream
using istream = basic_istream<char, std::char_traits<char>>;
/// \brief Convenience typedef for a file ifstream
using ifstream = basic_ifstream<char, std::char_traits<char>>;
// using ostream = basic_ostream<char, std::char_traits<char>>;
/// \brief Convenience typedef for a file ofstream
using ofstream = basic_ofstream<char, std::char_traits<char>>;
} // namespace gzio

View File

@@ -41,22 +41,61 @@
#include <optional>
#include <utility>
/// \file item.hpp
/// This file contains the declaration of item but also the item_value and item_handle
/// These handle the storage of and access to the data for a single data field.
/** \file item.hpp
*
* This file contains the declaration of item but also the item_value and item_handle
* These handle the storage of and access to the data for a single data item.
*/
namespace cif
{
// --------------------------------------------------------------------
/// \brief item is a transient class that is used to pass data into rows
/// but it also takes care of formatting data.
/** @brief item is a transient class that is used to pass data into rows
* but it also takes care of formatting data.
*
*
*
* The class cif::item is often used implicitly when creating a row in a category
* using the emplace function.
*
* @code{.cpp}
* cif::category cat("my-cat");
* cat.emplace({
* { "item-1", 1 }, // <- stores an item with value 1
* { "item-2", 1.0, 2 }, // <- stores an item with value 1.00
* { "item-3", std::optional<int>() }, // <- stores an item with value ?
* { "item-4", std::make_optional<int>(42) }, // <- stores an item with value 42
* { "item-5" } // <- stores an item with value .
* });
*
* std::cout << cat << '\n';
* @endcode
*
* Will result in:
*
* @code{.txt}
* _my-cat.item-1 1
* _my-cat.item-2 1.00
* _my-cat.item-3 ?
* _my-cat.item-4 42
* _my-cat.item-5 .
* @endcode
*/
class item
{
public:
/// \brief Default constructor, empty item
item() = default;
/// \brief constructor for an item with name \a name and as
/// content the character '.', i.e. an inapplicable value.
item(std::string_view name)
: m_name(name)
, m_value({ '.' })
{
}
/// \brief constructor for an item with name \a name and as
/// content a single character string with content \a value
item(std::string_view name, char value)
@@ -66,7 +105,7 @@ class item
}
/// \brief constructor for an item with name \a name and as
/// content a the formatted floating point value \a value with
/// content the formatted floating point value \a value with
/// precision \a precision
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
item(std::string_view name, const T &value, int precision)
@@ -78,11 +117,9 @@ class item
char buffer[32];
auto r = to_chars(buffer, buffer + sizeof(buffer) - 1, value, chars_format::fixed, precision);
if (r.ec != std::errc())
if ((bool)r.ec)
throw std::runtime_error("Could not format number");
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value.assign(buffer, r.ptr - buffer);
}
@@ -99,34 +136,30 @@ class item
char buffer[32];
auto r = to_chars(buffer, buffer + sizeof(buffer) - 1, value, chars_format::general);
if (r.ec != std::errc())
if ((bool)r.ec)
throw std::runtime_error("Could not format number");
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value.assign(buffer, r.ptr - buffer);
}
/// \brief constructor for an item with name \a name and as
/// content a the formatted integral value \a value
template <typename T, std::enable_if_t<std::is_integral_v<T> and not std::is_same_v<T,bool>, int> = 0>
/// content the formatted integral value \a value
template <typename T, std::enable_if_t<std::is_integral_v<T> and not std::is_same_v<T, bool>, int> = 0>
item(const std::string_view name, const T &value)
: m_name(name)
{
char buffer[32];
auto r = std::to_chars(buffer, buffer + sizeof(buffer) - 1, value);
if (r.ec != std::errc())
if ((bool)r.ec)
throw std::runtime_error("Could not format number");
assert(r.ptr >= buffer and r.ptr < buffer + sizeof(buffer));
*r.ptr = 0;
m_value.assign(buffer, r.ptr - buffer);
}
/// \brief constructor for an item with name \a name and as
/// content a the formatted boolean value \a value
template <typename T, std::enable_if_t<std::is_same_v<T,bool>, int> = 0>
/// content the formatted boolean value \a value
template <typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
item(const std::string_view name, const T &value)
: m_name(name)
{
@@ -135,22 +168,62 @@ class item
/// \brief constructor for an item with name \a name and as
/// content value \a value
item(const std::string_view name, const std::string_view value)
item(const std::string_view name, std::string_view value)
: m_name(name)
, m_value(value)
{
}
/// \brief constructor for an item with name \a name and as
/// content value \a value
template <typename T, std::enable_if_t<std::is_same_v<T, std::string>, int> = 0>
item(const std::string_view name, T &&value)
: m_name(name)
, m_value(std::move(value))
{
}
/// \brief constructor for an item with name \a name and as
/// content the optional value \a value
template <typename T>
item(const std::string_view name, const std::optional<T> &value)
: m_name(name)
{
if (value.has_value())
{
item tmp(name, *value);
std::swap(tmp.m_value, m_value);
}
else
m_value.assign("?");
}
/// \brief constructor for an item with name \a name and as
/// content the formatted floating point value \a value with
/// precision \a precision
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
item(std::string_view name, const std::optional<T> &value, int precision)
: m_name(name)
{
if (value.has_value())
{
item tmp(name, *value, precision);
std::swap(tmp.m_value, m_value);
}
else
m_value.assign("?");
}
/** @cond */
item(const item &rhs) = default;
item(item &&rhs) noexcept = default;
item &operator=(const item &rhs) = default;
item &operator=(item &&rhs) noexcept = default;
/** @endcond */
std::string_view name() const { return m_name; }
std::string_view value() const { return m_value; }
std::string_view name() const { return m_name; } ///< Return the name of the item
std::string_view value() const & { return m_value; } ///< Return the value of the item
std::string value() const && { return std::move(m_value); } ///< Return the value of the item
/// \brief replace the content of the stored value with \a v
void value(std::string_view v) { m_value = v; }
@@ -158,23 +231,27 @@ class item
/// \brief empty means either null or unknown
bool empty() const { return m_value.empty(); }
/// \brief returns true if the field contains '.'
/// \brief returns true if the item contains '.'
bool is_null() const { return m_value == "."; }
/// \brief returns true if the field contains '?'
/// \brief returns true if the item contains '?'
bool is_unknown() const { return m_value == "?"; }
/// \brief the length of the value string
size_t length() const { return m_value.length(); }
std::size_t length() const { return m_value.length(); }
/// \brief support for structured binding
template<size_t N>
template <std::size_t N>
decltype(auto) get() const
{
if constexpr (N == 0) return name();
else if constexpr (N == 1) return value();
if constexpr (N == 0)
return name();
else if constexpr (N == 1)
return value();
}
auto operator<=>(const item &rhs) const = default;
private:
std::string_view m_name;
std::string m_value;
@@ -190,7 +267,9 @@ class item
struct item_value
{
/** @cond */
item_value() = default;
/** @endcond */
/// \brief constructor
item_value(std::string_view text)
@@ -210,19 +289,17 @@ struct item_value
}
}
item_value(item_value &&rhs)
/** @cond */
item_value(item_value &&rhs) noexcept
: m_length(std::exchange(rhs.m_length, 0))
, m_storage(std::exchange(rhs.m_storage, 0))
{
}
item_value &operator=(item_value &&rhs)
item_value &operator=(item_value &&rhs) noexcept
{
if (this != &rhs)
{
m_length = std::exchange(rhs.m_length, m_length);
m_storage = std::exchange(rhs.m_storage, m_storage);
}
std::swap(m_length, rhs.m_length);
std::swap(m_storage, rhs.m_storage);
return *this;
}
@@ -236,24 +313,29 @@ struct item_value
item_value(const item_value &) = delete;
item_value &operator=(const item_value &) = delete;
/** @endcond */
/** operator bool, allows easy checking for empty items */
explicit operator bool() const
{
return m_length != 0;
}
size_t m_length = 0;
std::size_t m_length = 0; ///< Length of the data
union
{
char m_local_data[8];
char *m_data;
uint64_t m_storage;
char m_local_data[8]; ///< Storage area for small strings (strings smaller than kBufferSize)
char *m_data; ///< Pointer to a string stored in the heap
uint64_t m_storage; ///< Alternative storage of the data, used in move operations
};
static constexpr size_t kBufferSize = sizeof(m_local_data);
/** The maximum length of locally stored strings */
static constexpr std::size_t kBufferSize = sizeof(m_local_data);
// By using std::string_view instead of c_str we obain a
// nice performance gain since we avoid many calls to strlen.
/** Return the content of the item as a std::string_view */
constexpr inline std::string_view text() const
{
return { m_length >= kBufferSize ? m_data : m_local_data, m_length };
@@ -268,18 +350,68 @@ struct item_value
struct item_handle
{
public:
/** @cond */
// conversion helper class
template <typename T, typename = void>
struct item_value_as;
/** @endcond */
/**
* @brief Assign value @a value to the item referenced
*
* @tparam T Type of the value
* @param value The value
* @return reference to this item_handle
*/
template <typename T>
item_handle &operator=(const T &value)
{
item v{ "", value };
assign_value(v);
assign_value(item{ "", value }.value());
return *this;
}
/**
* @brief Assign value @a value to the item referenced
*
* @tparam T Type of the value
* @param value The value
* @return reference to this item_handle
*/
template <typename T>
item_handle &operator=(T &&value)
{
assign_value(item{ "", std::forward<T>(value) }.value());
return *this;
}
/**
* @brief Assign value @a value to the item referenced
*
* @tparam T Type of the value
* @param value The value
* @return reference to this item_handle
*/
template <std::size_t N>
item_handle &operator=(const char (&value)[N])
{
assign_value(item{ "", std::move(value) }.value());
return *this;
}
/**
* @brief A method with a variable number of arguments that will be concatenated and
* assigned as a string. Use it like this:
*
* @code{.cpp}
* cif::item_handle ih;
* is.os("The result of ", 1, " * ", 42, " is of course ", 42);
* @endcode
*
* And the content will then be `The result of 1 * 42 is of course 42`.
*
* @tparam Ts Types of the parameters
* @param v The parameters to concatenate
*/
template <typename... Ts>
void os(const Ts &...v)
{
@@ -288,8 +420,10 @@ struct item_handle
this->operator=(ss.str());
}
/** Swap contents of this and @a b */
void swap(item_handle &b);
/** Return the contents of this item as type @tparam T */
template <typename T = std::string>
auto as() const -> T
{
@@ -297,18 +431,36 @@ struct item_handle
return item_value_as<value_type>::convert(*this);
}
/** Return the contents of this item as type @tparam T or, if not
* set, use @a dv as the default value.
*/
template <typename T>
auto value_or(const T &dv) const
{
return empty() ? dv : this->as<T>();
}
/**
* @brief Compare the contents of this item with value @a value
* optionally ignoring character case, if @a icase is true.
* Returns 0 if both are equal, -1 if this sorts before @a value
* and 1 if this sorts after @a value
*
* @tparam T Type of the value @a value
* @param value The value to compare with
* @param icase Flag indicating if we should compare character case sensitive
* @return -1, 0 or 1
*/
template <typename T>
int compare(const T &value, bool icase = true) const
{
return item_value_as<T>::compare(*this, value, icase);
}
/**
* @brief Compare the value contained with the value @a value and
* return true if both are equal.
*/
template <typename T>
bool operator==(const T &value) const
{
@@ -317,45 +469,64 @@ struct item_handle
}
// We may not have C++20 yet...
/**
* @brief Compare the value contained with the value @a value and
* return true if both are not equal.
*/
template <typename T>
bool operator!=(const T &value) const
{
return not operator==(value);
}
// empty means either null or unknown
/**
* @brief Returns true if the content string is empty or
* only contains '.' meaning null or '?' meaning unknown
* in a mmCIF context
*/
bool empty() const
{
auto txt = text();
return txt.empty() or (txt.length() == 1 and (txt.front() == '.' or txt.front() == '?'));
}
/** Easy way to test for an empty item */
explicit operator bool() const { return not empty(); }
// is_null means the field contains '.'
/// is_null return true if the item contains '.'
bool is_null() const
{
auto txt = text();
return txt.length() == 1 and txt.front() == '.';
}
// is_unknown means the field contains '?'
/// is_unknown returns true if the item contains '?'
bool is_unknown() const
{
auto txt = text();
return txt.length() == 1 and txt.front() == '?';
}
/** Return a std::string_view for the contents */
std::string_view text() const;
item_handle(uint16_t column, row_handle &row)
: m_column(column)
/**
* @brief Construct a new item handle object
*
* @param item Item index
* @param row Reference to the row
*/
item_handle(uint16_t item, row_handle &row)
: m_item_ix(item)
, m_row_handle(row)
{
}
static CIFPP_EXPORT const item_handle s_null_item;
/** A variable holding an empty item */
CIFPP_EXPORT static const item_handle s_null_item;
/** friend to swap two item handles */
friend void swap(item_handle a, item_handle b)
{
a.swap(b);
@@ -364,14 +535,15 @@ struct item_handle
private:
item_handle();
uint16_t m_column;
uint16_t m_item_ix;
row_handle &m_row_handle;
void assign_value(const item &value);
void assign_value(std::string_view value);
};
// So sad that older gcc implementations of from_chars did not support floats yet...
/** @cond */
template <typename T>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> and not std::is_same_v<T, bool>>>
{
@@ -385,17 +557,24 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
{
auto txt = ref.text();
std::from_chars_result r = selected_charconv<value_type>::from_chars(txt.data(), txt.data() + txt.size(), result);
auto b = txt.data();
auto e = txt.data() + txt.size();
if (r.ec != std::errc())
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1])) //
? from_chars(b + 1, e, result)
: from_chars(b, e, result);
if ((bool)r.ec or r.ptr != e)
{
result = {};
if (cif::VERBOSE)
{
if (r.ec == std::errc::invalid_argument)
std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number" << std::endl;
std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number\n";
else if (r.ec == std::errc::result_out_of_range)
std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small" << std::endl;
std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small\n";
else
std::cerr << "Not a valid number " << std::quoted(txt) << '\n';
}
}
}
@@ -409,25 +588,34 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
auto txt = ref.text();
if (txt.empty())
if (ref.empty())
result = 1;
else
{
value_type v = {};
std::from_chars_result r = selected_charconv<value_type>::from_chars(txt.data(), txt.data() + txt.size(), v);
auto b = txt.data();
auto e = txt.data() + txt.size();
if (r.ec != std::errc())
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1]))
? from_chars(b + 1, e, v)
: from_chars(b, e, v);
if ((bool)r.ec or r.ptr != e)
{
if (cif::VERBOSE)
{
if (r.ec == std::errc::invalid_argument)
std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number" << std::endl;
std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number\n";
else if (r.ec == std::errc::result_out_of_range)
std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small" << std::endl;
std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small\n";
else
std::cerr << "Not a valid number " << std::quoted(txt) << '\n';
}
result = 1;
}
else if (std::abs(v - value) <= std::numeric_limits<value_type>::epsilon())
result = 0;
else if (v < value)
result = -1;
else if (v > value)
@@ -482,7 +670,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, bool>>>
}
};
template <size_t N>
template <std::size_t N>
struct item_handle::item_value_as<char[N]>
{
static std::string convert(const item_handle &ref)
@@ -546,22 +734,33 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::str
}
};
/** @endcond */
} // namespace cif
namespace std
{
template<> struct tuple_size<::cif::item>
: public std::integral_constant<std::size_t, 2> {};
/** @cond */
template<> struct tuple_element<0, ::cif::item>
template <>
struct tuple_size<::cif::item>
: public std::integral_constant<std::size_t, 2>
{
};
template <>
struct tuple_element<0, ::cif::item>
{
using type = decltype(std::declval<::cif::item>().name());
};
template<> struct tuple_element<1, ::cif::item>
template <>
struct tuple_element<1, ::cif::item>
{
using type = decltype(std::declval<::cif::item>().value());
};
}
/** @endcond */
} // namespace std

View File

@@ -30,22 +30,46 @@
#include <array>
/**
* @file iterator.hpp
*
* This file contains several implementations of generic iterators.
*
* Using partial specialization we can have implementation for
* iterators that return row_handles, a single value or tuples of
* multiple values.
*
*/
namespace cif
{
// --------------------------------------------------------------------
/**
* @brief Implementation of an iterator that can return
* multiple values in a tuple. Of course, that tuple can
* then be used in structured binding to receive the values
* in a for loop e.g.
*
* @tparam Category The category for this iterator
* @tparam Ts The types this iterator can be dereferenced to
*/
template <typename Category, typename... Ts>
class iterator_impl
{
public:
/** @cond */
template <typename, typename...>
friend class iterator_impl;
friend class category;
/** @endcond */
static constexpr size_t N = sizeof...(Ts);
/** variable that contains the number of elements in the tuple */
static constexpr std::size_t N = sizeof...(Ts);
/** @cond */
using category_type = std::remove_cv_t<Category>;
using row_type = std::conditional_t<std::is_const_v<Category>, const row, row>;
@@ -60,41 +84,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;
}
@@ -112,18 +133,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>());
@@ -152,29 +173,32 @@ class iterator_impl
return m_current != rhs.m_current;
}
/** @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 as<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;
};
template<typename Category>
/**
* @brief Implementation of an iterator that returns
* only row_handles
*
* @tparam Category The category for this iterator
*/
template <typename Category>
class iterator_impl<Category>
{
public:
/** @cond */
template <typename, typename...>
friend class iterator_impl;
@@ -185,37 +209,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;
}
@@ -223,7 +244,7 @@ class iterator_impl<Category>
reference operator*()
{
return {*m_category, *m_current};
return m_current;
}
pointer operator->()
@@ -233,18 +254,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;
}
@@ -271,16 +292,25 @@ class iterator_impl<Category>
return m_current != rhs.m_current;
}
/** @endcond */
private:
category_type *m_category = nullptr;
row_type *m_current = nullptr;
row_handle m_current;
};
/**
* @brief Implementation of an iterator that can return
* a single value.
*
* @tparam Category The category for this iterator
* @tparam T The type this iterator can be dereferenced to
*/
template<typename Category, typename T>
template <typename Category, typename T>
class iterator_impl<Category, T>
{
public:
/** @cond */
template <typename, typename...>
friend class iterator_impl;
@@ -298,41 +328,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;
}
@@ -350,18 +377,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();
@@ -390,32 +417,40 @@ class iterator_impl<Category, T>
return m_current != rhs.m_current;
}
/** @endcond */
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 as<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;
};
// --------------------------------------------------------------------
// iterator proxy
/**
* @brief An iterator_proxy is used as a result type for methods that
* return a range of values you want to iterate over.
*
* E.g. the class cif::category contains the method cif::category::rows()
* that returns an iterator_proxy that allows you to iterate over
* all the rows in the category.
*
* @tparam Category The category for the iterators
* @tparam Ts The types the iterators return. See class: iterator
*/
template <typename Category, typename... Ts>
class iterator_proxy
{
public:
static constexpr const size_t N = sizeof...(Ts);
/** @cond */
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>;
@@ -423,51 +458,61 @@ 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);
iterator_proxy(const iterator_proxy &) = delete;
iterator_proxy &operator=(const iterator_proxy &) = delete;
/** @endcond */
iterator begin() const { return iterator(m_begin, m_column_ix); }
iterator end() const { return iterator(m_end, m_column_ix); }
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; }
explicit operator bool() const { return not empty(); }
size_t size() const { return std::distance(begin(), end()); }
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
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())); }
category_type &category() const { return *m_category; }
category_type &category() const { return *m_category; } ///< Return the category the iterator belong to
/** swap */
void swap(iterator_proxy &rhs)
{
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;
};
// --------------------------------------------------------------------
// conditional iterator proxy
/**
* @brief A conditional iterator proxy is similar to an iterator_proxy
* in that it can be used to return a range of rows you can iterate over.
* In the case of an conditional_iterator_proxy a cif::condition is used
* to filter out only those rows that match the condition.
*
* @tparam CategoryType The category the iterators belong to
* @tparam Ts The types to which the iterators can be dereferenced
*/
template <typename CategoryType, typename... Ts>
class conditional_iterator_proxy
{
public:
static constexpr const size_t N = sizeof...(Ts);
/** @cond */
static constexpr const std::size_t N = sizeof...(Ts);
using category_type = std::remove_cv_t<CategoryType>;
@@ -493,22 +538,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;
}
@@ -522,18 +568,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;
};
@@ -549,20 +599,21 @@ class conditional_iterator_proxy
conditional_iterator_proxy(const conditional_iterator_proxy &) = delete;
conditional_iterator_proxy &operator=(const conditional_iterator_proxy &) = delete;
iterator begin() const;
iterator end() const;
/** @endcond */
bool empty() const;
iterator begin() const; ///< Return the iterator pointing to the first row
iterator end() const; ///< Return the iterator pointing past the last row
explicit operator bool() const { return not empty(); }
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
std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
size_t size() const { return std::distance(begin(), end()); }
row_handle front() { return *begin(); }
row_handle front() { return *begin(); } ///< Return reference to the first row
// row_handle back() { return *begin(); }
CategoryType &category() const { return *m_cat; }
CategoryType &category() const { return *m_cat; } ///< Category the iterators belong to
/** swap */
void swap(conditional_iterator_proxy &rhs);
private:
@@ -574,27 +625,28 @@ 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);
}
// --------------------------------------------------------------------
@@ -602,11 +654,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())
m_begin = m_end;
}
template <typename Category, typename... Ts>
@@ -629,15 +683,20 @@ 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");
m_condition.prepare(cat);
if (m_condition)
{
m_condition.prepare(cat);
while (mCBegin != mCEnd and not m_condition(*mCBegin))
++mCBegin;
while (mCBegin != mCEnd and not m_condition(*mCBegin))
++mCBegin;
}
else
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>
@@ -675,4 +734,6 @@ void conditional_iterator_proxy<Category, Ts...>::swap(conditional_iterator_prox
std::swap(mCix, rhs.mCix);
}
/** @endcond */
} // namespace cif

View File

@@ -35,33 +35,51 @@
#include <type_traits>
#include <vector>
/**
* @file matrix.hpp
*
* Some basic matrix operations and classes to hold matrices.
*
* We're using expression templates for optimal performance.
*
*/
namespace cif
{
// --------------------------------------------------------------------
// We're using expression templates here
/**
* @brief Base for the matrix expression templates
* This all uses the Curiously recurring template pattern
*
* @tparam M The type of the derived class
*/
template <typename M>
class matrix_expression
{
public:
constexpr size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); }
constexpr size_t dim_n() const { return static_cast<const M &>(*this).dim_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; }
constexpr bool empty() const { return dim_m() == 0 or dim_n() == 0; } ///< Convenient way to test for empty matrices
constexpr auto &operator()(size_t i, size_t j)
/** Return a reference to element [ @a i, @a j ] */
constexpr auto &operator()(std::size_t i, std::size_t j)
{
return static_cast<M &>(*this).operator()(i, j);
}
constexpr auto operator()(size_t i, size_t j) const
/** Return the value of element [ @a i, @a j ] */
constexpr auto operator()(std::size_t i, std::size_t j) const
{
return static_cast<const M &>(*this).operator()(i, j);
}
void swap_row(size_t r1, size_t r2)
/** Swap the contents of rows @a r1 and @a 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);
@@ -69,9 +87,10 @@ class matrix_expression
}
}
void swap_col(size_t c1, size_t c2)
/** Swap the contents of columns @a c1 and @a 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);
@@ -79,15 +98,16 @@ class matrix_expression
}
}
/** write the matrix @a m to std::ostream @a os */
friend std::ostream &operator<<(std::ostream &os, const matrix_expression &m)
{
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())
@@ -107,29 +127,51 @@ class matrix_expression
};
// --------------------------------------------------------------------
// 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
/**
* @brief Storage class implementation of matrix_expression.
*
* @tparam F The type of the stored values
*
* 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 = float>
class matrix : public matrix_expression<matrix<F>>
{
public:
/** The value type */
using value_type = F;
/**
* @brief Copy construct a new matrix object using @a m
*
* @tparam M2 Type of @a m
* @param m The matrix expression to copy values from
*/
template <typename M2>
matrix(const matrix_expression<M2> &m)
: m_m(m.dim_m())
, 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);
}
}
matrix(size_t m, size_t n, value_type v = 0)
/**
* @brief Construct a new matrix object with dimension @a m and @a n
* setting the values to @a v
*
* @param m Requested dimension M
* @param n Requested dimension N
* @param v Value to store in each element
*/
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)
@@ -137,23 +179,27 @@ class matrix : public matrix_expression<matrix<F>>
std::fill(m_data.begin(), m_data.end(), v);
}
/** @cond */
matrix() = default;
matrix(matrix &&m) = default;
matrix(const matrix &m) = default;
matrix &operator=(matrix &&m) = default;
matrix &operator=(const matrix &m) = default;
/** @endcond */
constexpr size_t dim_m() const { return m_m; }
constexpr size_t dim_n() const { return m_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
constexpr value_type operator()(size_t i, size_t j) const
/** Return the value of element [ @a i, @a j ] */
constexpr value_type operator()(std::size_t i, std::size_t j) const
{
assert(i < m_m);
assert(j < m_n);
return m_data[i * m_n + j];
}
constexpr value_type &operator()(size_t i, size_t j)
/** Return a reference to element [ @a i, @a j ] */
constexpr value_type &operator()(std::size_t i, std::size_t j)
{
assert(i < m_m);
assert(j < m_n);
@@ -161,65 +207,85 @@ 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;
};
// --------------------------------------------------------------------
// special case, 3x3 matrix
template <typename F, size_t M, size_t N>
/**
* @brief Storage class implementation of matrix_expression
* with compile time fixed size.
*
* @tparam F The type of the stored values
*
* 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, std::size_t M, std::size_t N>
class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
{
public:
/** The value type */
using value_type = F;
static constexpr size_t kSize = M * N;
/** The storage size */
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);
}
}
/** default constructor */
matrix_fixed(value_type v = 0)
{
m_data.fill(v);
}
/** Alternate constructor taking an array of values to store */
matrix_fixed(const F (&v)[kSize])
{
fill(v, std::make_index_sequence<kSize>{});
}
/** @cond */
matrix_fixed(matrix_fixed &&m) = default;
matrix_fixed(const matrix_fixed &m) = default;
matrix_fixed &operator=(matrix_fixed &&m) = default;
matrix_fixed &operator=(const matrix_fixed &m) = default;
/** @endcond */
template<size_t... Ixs>
/** Store the values in @a a in the matrix */
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; }
constexpr size_t dim_n() const { return 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
constexpr value_type operator()(size_t i, size_t j) const
/** Return the value of element [ @a i, @a j ] */
constexpr value_type operator()(std::size_t i, std::size_t j) const
{
assert(i < M);
assert(j < N);
return m_data[i * N + j];
}
constexpr value_type &operator()(size_t i, size_t j)
/** Return a reference to element [ @a i, @a j ] */
constexpr value_type &operator()(std::size_t i, std::size_t j)
{
assert(i < M);
assert(j < N);
@@ -230,44 +296,60 @@ class matrix_fixed : public matrix_expression<matrix_fixed<F, M, N>>
std::array<value_type, M * N> m_data;
};
/** typedef of a fixed matrix of size 3x3 */
template <typename F>
using matrix3x3 = matrix_fixed<F, 3, 3>;
/** typedef of a fixed matrix of size 4x4 */
template <typename F>
using matrix4x4 = matrix_fixed<F, 4, 4>;
// --------------------------------------------------------------------
/**
* @brief Storage class implementation of symmetric matrix_expression
*
* @tparam F The type of the stored values
*
* 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 = float>
class symmetric_matrix : public matrix_expression<symmetric_matrix<F>>
{
public:
/** The value type */
using value_type = F;
symmetric_matrix(size_t n, value_type v = 0)
/** constructor for a matrix of size @a n x @a n elements with value @a v */
symmetric_matrix(std::size_t n, value_type v = 0)
: m_n(n)
, m_data((m_n * (m_n + 1)) / 2)
{
std::fill(m_data.begin(), m_data.end(), v);
}
/** @cond */
symmetric_matrix() = default;
symmetric_matrix(symmetric_matrix &&m) = default;
symmetric_matrix(const symmetric_matrix &m) = default;
symmetric_matrix &operator=(symmetric_matrix &&m) = default;
symmetric_matrix &operator=(const symmetric_matrix &m) = default;
/** @endcond */
constexpr size_t dim_m() const { return m_n; }
constexpr size_t dim_n() const { return m_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
constexpr value_type operator()(size_t i, size_t j) const
/** Return the value of element [ @a i, @a j ] */
constexpr value_type operator()(std::size_t i, std::size_t j) const
{
return i < j
? m_data[(j * (j + 1)) / 2 + i]
: m_data[(i * (i + 1)) / 2 + j];
}
constexpr value_type &operator()(size_t i, size_t j)
/** Return a reference to element [ @a i, @a j ] */
constexpr value_type &operator()(std::size_t i, std::size_t j)
{
if (i > j)
std::swap(i, j);
@@ -276,39 +358,54 @@ 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;
};
// --------------------------------------------------------------------
template <typename F, size_t M>
/**
* @brief Storage class implementation of symmetric matrix_expression
* with compile time fixed size.
*
* @tparam F The type of the stored values
*
* 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, std::size_t M>
class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F, M>>
{
public:
/** The value type */
using value_type = F;
/** constructor with all elements set to value @a v */
symmetric_matrix_fixed(value_type v = 0)
{
std::fill(m_data.begin(), m_data.end(), v);
}
/** @cond */
symmetric_matrix_fixed(symmetric_matrix_fixed &&m) = default;
symmetric_matrix_fixed(const symmetric_matrix_fixed &m) = default;
symmetric_matrix_fixed &operator=(symmetric_matrix_fixed &&m) = default;
symmetric_matrix_fixed &operator=(const symmetric_matrix_fixed &m) = default;
/** @endcond */
constexpr size_t dim_m() const { return M; }
constexpr size_t dim_n() const { return M; }
constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
constexpr std::size_t dim_n() const { return M; } ///< Return dimension n
constexpr value_type operator()(size_t i, size_t j) const
/** Return the value of element [ @a i, @a j ] */
constexpr value_type operator()(std::size_t i, std::size_t j) const
{
return i < j
? m_data[(j * (j + 1)) / 2 + i]
: m_data[(i * (i + 1)) / 2 + j];
}
constexpr value_type &operator()(size_t i, size_t j)
/** Return a reference to element [ @a i, @a j ] */
constexpr value_type &operator()(std::size_t i, std::size_t j)
{
if (i > j)
std::swap(i, j);
@@ -320,44 +417,65 @@ class symmetric_matrix_fixed : public matrix_expression<symmetric_matrix_fixed<F
std::array<value_type, (M * (M + 1)) / 2> m_data;
};
/** typedef of a fixed symmetric matrix of size 3x3 */
template <typename F>
using symmetric_matrix3x3 = symmetric_matrix_fixed<F, 3>;
/** typedef of a fixed symmetric matrix of size 4x4 */
template <typename F>
using symmetric_matrix4x4 = symmetric_matrix_fixed<F, 4>;
// --------------------------------------------------------------------
/**
* @brief implementation of symmetric matrix_expression with a value
* of 1 for the diagonal values and 0 for all the others.
*
* @tparam F The type of the stored values
*
* 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 = float>
class identity_matrix : public matrix_expression<identity_matrix<F>>
{
public:
/** the value type */
using value_type = F;
identity_matrix(size_t n)
/** constructor taking a dimension @a n */
identity_matrix(std::size_t n)
: m_n(n)
{
}
constexpr size_t dim_m() const { return m_n; }
constexpr size_t dim_n() const { return m_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
constexpr value_type operator()(size_t i, size_t j) const
/** Return the value of element [ @a i, @a j ] */
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;
};
// --------------------------------------------------------------------
// matrix functions, implemented as expression templates
/**
* @brief Implementation of a substraction operation as a matrix expression
*
* @tparam M1 Type of matrix 1
* @tparam M2 Type of matrix 2
*/
template <typename M1, typename M2>
class matrix_subtraction : public matrix_expression<matrix_subtraction<M1, M2>>
{
public:
/** constructor */
matrix_subtraction(const M1 &m1, const M2 &m2)
: m_m1(m1)
, m_m2(m2)
@@ -366,10 +484,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(); }
constexpr size_t dim_n() const { return m_m1.dim_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
constexpr auto operator()(size_t i, size_t j) const
/** Access to the value of element [ @a i, @a j ] */
constexpr auto operator()(std::size_t i, std::size_t j) const
{
return m_m1(i, j) - m_m2(i, j);
}
@@ -379,16 +498,24 @@ class matrix_subtraction : public matrix_expression<matrix_subtraction<M1, M2>>
const M2 &m_m2;
};
/** operator to subtract two matrices and return a matrix expression */
template <typename M1, typename M2>
auto operator-(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
{
return matrix_subtraction(m1, m2);
}
/**
* @brief Implementation of a multiplication operation as a matrix expression
*
* @tparam M1 Type of matrix 1
* @tparam M2 Type of matrix 2
*/
template <typename M1, typename M2>
class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_multiplication<M1, M2>>
{
public:
/** constructor */
matrix_matrix_multiplication(const M1 &m1, const M2 &m2)
: m_m1(m1)
, m_m2(m2)
@@ -396,16 +523,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(); }
constexpr size_t dim_n() const { return m_m1.dim_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
constexpr auto operator()(size_t i, size_t j) const
/** Access to the value of element [ @a i, @a j ] */
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;
@@ -416,22 +544,31 @@ class matrix_matrix_multiplication : public matrix_expression<matrix_matrix_mult
const M2 &m_m2;
};
/**
* @brief Implementation of a multiplication operation of a matrix and a scalar value as a matrix expression
*
* @tparam M1 Type of matrix
* @tparam M2 Type of scalar value
*/
template <typename M, typename T>
class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_multiplication<M, T>>
{
public:
/** value type */
using value_type = T;
/** constructor */
matrix_scalar_multiplication(const M &m, value_type v)
: m_m(m)
, m_v(v)
{
}
constexpr size_t dim_m() const { return m_m.dim_m(); }
constexpr size_t dim_n() const { return m_m.dim_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
constexpr auto operator()(size_t i, size_t j) const
/** 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, j) * m_v;
}
@@ -441,12 +578,14 @@ class matrix_scalar_multiplication : public matrix_expression<matrix_scalar_mult
value_type m_v;
};
/** First implementation of operator*, enabled if the second parameter is a scalar */
template <typename M1, typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
auto operator*(const matrix_expression<M1> &m, T v)
{
return matrix_scalar_multiplication(m, v);
}
/** First implementation of operator*, enabled if the second parameter is not a scalar and thus must be a matrix, right? */
template <typename M1, typename M2, std::enable_if_t<not std::is_floating_point_v<M2>, int> = 0>
auto operator*(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
{
@@ -455,9 +594,14 @@ auto operator*(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
// --------------------------------------------------------------------
/** Generic routine to calculate the determinant of a matrix
*
* @note This is currently only implemented for fixed matrices of size 3x3
*/
template <typename M>
auto determinant(const M &m);
/** Implementation of the determinant function for fixed size matrices of size 3x3 */
template <typename F = float>
auto determinant(const matrix3x3<F> &m)
{
@@ -466,9 +610,14 @@ auto determinant(const matrix3x3<F> &m)
m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
}
/** Generic routine to calculate the inverse of a matrix
*
* @note This is currently only implemented for fixed matrices of size 3x3
*/
template <typename M>
M inverse(const M &m);
/** Implementation of the inverse function for fixed size matrices of size 3x3 */
template <typename F = float>
matrix3x3<F> inverse(const matrix3x3<F> &m)
{
@@ -491,29 +640,36 @@ matrix3x3<F> inverse(const matrix3x3<F> &m)
// --------------------------------------------------------------------
/**
* @brief Implementation of a cofactor calculation as a matrix expression
*
* @tparam M Type of matrix
*/
template <typename M>
class matrix_cofactors : public matrix_expression<matrix_cofactors<M>>
{
public:
/** constructor */
matrix_cofactors(const M &m)
: m_m(m)
{
}
constexpr size_t dim_m() const { return m_m.dim_m(); }
constexpr size_t dim_n() const { return m_m.dim_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
constexpr auto operator()(size_t i, size_t j) const
/** Access to the value of element [ @a i, @a j ] */
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]) +

File diff suppressed because it is too large Load Diff

View File

@@ -30,14 +30,24 @@
#include <map>
/**
* @file parser.hpp
*
* This file contains the declaration of an mmCIF parser
*/
namespace cif
{
class validator;
// --------------------------------------------------------------------
/** Exception that is thrown when the mmCIF file contains a parsing error */
class parse_error : public std::runtime_error
{
public:
/// \brief constructor
parse_error(uint32_t line_nr, const std::string &message)
: std::runtime_error("parse error at line " + std::to_string(line_nr) + ": " + message)
{
@@ -46,57 +56,91 @@ class parse_error : public std::runtime_error
// --------------------------------------------------------------------
/**
* @brief The sac_parser is a similar to SAX parsers (Simple API for XML,
* in our case it is Simple API for CIF)
*
* This is a hand crafted, optimised parser for reading cif files,
* both cif 1.0 and cif 1.1 is supported. But version 2.0 is not.
* That means that the content of files strictly contains only
* ASCII characters. Anything else will generate an error.
*
* This class is an abstract base class. Derived classes should
* implement the produce_ methods.
*/
// TODO: Need to implement support for transformed long lines
class sac_parser
{
public:
using datablock_index = std::map<std::string, std::size_t>;
virtual ~sac_parser() = default;
enum CharTraitsMask : uint8_t
/** @cond */
struct iless_op
{
kOrdinaryMask = 1 << 0,
kNonBlankMask = 1 << 1,
kTextLeadMask = 1 << 2,
kAnyPrintMask = 1 << 3
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 */
/// \brief The parser only supports ASCII so we can
/// create a table with character properties.
enum CharTraitsMask : uint8_t
{
kOrdinaryMask = 1 << 0, ///< The character is in the Ordinary class
kNonBlankMask = 1 << 1, ///< The character is in the NonBlank class
kTextLeadMask = 1 << 2, ///< The character is in the TextLead class
kAnyPrintMask = 1 << 3 ///< The character is in the AnyPrint class
};
/// \brief Return true if the character @a ch is a *space* character
static constexpr bool is_space(int ch)
{
return ch == ' ' or ch == '\t' or ch == '\r' or ch == '\n';
}
/// \brief Return true if the character @a ch is a *white* character
static constexpr bool is_white(int ch)
{
return is_space(ch) or ch == '#';
}
/// \brief Return true if the character @a ch is a *ordinary* character
static constexpr bool is_ordinary(int ch)
{
return ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kOrdinaryMask) != 0;
}
/// \brief Return true if the character @a ch is a *non_blank* character
static constexpr bool is_non_blank(int ch)
{
return ch > 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kNonBlankMask) != 0;
}
/// \brief Return true if the character @a ch is a *text_lead* character
static constexpr bool is_text_lead(int ch)
{
return ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kTextLeadMask) != 0;
}
/// \brief Return true if the character @a ch is a *any_print* character
static constexpr bool is_any_print(int ch)
{
return ch == '\t' or
(ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kAnyPrintMask) != 0);
}
/// \brief Return true if the string in @a text can safely be written without quotation
static bool is_unquoted_string(std::string_view text);
protected:
/** @cond */
static constexpr uint8_t kCharTraitsTable[128] = {
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
14, 15, 14, 14, 14, 15, 15, 14, 15, 15, 15, 15, 15, 15, 15, 15, // 2
@@ -109,9 +153,9 @@ class sac_parser
enum class CIFToken
{
Unknown,
UNKNOWN,
Eof,
END_OF_FILE,
DATA,
LOOP,
@@ -119,24 +163,24 @@ class sac_parser
SAVE_,
SAVE_NAME,
STOP,
Tag,
Value
ITEM_NAME,
VALUE
};
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";
default: return "Invalid token parameter";
}
}
@@ -152,17 +196,45 @@ class sac_parser
void match(CIFToken token);
/** @endcond */
public:
/** \brief Parse only a single datablock in the string @a datablock
* The start of the datablock is first located and then data
* is parsed up until the next start of a datablock or the end of
* the data.
* */
bool parse_single_datablock(const std::string &datablock);
/** \brief Return an index for all the datablocks found, that is
* the index will contain the names and offsets for each.
*/
datablock_index index_datablocks();
/**
* @brief Parse the datablock named @a datablock
*
* This will first lookup the datablock's offset in the index @a index
* and then start parsing from that location until the next datablock.
*
* @param datablock Name of the datablock to parse
* @param index The index created using index_datablocks
* @return true If the datablock was found
* @return false If the datablock was not found
*/
bool parse_single_datablock(const std::string &datablock, const datablock_index &index);
/**
* @brief Parse the file
*
*/
void parse_file();
protected:
/** @cond */
sac_parser(std::istream &is, bool init = true);
void parse_global();
@@ -174,7 +246,7 @@ class sac_parser
void error(const std::string &msg)
{
if (cif::VERBOSE > 0)
std::cerr << "Error parsing mmCIF: " << msg << std::endl;
std::cerr << "Error parsing mmCIF: " << msg << '\n';
throw parse_error(m_line_nr, msg);
}
@@ -182,7 +254,7 @@ class sac_parser
void warning(const std::string &msg)
{
if (cif::VERBOSE > 0)
std::cerr << "parser warning at line " << m_line_nr << ": " << msg << std::endl;
std::cerr << "parser warning at line " << m_line_nr << ": " << msg << '\n';
}
// production methods, these are pure virtual here
@@ -205,9 +277,9 @@ class sac_parser
QuotedString,
QuotedStringQuote,
UnquotedString,
Tag,
TextField,
TextFieldNL,
ItemName,
TextItem,
TextItemNL,
Reserved,
Value
};
@@ -222,19 +294,37 @@ class sac_parser
// token buffer
std::vector<char> m_token_buffer;
std::string_view m_token_value;
/** @endcond */
};
// --------------------------------------------------------------------
/**
* @brief An actual implementation of a sac_parser generating data in a file
*
* This parser will create the cif::file, cif::datablock and cif::category
* objects required to contain all data
*/
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)
, m_file(file)
{
}
/** @cond */
void produce_datablock(std::string_view name) override;
void produce_category(std::string_view name) override;
@@ -247,7 +337,10 @@ class parser : public sac_parser
file &m_file;
datablock *m_datablock = nullptr;
category *m_category = nullptr;
const validator *m_validator = nullptr;
row_handle m_row;
/** @endcond */
};
} // namespace cif

251
include/cif++/pdb.hpp Normal file
View File

@@ -0,0 +1,251 @@
/*-
* 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
* 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.
*/
#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
{
/// --------------------------------------------------------------------
// PDB to mmCIF
/** @brief Read a file in either mmCIF or PDB format from file @a file,
* compressed or not, depending on the content.
*/
file read(const std::filesystem::path &file);
/** @brief Read a file in either mmCIF or PDB format from std::istream @a is,
* compressed or not, depending on the content.
*/
file read(std::istream &is);
/**
* @brief Read a file in legacy PDB format from std::istream @a is and
* put the data into @a cifFile
*/
file read_pdb_file(std::istream &pdbFile);
// mmCIF to PDB
/** @brief Write out the data in @a db in legacy PDB format
* to std::ostream @a os
*/
void write(std::ostream &os, const datablock &db);
/** @brief Write out the data in @a f in legacy PDB format
* to std::ostream @a os
*/
inline void write(std::ostream &os, const file &f)
{
write(os, f.front());
}
/** @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.
*/
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.
*/
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
/** @brief Return the HEADER line for the data in @a data
*
* 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_HEADER_line(const datablock &data, std::string::size_type truncate_at = 127);
/** @brief Return the COMPND line for the data in @a data
*
* 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_COMPND_line(const datablock &data, std::string::size_type truncate_at = 127);
/** @brief Return the SOURCE line for the data in @a data
*
* 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_SOURCE_line(const datablock &data, std::string::size_type truncate_at = 127);
/** @brief Return the AUTHOR line for the data in @a data
*
* 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 cif::pdb

View File

@@ -26,17 +26,8 @@
#pragma once
#include "cif++/datablock.hpp"
/// \file cif2pdb.hpp
/// \deprecated This file is no longer used. Please use "cif++/pdb.hpp" instead
namespace cif::pdb
{
#warning "Use of this file is deprecated, please use "cif++/pdb.hpp"
/// \brief Just the HEADER, COMPND, SOURCE and AUTHOR lines
void write_header_lines(std::ostream &os, const datablock &data);
std::string get_HEADER_line(const datablock &data, std::string::size_type truncate_at = 127);
std::string get_COMPND_line(const datablock &data, std::string::size_type truncate_at = 127);
std::string get_SOURCE_line(const datablock &data, std::string::size_type truncate_at = 127);
std::string get_AUTHOR_line(const datablock &data, std::string::size_type truncate_at = 127);
} // namespace pdbx

View File

@@ -26,35 +26,7 @@
#pragma once
#include "cif++/datablock.hpp"
/// \file io.hpp
/// \deprecated This file is no longer used. Please use "cif++/pdb.hpp" instead
namespace cif::pdb
{
/// \brief Read a file in either mmCIF or PDB format, compressed or not,
/// depending on the content.
file read(const std::filesystem::path &file);
/// \brief Read a file in either mmCIF or PDB format, compressed or not,
/// depending on the content.
file read(std::istream &is);
/// \brief Write out a file in PDB format
void write(std::ostream &os, const datablock &db);
/// \brief Write out a file in PDB format
inline void write(std::ostream &os, const file &f)
{
write(os, f.front());
}
/// \brief Write out a file in PDB format or mmCIF format, depending on the filename extension
void write(const std::filesystem::path &file, const datablock &db);
/// \brief Write out a file in PDB format or mmCIF format, depending on the filename extension
inline void write(const std::filesystem::path &p, const file &f)
{
write(p, f.front());
}
}
#warning "Use of this file is deprecated, please use "cif++/pdb.hpp"

View File

@@ -26,39 +26,7 @@
#pragma once
#include "cif++/file.hpp"
namespace cif::pdb
{
/// \file pdb2cif.hpp
/// \deprecated This file is no longer used. Please use "cif++/pdb.hpp" instead
// --------------------------------------------------------------------
struct PDBRecord
{
PDBRecord *mNext;
uint32_t mLineNr;
char mName[11];
size_t mVlen;
char mValue[1];
PDBRecord(uint32_t lineNr, const std::string &name, const std::string &value);
~PDBRecord();
void *operator new(size_t);
void *operator new(size_t size, size_t vLen);
void operator delete(void *p);
void operator delete(void *p, size_t vLen);
bool is(const char *name) const;
char vC(size_t column);
std::string vS(size_t columnFirst, size_t columnLast = std::numeric_limits<size_t>::max());
int vI(int columnFirst, int columnLast);
std::string vF(size_t columnFirst, size_t columnLast);
};
// --------------------------------------------------------------------
void ReadPDBFile(std::istream &pdbFile, file &cifFile);
} // namespace pdbx
#warning "Use of this file is deprecated, please use "cif++/pdb.hpp"

View File

@@ -26,26 +26,7 @@
#pragma once
#include "cif++/datablock.hpp"
/// \file tls.hpp
/// \deprecated This code has been moved to libpdb-redo
#include <string>
#include <tuple>
#include <vector>
namespace cif
{
struct tls_selection;
struct tls_residue;
struct tls_selection
{
virtual ~tls_selection() {}
virtual void collect_residues(cif::datablock &db, std::vector<tls_residue> &residues, std::size_t indentLevel = 0) const = 0;
std::vector<std::tuple<std::string, int, int>> get_ranges(cif::datablock &db, bool pdbNamespace) const;
};
// Low level: get the selections
std::unique_ptr<tls_selection> parse_tls_selection_details(const std::string &program, const std::string &selection);
} // namespace cif
#warning "This code has been moved to libpdb-redo"

View File

@@ -26,8 +26,6 @@
#pragma once
#include "cif++/exports.hpp"
#include <array>
#include <cmath>
#include <complex>
@@ -37,27 +35,55 @@
#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
*
* This file contains the definition for *cif::point* as well as
* lots of routines and classes that can manipulate points.
*/
namespace cif
{
// --------------------------------------------------------------------
/// \brief Our value for Pi
const double
kPI = 3.141592653589793238462643383279502884;
// --------------------------------------------------------------------
// A stripped down quaternion implementation, based on boost::math::quaternion
// We use quaternions to do rotations in 3d space
/**
* @brief A stripped down quaternion implementation, based on boost::math::quaternion
*
* We use quaternions to do rotations in 3d space. Quaternions are faster than
* matrix calculations and they also suffer less from drift caused by rounding
* errors.
*
* Like complex number, quaternions do have a meaningful notion of "real part",
* but unlike them there is no meaningful notion of "imaginary part".
* Instead there is an "unreal part" which itself is a quaternion, and usually
* nothing simpler (as opposed to the complex number case).
* However, for practicality, there are accessors for the other components
* (these are necessary for the templated copy constructor, for instance).
*
* @note Quaternion multiplication is *NOT* commutative;
* symbolically, "q *= rhs;" means "q = q * rhs;"
* and "q /= rhs;" means "q = q * inverse_of(rhs);"
*/
template <typename T>
class quaternion_type
{
public:
/// \brief the value type of the elements, usually this is float
using value_type = T;
/// \brief constructor with the four members
constexpr explicit quaternion_type(value_type const &value_a = {}, value_type const &value_b = {}, value_type const &value_c = {}, value_type const &value_d = {})
: a(value_a)
, b(value_b)
@@ -66,6 +92,7 @@ class quaternion_type
{
}
/// \brief constructor taking two complex values as input
constexpr explicit quaternion_type(std::complex<value_type> const &z0, std::complex<value_type> const &z1 = std::complex<value_type>())
: a(z0.real())
, b(z0.imag())
@@ -74,9 +101,10 @@ class quaternion_type
{
}
constexpr quaternion_type(quaternion_type const &) = default;
constexpr quaternion_type(quaternion_type &&) = default;
constexpr quaternion_type(quaternion_type const &) = default; ///< Copy constructor
constexpr quaternion_type(quaternion_type &&) = default; ///< Copy constructor
/// \brief Copy constructor accepting a quaternion with a different value_type
template <typename X>
constexpr explicit quaternion_type(quaternion_type<X> const &rhs)
: a(static_cast<value_type>(rhs.a))
@@ -87,24 +115,20 @@ class quaternion_type
}
// accessors
//
// Note: Like complex number, quaternions do have a meaningful notion of "real part",
// but unlike them there is no meaningful notion of "imaginary part".
// Instead there is an "unreal part" which itself is a quaternion, and usually
// nothing simpler (as opposed to the complex number case).
// However, for practicality, there are accessors for the other components
// (these are necessary for the templated copy constructor, for instance).
/// \brief See class description, return the *real* part of the quaternion
constexpr value_type real() const
{
return a;
}
/// \brief See class description, return the *unreal* part of the quaternion
constexpr quaternion_type unreal() const
{
return { 0, b, c, d };
}
/// \brief swap
constexpr void swap(quaternion_type &o)
{
std::swap(a, o.a);
@@ -115,6 +139,7 @@ class quaternion_type
// assignment operators
/// \brief Assignment operator accepting a quaternion with optionally another value_type
template <typename X>
constexpr quaternion_type &operator=(quaternion_type<X> const &rhs)
{
@@ -126,6 +151,7 @@ class quaternion_type
return *this;
}
/// \brief Assignment operator
constexpr quaternion_type &operator=(quaternion_type const &rhs)
{
a = rhs.a;
@@ -136,6 +162,7 @@ class quaternion_type
return *this;
}
/// \brief Assignment operator that sets the *real* part to @a rhs and the *unreal* parts to zero
constexpr quaternion_type &operator=(value_type const &rhs)
{
a = rhs;
@@ -145,6 +172,9 @@ class quaternion_type
return *this;
}
/// \brief Assignment operator that sets the *real* part to the real part of @a rhs
/// and the first *unreal* part to the imaginary part of of @a rhs. The other *unreal*
// parts are set to zero.
constexpr quaternion_type &operator=(std::complex<value_type> const &rhs)
{
a = rhs.real();
@@ -156,17 +186,16 @@ class quaternion_type
}
// other assignment-related operators
//
// NOTE: Quaternion multiplication is *NOT* commutative;
// symbolically, "q *= rhs;" means "q = q * rhs;"
// and "q /= rhs;" means "q = q * inverse_of(rhs);"
/// \brief operator += adding value @a rhs to the *real* part
constexpr quaternion_type &operator+=(value_type const &rhs)
{
a += rhs;
return *this;
}
/// \brief operator += adding the real part of @a rhs to the *real* part
/// and the imaginary part of @a rhs to the first *unreal* part
constexpr quaternion_type &operator+=(std::complex<value_type> const &rhs)
{
a += std::real(rhs);
@@ -174,6 +203,7 @@ class quaternion_type
return *this;
}
/// \brief operator += adding the parts of @a rhs to the equivalent part of this
template <class X>
constexpr quaternion_type &operator+=(quaternion_type<X> const &rhs)
{
@@ -184,12 +214,15 @@ class quaternion_type
return *this;
}
/// \brief operator -= subtracting value @a rhs from the *real* part
constexpr quaternion_type &operator-=(value_type const &rhs)
{
a -= rhs;
return *this;
}
/// \brief operator -= subtracting the real part of @a rhs from the *real* part
/// and the imaginary part of @a rhs from the first *unreal* part
constexpr quaternion_type &operator-=(std::complex<value_type> const &rhs)
{
a -= std::real(rhs);
@@ -197,6 +230,7 @@ class quaternion_type
return *this;
}
/// \brief operator -= subtracting the parts of @a rhs from the equivalent part of this
template <class X>
constexpr quaternion_type &operator-=(quaternion_type<X> const &rhs)
{
@@ -207,6 +241,7 @@ class quaternion_type
return *this;
}
/// \brief multiply all parts with value @a rhs
constexpr quaternion_type &operator*=(value_type const &rhs)
{
a *= rhs;
@@ -216,6 +251,7 @@ class quaternion_type
return *this;
}
/// \brief multiply with complex number @a rhs
constexpr quaternion_type &operator*=(std::complex<value_type> const &rhs)
{
value_type ar = rhs.real();
@@ -225,13 +261,15 @@ class quaternion_type
return *this;
}
constexpr friend quaternion_type operator*(const quaternion_type &a, const quaternion_type &b)
/// \brief multiply @a a with @a b and return the result
friend constexpr quaternion_type operator*(const quaternion_type &a, const quaternion_type &b)
{
auto result = a;
result *= b;
return result;
}
/// \brief multiply with quaternion @a rhs
template <typename X>
constexpr quaternion_type &operator*=(quaternion_type<X> const &rhs)
{
@@ -245,6 +283,7 @@ class quaternion_type
return *this;
}
/// \brief divide all parts by @a rhs
constexpr quaternion_type &operator/=(value_type const &rhs)
{
a /= rhs;
@@ -254,6 +293,7 @@ class quaternion_type
return *this;
}
/// \brief divide by complex number @a rhs
constexpr quaternion_type &operator/=(std::complex<value_type> const &rhs)
{
value_type ar = rhs.real();
@@ -264,6 +304,7 @@ class quaternion_type
return *this;
}
/// \brief divide by quaternion @a rhs
template <typename X>
constexpr quaternion_type &operator/=(quaternion_type<X> const &rhs)
{
@@ -278,7 +319,8 @@ class quaternion_type
return *this;
}
constexpr friend quaternion_type normalize(quaternion_type q)
/// \brief normalise the values so that the length of the result is exactly 1
friend constexpr quaternion_type normalize(quaternion_type q)
{
std::valarray<value_type> t(4);
@@ -299,26 +341,30 @@ class quaternion_type
return q;
}
constexpr friend quaternion_type conj(quaternion_type q)
/// \brief return the conjugate of this
friend constexpr quaternion_type conj(quaternion_type q)
{
return quaternion_type{ +q.a, -q.b, -q.c, -q.d };
}
constexpr value_type get_a() const { return a; }
constexpr value_type get_b() const { return b; }
constexpr value_type get_c() const { return c; }
constexpr value_type get_d() const { return d; }
constexpr value_type get_a() const { return a; } ///< Return part a
constexpr value_type get_b() const { return b; } ///< Return part b
constexpr value_type get_c() const { return c; } ///< Return part c
constexpr value_type get_d() const { return d; } ///< Return part d
/// \brief compare with @a rhs
constexpr bool operator==(const quaternion_type &rhs) const
{
return a == rhs.a and b == rhs.b and c == rhs.c and d == rhs.d;
}
/// \brief compare with @a rhs
constexpr bool operator!=(const quaternion_type &rhs) const
{
return a != rhs.a or b != rhs.b or c != rhs.c or d != rhs.d;
}
/// \brief test for all zero values
constexpr operator bool() const
{
return a != 0 or b != 0 or c != 0 or d != 0;
@@ -328,6 +374,19 @@ class quaternion_type
value_type a, b, c, d;
};
/**
* @brief This code is similar to the code in boost so I copy the documentation as well:
*
* > spherical is a simple transposition of polar, it takes as inputs a (positive)
* > magnitude and a point on the hypersphere, given by three angles. The first of
* > these, theta has a natural range of -pi to +pi, and the other two have natural
* > ranges of -pi/2 to +pi/2 (as is the case with the usual spherical coordinates in
* > **R**<sup>3</sup>). Due to the many symmetries and periodicities, nothing untoward happens if
* > the magnitude is negative or the angles are outside their natural ranges. The
* > expected degeneracies (a magnitude of zero ignores the angles settings...) do
* > happen however.
*/
template <typename T>
inline quaternion_type<T> spherical(T const &rho, T const &theta, T const &phi1, T const &phi2)
{
@@ -345,24 +404,34 @@ inline quaternion_type<T> spherical(T const &rho, T const &theta, T const &phi1,
return result;
}
/// \brief By default we use the float version of a quaternion
using quaternion = quaternion_type<float>;
// --------------------------------------------------------------------
// point, a location with x, y and z coordinates as floating point.
// This one is derived from a tuple<float,float,float> so
// you can do things like:
//
// float x, y, z;
// tie(x, y, z) = atom.loc();
/**
* @brief 3D point: a location with x, y and z coordinates as floating point.
*
* Note that you can simply use structured binding to get access to the
* individual parts like so:
*
* @code{.cpp}
* float x, y, z;
* tie(x, y, z) = atom.get_location();
* @endcode
*/
template <typename F>
struct point_type
{
/// \brief the value type of the x, y and z members
using value_type = F;
value_type m_x, m_y, m_z;
value_type m_x, ///< The x part of the location
m_y, ///< The y part of the location
m_z; ///< The z part of the location
/// \brief default constructor, initialises the values to zero
constexpr point_type()
: m_x(0)
, m_y(0)
@@ -370,6 +439,7 @@ struct point_type
{
}
/// \brief constructor taking three values
constexpr point_type(value_type x, value_type y, value_type z)
: m_x(x)
, m_y(y)
@@ -377,6 +447,7 @@ struct point_type
{
}
/// \brief Copy constructor
template <typename PF>
constexpr point_type(const point_type<PF> &pt)
: m_x(static_cast<F>(pt.m_x))
@@ -385,12 +456,14 @@ struct point_type
{
}
/// \brief constructor taking a tuple of three values
constexpr point_type(const std::tuple<value_type, value_type, value_type> &pt)
: point_type(std::get<0>(pt), std::get<1>(pt), std::get<2>(pt))
{
}
#if HAVE_LIBCLIPPER
/// \brief Construct a point using the values in clipper coordinate @a pt
constexpr point_type(const clipper::Coord_orth &pt)
: m_x(pt[0])
, m_y(pt[1])
@@ -398,6 +471,7 @@ struct point_type
{
}
/// \brief Assign a point using the values in clipper coordinate @a rhs
constexpr point_type &operator=(const clipper::Coord_orth &rhs)
{
m_x = rhs[0];
@@ -407,6 +481,7 @@ struct point_type
}
#endif
/// \brief Assignment operator
template <typename PF>
constexpr point_type &operator=(const point_type<PF> &rhs)
{
@@ -416,18 +491,19 @@ struct point_type
return *this;
}
constexpr value_type &get_x() { return m_x; }
constexpr value_type get_x() const { return m_x; }
constexpr void set_x(value_type x) { m_x = x; }
constexpr value_type &get_x() { return m_x; } ///< Get a reference to x
constexpr value_type get_x() const { return m_x; } ///< Get the value of x
constexpr void set_x(value_type x) { m_x = x; } ///< Set the value of x to @a x
constexpr value_type &get_y() { return m_y; }
constexpr value_type get_y() const { return m_y; }
constexpr void set_y(value_type y) { m_y = y; }
constexpr value_type &get_y() { return m_y; } ///< Get a reference to y
constexpr value_type get_y() const { return m_y; } ///< Get the value of y
constexpr void set_y(value_type y) { m_y = y; } ///< Set the value of y to @a y
constexpr value_type &get_z() { return m_z; }
constexpr value_type get_z() const { return m_z; }
constexpr void set_z(value_type z) { m_z = z; }
constexpr value_type &get_z() { return m_z; } ///< Get a reference to z
constexpr value_type get_z() const { return m_z; } ///< Get the value of z
constexpr void set_z(value_type z) { m_z = z; } ///< Set the value of z to @a z
/// \brief add @a rhs
constexpr point_type &operator+=(const point_type &rhs)
{
m_x += rhs.m_x;
@@ -437,6 +513,7 @@ struct point_type
return *this;
}
/// \brief add @a d to all members
constexpr point_type &operator+=(value_type d)
{
m_x += d;
@@ -446,6 +523,14 @@ struct point_type
return *this;
}
/// \brief Add the points @a lhs and @a rhs and return the result
template <typename F2>
friend constexpr auto operator+(const point_type &lhs, const point_type<F2> &rhs)
{
return point_type<std::common_type_t<value_type, F2>>(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y, lhs.m_z + rhs.m_z);
}
/// \brief subtract @a rhs
constexpr point_type &operator-=(const point_type &rhs)
{
m_x -= rhs.m_x;
@@ -455,6 +540,7 @@ struct point_type
return *this;
}
/// \brief subtract @a d from all members
constexpr point_type &operator-=(value_type d)
{
m_x -= d;
@@ -464,6 +550,20 @@ struct point_type
return *this;
}
/// \brief Subtract the points @a lhs and @a rhs and return the result
template <typename F2>
friend constexpr auto operator-(const point_type &lhs, const point_type<F2> &rhs)
{
return point_type<std::common_type_t<value_type, F2>>(lhs.m_x - rhs.m_x, lhs.m_y - rhs.m_y, lhs.m_z - rhs.m_z);
}
/// \brief Return the negative copy of @a pt
friend constexpr point_type operator-(const point_type &pt)
{
return point_type(-pt.m_x, -pt.m_y, -pt.m_z);
}
/// \brief multiply all members with @a rhs
constexpr point_type &operator*=(value_type rhs)
{
m_x *= rhs;
@@ -472,6 +572,21 @@ struct point_type
return *this;
}
/// \brief multiply point @a pt with value @a f and return the result
template <typename F2>
friend constexpr auto operator*(const point_type &pt, F2 f)
{
return point_type<std::common_type_t<value_type, F2>>(pt.m_x * f, pt.m_y * f, pt.m_z * f);
}
/// \brief multiply point @a pt with value @a f and return the result
template <typename F2>
friend constexpr auto operator*(F2 f, const point_type &pt)
{
return point_type<std::common_type_t<value_type, F2>>(pt.m_x * f, pt.m_y * f, pt.m_z * f);
}
/// \brief divide all members by @a rhs
constexpr point_type &operator/=(value_type rhs)
{
m_x /= rhs;
@@ -480,6 +595,20 @@ struct point_type
return *this;
}
/// \brief divide point @a pt by value @a f and return the result
template <typename F2>
friend constexpr auto operator/(const point_type &pt, F2 f)
{
return point_type<std::common_type_t<value_type, F2>>(pt.m_x / f, pt.m_y / f, pt.m_z / f);
}
/**
* @brief looking at this point as a vector, normalise it which
* means dividing all members by the length making the length
* effectively 1.
*
* @return The previous length of this vector
*/
constexpr value_type normalize()
{
auto length = m_x * m_x + m_y * m_y + m_z * m_z;
@@ -491,6 +620,7 @@ struct point_type
return length;
}
/// \brief Rotate this point using the quaterion @a q
constexpr void rotate(const quaternion &q)
{
quaternion_type<value_type> p(0, m_x, m_y, m_z);
@@ -502,6 +632,9 @@ struct point_type
m_z = p.get_d();
}
/// \brief Rotate this point using the quaterion @a q by first
/// moving the point to @a pivot and after rotating moving it
/// back
constexpr void rotate(const quaternion &q, point_type pivot)
{
operator-=(pivot);
@@ -510,97 +643,82 @@ struct point_type
}
#if HAVE_LIBCLIPPER
/// \brief Make it possible to pass a point to clipper functions expecting a clipper coordinate
operator clipper::Coord_orth() const
{
return clipper::Coord_orth(m_x, m_y, m_z);
}
#endif
/// \brief Allow access to this point as if it is a tuple of three const value_type's
constexpr operator std::tuple<const value_type &, const value_type &, const value_type &>() const
{
return std::make_tuple(std::ref(m_x), std::ref(m_y), std::ref(m_z));
}
/// \brief Allow access to this point as if it is a tuple of three value_type's
constexpr operator std::tuple<value_type &, value_type &, value_type &>()
{
return std::make_tuple(std::ref(m_x), std::ref(m_y), std::ref(m_z));
}
#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
constexpr value_type length_sq() const
{
return m_x * m_x + m_y * m_y + m_z * m_z;
}
/// \brief looking at the point as if it is a vector, return the length
constexpr value_type length() const
{
return std::sqrt(m_x * m_x + m_y * m_y + m_z * m_z);
return std::sqrt(length_sq());
}
/// \brief Print out the point @a pt to @a os
friend std::ostream &operator<<(std::ostream &os, const point_type &pt)
{
os << '(' << pt.m_x << ',' << pt.m_y << ',' << pt.m_z << ')';
return os;
}
};
/// \brief By default we use points with float value_type
using point = point_type<float>;
template <typename F>
inline constexpr std::ostream &operator<<(std::ostream &os, const point_type<F> &pt)
{
os << '(' << pt.m_x << ',' << pt.m_y << ',' << pt.m_z << ')';
return os;
}
template <typename F>
inline constexpr point_type<F> operator+(const point_type<F> &lhs, const point_type<F> &rhs)
{
return point_type<F>(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y, lhs.m_z + rhs.m_z);
}
template <typename F>
inline constexpr point_type<F> operator-(const point_type<F> &lhs, const point_type<F> &rhs)
{
return point_type<F>(lhs.m_x - rhs.m_x, lhs.m_y - rhs.m_y, lhs.m_z - rhs.m_z);
}
template <typename F>
inline constexpr point_type<F> operator-(const point_type<F> &pt)
{
return point_type<F>(-pt.m_x, -pt.m_y, -pt.m_z);
}
template <typename F>
inline constexpr point_type<F> operator*(const point_type<F> &pt, F f)
{
return point_type<F>(pt.m_x * f, pt.m_y * f, pt.m_z * f);
}
template <typename F>
inline constexpr point_type<F> operator*(F f, const point_type<F> &pt)
{
return point_type<F>(pt.m_x * f, pt.m_y * f, pt.m_z * f);
}
template <typename F>
inline constexpr point_type<F> operator/(const point_type<F> &pt, F f)
{
return point_type<F>(pt.m_x / f, pt.m_y / f, pt.m_z / f);
}
// --------------------------------------------------------------------
// several standard 3d operations
template <typename F>
inline constexpr auto distance_squared(const point_type<F> &a, const point_type<F> &b)
/// \brief return the squared distance between points @a a and @a b
template <typename F1, typename F2>
constexpr auto distance_squared(const point_type<F1> &a, const point_type<F2> &b)
{
return (a.m_x - b.m_x) * (a.m_x - b.m_x) +
(a.m_y - b.m_y) * (a.m_y - b.m_y) +
(a.m_z - b.m_z) * (a.m_z - b.m_z);
}
template <typename F>
inline constexpr auto distance(const point_type<F> &a, const point_type<F> &b)
/// \brief return the distance between points @a a and @a b
template <typename F1, typename F2>
constexpr auto distance(const point_type<F1> &a, const point_type<F2> &b)
{
return std::sqrt(
(a.m_x - b.m_x) * (a.m_x - b.m_x) +
@@ -608,20 +726,24 @@ inline constexpr auto distance(const point_type<F> &a, const point_type<F> &b)
(a.m_z - b.m_z) * (a.m_z - b.m_z));
}
template <typename F>
inline constexpr auto dot_product(const point_type<F> &a, const point_type<F> &b)
/// \brief return the dot product between the vectors @a a and @a b
template <typename F1, typename F2>
inline constexpr auto dot_product(const point_type<F1> &a, const point_type<F2> &b)
{
return a.m_x * b.m_x + a.m_y * b.m_y + a.m_z * b.m_z;
}
template <typename F>
inline constexpr point_type<F> cross_product(const point_type<F> &a, const point_type<F> &b)
/// \brief return the cross product between the vectors @a a and @a b
template <typename F1, typename F2>
inline constexpr auto cross_product(const point_type<F1> &a, const point_type<F2> &b)
{
return point_type<F>(a.m_y * b.m_z - b.m_y * a.m_z,
return point_type<std::common_type_t<F1, F2>>(
a.m_y * b.m_z - b.m_y * a.m_z,
a.m_z * b.m_x - b.m_z * a.m_x,
a.m_x * b.m_y - b.m_x * a.m_y);
}
/// \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)
{
@@ -631,6 +753,9 @@ constexpr auto angle(const point_type<F> &p1, const point_type<F> &p2, const poi
return std::acos(dot_product(v1, v2) / (v1.length() * v2.length())) * 180 / kPI;
}
/// \brief return the dihedral angle in degrees for the four points @a p1, @a p2, @a p3 and @a p4
///
/// See https://en.wikipedia.org/wiki/Dihedral_angle for an explanation of what a dihedral angle is
template <typename F>
constexpr auto dihedral_angle(const point_type<F> &p1, const point_type<F> &p2, const point_type<F> &p3, const point_type<F> &p4)
{
@@ -658,6 +783,7 @@ constexpr auto dihedral_angle(const point_type<F> &p1, const point_type<F> &p2,
return result;
}
/// \brief return the cosinus angle for the four points @a p1, @a p2, @a p3 and @a p4
template <typename F>
constexpr auto cosinus_angle(const point_type<F> &p1, const point_type<F> &p2, const point_type<F> &p3, const point_type<F> &p4)
{
@@ -669,6 +795,7 @@ constexpr auto cosinus_angle(const point_type<F> &p1, const point_type<F> &p2, c
return x > 0 ? dot_product(v12, v34) / std::sqrt(x) : 0;
}
/// \brief return the distance from point @a p to the line from @a l1 to @a l2
template <typename F>
constexpr auto distance_point_to_line(const point_type<F> &l1, const point_type<F> &l2, const point_type<F> &p)
{
@@ -680,15 +807,19 @@ constexpr auto distance_point_to_line(const point_type<F> &l1, const point_type<
}
// --------------------------------------------------------------------
// For e.g. simulated annealing, returns a new point that is moved in
// a random direction with a distance randomly chosen from a normal
// distribution with a stddev of offset.
/**
* @brief For e.g. simulated annealing, returns a new point that is moved in
* a random direction with a distance randomly chosen from a normal
* distribution with a stddev of offset.
*/
point nudge(point p, float offset);
// --------------------------------------------------------------------
/// \brief Return a quaternion created from angle @a angle and axis @a axis
quaternion construct_from_angle_axis(float angle, point axis);
/// \brief Return a tuple of an angle and an axis for quaternion @a q
std::tuple<double, point> quaternion_to_angle_axis(quaternion q);
/// @brief Given four points and an angle, return the quaternion required to rotate
@@ -697,8 +828,12 @@ std::tuple<double, point> quaternion_to_angle_axis(quaternion q);
quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
float angle, float esd);
point centroid(const std::vector<point> &Points);
point center_points(std::vector<point> &Points);
/// \brief Return the point that is the centroid of all the points in @a pts
point centroid(const std::vector<point> &pts);
/// \brief Move all the points in @a pts so that their centroid is at the origin
/// (0, 0, 0) and return the offset used (the former centroid)
point center_points(std::vector<point> &pts);
/// \brief Returns how the two sets of points \a a and \b b can be aligned
///
@@ -712,38 +847,56 @@ quaternion align_points(const std::vector<point> &a, const std::vector<point> &b
double RMSd(const std::vector<point> &a, const std::vector<point> &b);
// --------------------------------------------------------------------
// Helper class to generate evenly divided points on a sphere
// we use a fibonacci sphere to calculate even distribution of the dots
/**
* @brief Helper class to generate evenly divided points on a sphere
*
* We use a fibonacci sphere to calculate even distribution of the dots
*
* @tparam N The number of points on the sphere is 2 * N + 1
*/
template <int N>
class spherical_dots
{
public:
/// \brief the number of points
constexpr static int P = 2 * N * 1;
/// \brief the *weight* of the fibonacci sphere
constexpr static double W = (4 * kPI) / P;
/// \brief the internal storage type
using array_type = typename std::array<point, P>;
/// \brief iterator type
using iterator = typename array_type::const_iterator;
/// \brief singleton instance
static spherical_dots &instance()
{
static spherical_dots sInstance;
return sInstance;
}
size_t size() const { return m_points.size(); }
/// \brief The number of points
std::size_t size() const { return P; }
/// \brief Access a point by index
const point operator[](uint32_t inIx) const { return m_points[inIx]; }
/// \brief iterator pointing to the first point
iterator begin() const { return m_points.begin(); }
/// \brief iterator pointing past the last point
iterator end() const { return m_points.end(); }
double weight() const { return m_weight; }
/// \brief return the *weight*,
double weight() const { return W; }
spherical_dots()
{
const double
kGoldenRatio = (1 + std::sqrt(5.0)) / 2;
m_weight = (4 * kPI) / P;
auto p = m_points.begin();
for (int32_t i = -N; i <= N; ++i)
@@ -761,7 +914,6 @@ class spherical_dots
private:
array_type m_points;
double m_weight;
};
} // namespace cif

View File

@@ -30,6 +30,51 @@
#include <array>
/**
* @file row.hpp
*
* The class cif::row should be an opaque type. It is used to store the
* internal data per row in a category. You should use cif::row_handle
* to get access to the contents in a row.
*
* One could think of rows as vectors of cif::item. But internally
* 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.
*
* @code {.cpp}
* cif::category &atom_site = my_db["atom_site"];
* cif::row_handle rh = atom_site.front();
*
* // by name:
* std::string name = rh["label_atom_id"].as<std::string>();
*
* // by index:
* uint16_t ix = atom_site.get_item_ix("label_atom_id");
* assert(rh[ix].as<std::string() == name);
* @endcode
*
* There some template magic here to allow easy extracting of data
* from rows. This can be done using cif::tie e.g.:
*
* @code {.cpp}
* std::string name;
* float x, y, z;
*
* cif::tie(name, x, y, z) = rh.get("label_atom_id", "cartn_x", "cartn_y", "cartn_z");
* @endcode
*
* However, a more modern way uses structured binding:
*
* @code {.cpp}
* const auto &[name, x, y, z] = rh.get<std::string,float,float,float>("label_atom_id", "cartn_x", "cartn_y", "cartn_z");
* @endcode
*
*
*
*/
namespace cif
{
@@ -40,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
{
return m_row[m_columns[ix]];
return m_row[m_items[ix]];
}
template <typename... Ts, std::enable_if_t<N == sizeof...(Ts), int> = 0>
@@ -59,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 as<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
@@ -96,6 +141,8 @@ namespace detail
} // namespace detail
/// \brief similar to std::tie, assign values to each element in @a v from the
/// result of a get on a row_handle.
template <typename... Ts>
auto tie(Ts &...v)
{
@@ -110,11 +157,17 @@ class row : public std::vector<item_value>
public:
row() = default;
/**
* @brief Return the item_value pointer for item at index @a ix
*/
item_value* get(uint16_t ix)
{
return ix < size() ? &data()[ix] : nullptr;
}
/**
* @brief Return the const item_value pointer for item at index @a ix
*/
const item_value* get(uint16_t ix) const
{
return ix < size() ? &data()[ix] : nullptr;
@@ -150,10 +203,12 @@ class row : public std::vector<item_value>
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;
@@ -163,86 +218,133 @@ class row_handle
row_handle &operator=(const row_handle &) = default;
row_handle &operator=(row_handle &&) = default;
/** @endcond */
/// \brief constructor taking a category @a cat and a row @a r
row_handle(const category &cat, const row &r)
: m_category(const_cast<category *>(&cat))
, m_row(const_cast<row *>(&r))
{
}
/// \brief return the category this row belongs to
const category &get_category() const
{
return *m_category;
}
/// \brief Return true if the row is empty or uninitialised
bool empty() const
{
return m_category == nullptr or m_row == nullptr;
}
/// \brief convenience method to test for empty()
explicit operator bool() const
{
return not empty();
}
item_handle operator[](uint16_t column_ix)
/// \brief return a cif::item_handle to the item in item @a item_ix
item_handle operator[](uint16_t item_ix)
{
return empty() ? item_handle::s_null_item : item_handle(column_ix, *this);
return empty() ? item_handle::s_null_item : item_handle(item_ix, *this);
}
const item_handle operator[](uint16_t column_ix) const
/// \brief return a const cif::item_handle to the item in item @a item_ix
const item_handle operator[](uint16_t item_ix) const
{
return empty() ? item_handle::s_null_item : item_handle(column_ix, const_cast<row_handle &>(*this));
return empty() ? item_handle::s_null_item : item_handle(item_ix, const_cast<row_handle &>(*this));
}
item_handle operator[](std::string_view column_name)
/// \brief return a cif::item_handle to the item in the item named @a item_name
item_handle operator[](std::string_view item_name)
{
return empty() ? item_handle::s_null_item : item_handle(add_column(column_name), *this);
return empty() ? item_handle::s_null_item : item_handle(add_item(item_name), *this);
}
const item_handle operator[](std::string_view column_name) const
/// \brief return a const cif::item_handle to the item in the item named @a item_name
const item_handle operator[](std::string_view item_name) const
{
return empty() ? item_handle::s_null_item : item_handle(get_column_ix(column_name), const_cast<row_handle &>(*this));
return empty() ? item_handle::s_null_item : item_handle(get_item_ix(item_name), const_cast<row_handle &>(*this));
}
/// \brief Return an object that can be used in combination with cif::tie
/// 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 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 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 as<T>();
}
/// \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 as<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 item named @a name
*
* If updateLinked it true, linked records are updated as well.
* 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.
*
* If validate is true, which is default, the assigned value is
* 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)
{
assign(add_column(name), value, updateLinked, validate);
assign(add_item(name), value, updateLinked, validate);
}
void assign(uint16_t column, std::string_view value, bool updateLinked, bool validate = true);
/** \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 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.
*
* If validate is true, which is default, the assigned value is
* checked to see if it conforms to the rules defined in the dictionary
*/
void assign(uint16_t item, std::string_view 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; }
/// \brief compare two rows
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()
{
@@ -259,7 +361,7 @@ class row_handle
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;
@@ -267,9 +369,17 @@ class row_handle
// --------------------------------------------------------------------
/**
* @brief The class row_initializer is a list of cif::item's.
*
* This class is used to construct new rows, it allows to
* group a list of item name and value pairs and pass it
* in one go to the constructing function.
*/
class row_initializer : public std::vector<item>
{
public:
/** @cond */
friend class category;
row_initializer() = default;
@@ -278,26 +388,38 @@ class row_initializer : public std::vector<item>
row_initializer &operator=(const row_initializer &) = default;
row_initializer &operator=(row_initializer &&) = default;
/** @endcond */
/// \brief constructor taking a std::initializer_list of items
row_initializer(std::initializer_list<item> items)
: std::vector<item>(items)
{
}
/// \brief constructor taking a range of items
template <typename ItemIter, std::enable_if_t<std::is_same_v<typename ItemIter::value_type, item>, int> = 0>
row_initializer(ItemIter b, ItemIter e)
: std::vector<item>(b, e)
{
}
/// \brief constructor taking the values of an existing row
row_initializer(row_handle rh);
/// \brief set the value for item name @a name to @a value
void set_value(std::string_view name, std::string_view value);
/// \brief set the value for item based on @a i
void set_value(const item &i)
{
set_value(i.name(), i.value());
}
/// \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);
/// \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)
{
set_value_if_empty(i.name(), i.value());

View File

@@ -38,15 +38,18 @@
#include <compare>
#endif
/// \file cif++/symmetry.hpp
/// This file contains code to do symmetry operations based on the
/// operations as specified in the International Tables.
/** \file cif++/symmetry.hpp
*
* This file contains code to do symmetry operations based on the
* operations as specified in the International Tables.
*/
namespace cif
{
// --------------------------------------------------------------------
/// \brief Apply matrix transformation @a m on point @a pt and return the result
inline point operator*(const matrix3x3<float> &m, const point &pt)
{
return {
@@ -58,28 +61,40 @@ inline point operator*(const matrix3x3<float> &m, const point &pt)
// --------------------------------------------------------------------
/// \brief the space groups we know
enum class space_group_name
{
full,
xHM,
Hall
full, ///< The *full* spacegroup
xHM, ///< The *xHM* spacegroup
Hall ///< The *Hall* spacegroup
};
/// \brief For each known spacegroup we define a structure like this
struct space_group
{
const char *name;
const char *xHM;
const char *Hall;
int nr;
const char *name; ///< The name according to *full*
const char *xHM; ///< The name according to *xHM*
const char *Hall; ///< The name according to *Hall*
int nr; ///< The number for this spacegroup
};
/// \brief Global list of spacegroups
extern CIFPP_EXPORT const space_group kSpaceGroups[];
/// \brief Global for the size of the list of spacegroups
extern CIFPP_EXPORT const std::size_t kNrOfSpaceGroups;
// --------------------------------------------------------------------
/**
* @brief Helper class to efficiently pack the data that
* makes up a symmetry operation
*
*/
struct symop_data
{
/// \brief constructor
constexpr symop_data(const std::array<int, 15> &data)
: m_packed((data[0] bitand 0x03ULL) << 34 bitor
(data[1] bitand 0x03ULL) << 32 bitor
@@ -99,27 +114,32 @@ struct symop_data
{
}
/// \brief compare
bool operator==(const symop_data &rhs) const
{
return m_packed == rhs.m_packed;
}
/// \brief sorting order
bool operator<(const symop_data &rhs) const
{
return m_packed < rhs.m_packed;
}
/// \brief return an int representing the value stored in the two bits at offset @a offset
inline constexpr int unpack3(int offset) const
{
int result = (m_packed >> offset) bitand 0x03;
return result == 3 ? -1 : result;
}
/// \brief return an int representing the value stored in the three bits at offset @a offset
inline constexpr int unpack7(int offset) const
{
return (m_packed >> offset) bitand 0x07;
}
/// \brief return an array of 15 ints representing the values stored
constexpr std::array<int, 15> data() const
{
return {
@@ -154,8 +174,14 @@ struct symop_data
uint64_t m_packed;
};
/**
* @brief For each symmetry operator defined in the international tables
* we have an entry in this struct type. It contains the spacegroup
* number, the symmetry operations and the rotational number.
*/
struct symop_datablock
{
/// \brief constructor
constexpr symop_datablock(int spacegroup, int rotational_number, const std::array<int, 15> &rt_data)
: m_v((spacegroup bitand 0xffffULL) << 48 bitor
(rotational_number bitand 0xffULL) << 40 bitor
@@ -163,9 +189,9 @@ struct symop_datablock
{
}
uint16_t spacegroup() const { return m_v >> 48; }
symop_data symop() const { return symop_data(m_v); }
uint8_t rotational_number() const { return (m_v >> 40) bitand 0xff; }
uint16_t spacegroup() const { return m_v >> 48; } ///< Return the spacegroup
symop_data symop() const { return symop_data(m_v); } ///< Return the symmetry operation
uint8_t rotational_number() const { return (m_v >> 40) bitand 0xff; } ///< Return the rotational_number
private:
uint64_t m_v;
@@ -173,7 +199,10 @@ struct symop_datablock
static_assert(sizeof(symop_datablock) == sizeof(uint64_t), "Size of symop_data is wrong");
/// \brief Global containing the list of known symmetry operations
extern CIFPP_EXPORT const symop_datablock kSymopNrTable[];
/// \brief Size of the list of known symmetry operations
extern CIFPP_EXPORT const std::size_t kSymopNrTableSize;
// --------------------------------------------------------------------
@@ -186,13 +215,21 @@ class spacegroup;
class rtop;
struct sym_op;
/** @brief A class that encapsulates the symmetry operations as used in PDB files,
* i.e. a rotational number and a translation vector.
*
* The syntax in string format follows the syntax as used in mmCIF files, i.e.
* rotational number followed by underscore and the three translations where 5 is
* no movement.
*
* So the string 1_555 means no symmetry movement at all since the rotational number
* 1 always corresponds to the symmetry operation [x, y, z].
*/
/// @brief A class that encapsulates the symmetry operations as used in PDB files, i.e. a rotational number and a translation vector
/// The syntax in string format follows the syntax as used in mmCIF files, i.e. rotational number followed by underscore and the
/// three translations where 5 is no movement.
struct sym_op
{
public:
/// \brief constructor
sym_op(uint8_t nr = 1, uint8_t ta = 5, uint8_t tb = 5, uint8_t tc = 5)
: m_nr(nr)
, m_ta(ta)
@@ -201,48 +238,69 @@ struct sym_op
{
}
/// \brief construct a sym_op based on the contents encoded in string @a s
explicit sym_op(std::string_view s);
/** @cond */
sym_op(const sym_op &) = default;
sym_op(sym_op &&) = default;
sym_op &operator=(const sym_op &) = default;
sym_op &operator=(sym_op &&) = default;
/** @endcond */
/// \brief return true if this sym_op is the identity operator
constexpr bool is_identity() const
{
return m_nr == 1 and m_ta == 5 and m_tb == 5 and m_tc == 5;
}
/// \brief quick test for unequal to identity
explicit constexpr operator bool() const
{
return not is_identity();
}
/// \brief return the content encoded in a string
std::string string() const;
#if defined(__cpp_impl_three_way_comparison)
/// \brief a default spaceship operator
constexpr auto operator<=>(const sym_op &rhs) const = default;
#else
/// \brief a default equals operator
constexpr bool operator==(const sym_op &rhs) const
{
return m_nr == rhs.m_nr and m_ta == rhs.m_ta and m_tb == rhs.m_tb and m_tc == rhs.m_tc;
}
/// \brief a default not-equals operator
constexpr bool operator!=(const sym_op &rhs) const
{
return not operator==(rhs);
}
#endif
/// @cond
uint8_t m_nr;
uint8_t m_ta, m_tb, m_tc;
/// @endcond
};
static_assert(sizeof(sym_op) == 4, "Sym_op should be four bytes");
namespace literals
{
inline sym_op operator""_symop(const char *text, size_t length)
/**
* @brief This operator allows you to write code like this:
*
* @code {.cpp}
* using namespace cif::literals;
*
* cif::sym_op so = "1_555"_symop;
* @endcode
*
*/
inline sym_op operator""_symop(const char *text, std::size_t length)
{
return sym_op({ text, length });
}
@@ -251,17 +309,33 @@ namespace literals
// --------------------------------------------------------------------
// The transformation class
/**
* @brief A class you can use to apply symmetry transformations on points
*
* Transformations consist of two operations, a matrix transformation which
* is often a rotation followed by a translation.
*
* In case the matrix transformation is a pure rotation a quaternion
* is created to do the actual calculations. That's faster and more
* precise.
*/
class transformation
{
public:
/// \brief constructor taking a symop_data object @a data
transformation(const symop_data &data);
/// \brief constructor taking a rotation matrix @a r and a translation vector @a t
transformation(const matrix3x3<float> &r, const cif::point &t);
/** @cond */
transformation(const transformation &) = default;
transformation(transformation &&) = default;
transformation &operator=(const transformation &) = default;
transformation &operator=(transformation &&) = default;
/** @endcond */
/// \brief operator() to perform the transformation on point @a pt and return the result
point operator()(point pt) const
{
if (m_q)
@@ -272,9 +346,13 @@ class transformation
return pt + m_translation;
}
/// \brief return a transformation object that is the result of applying @a rhs after @a lhs
friend transformation operator*(const transformation &lhs, const transformation &rhs);
/// \brief return the inverse transformation for @a t
friend transformation inverse(const transformation &t);
/// \brief return the inverse tranformation for this
transformation operator-() const
{
return inverse(*this);
@@ -283,7 +361,6 @@ class transformation
friend class spacegroup;
private:
// Most rotation matrices provided by the International Tables
// are really rotation matrices, in those cases we can construct
// a quaternion. Unfortunately, that doesn't work for all of them
@@ -298,22 +375,32 @@ class transformation
// --------------------------------------------------------------------
// class cell
/**
* @brief The cell class describes the dimensions and angles of a unit cell
* in a crystal
*/
class cell
{
public:
/// \brief constructor
cell(float a, float b, float c, float alpha = 90.f, float beta = 90.f, float gamma = 90.f);
/// \brief constructor that takes the appropriate values from the *cell* category in datablock @a db
cell(const datablock &db);
float get_a() const { return m_a; }
float get_b() const { return m_b; }
float get_c() const { return m_c; }
float get_a() const { return m_a; } ///< return dimension a
float get_b() const { return m_b; } ///< return dimension b
float get_c() const { return m_c; } ///< return dimension c
float get_alpha() const { return m_alpha; }
float get_beta() const { return m_beta; }
float get_gamma() const { return m_gamma; }
float get_alpha() const { return m_alpha; } ///< return angle alpha
float get_beta() const { return m_beta; } ///< return angle beta
float get_gamma() const { return m_gamma; } ///< return angle gamma
matrix3x3<float> get_orthogonal_matrix() const { return m_orthogonal; }
matrix3x3<float> get_fractional_matrix() const { return m_fractional; }
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
private:
void init();
@@ -324,80 +411,112 @@ class cell
// --------------------------------------------------------------------
/// \brief Return the spacegroup number from the *symmetry* category in datablock @a db
int get_space_group_number(const datablock &db);
/// \brief Return the spacegroup number for spacegroup named @a spacegroup
int get_space_group_number(std::string_view spacegroup);
/// \brief Return the spacegroup number for spacegroup named @a spacegroup assuming space_group_name @a type
int get_space_group_number(std::string_view spacegroup, space_group_name type);
/**
* @brief class to encapsulate the list of transformations making up a spacegroup
*
*/
class spacegroup : public std::vector<transformation>
{
public:
/// \brief constructor using the information in the *symmetry* category in datablock @a db
spacegroup(const datablock &db)
: spacegroup(get_space_group_number(db))
{
}
/// \brief constructor using the spacegroup named @a name
spacegroup(std::string_view name)
: spacegroup(get_space_group_number(name))
{
}
/// \brief constructor using the spacegroup named @a name assuming space_group_name @a type
spacegroup(std::string_view name, space_group_name type)
: spacegroup(get_space_group_number(name, type))
{
}
/// \brief constructor using the spacegroup number @a nr
spacegroup(int nr);
int get_nr() const { return m_nr; }
std::string get_name() const;
int get_nr() const { return m_nr; } ///< Return the nr
std::string get_name() const; ///< Return the name
/** \brief perform a spacegroup operation on point @a pt using
* cell @a c and sym_op @a symop
*/
point operator()(const point &pt, const cell &c, sym_op symop) const;
/** \brief perform an inverse spacegroup operation on point @a pt using
* cell @a c and sym_op @a symop
*/
point inverse(const point &pt, const cell &c, sym_op symop) const;
private:
int m_nr;
size_t m_index;
std::size_t m_index;
};
// --------------------------------------------------------------------
// A crystal combines a cell and a spacegroup.
/**
* @brief A crystal combines a cell and a spacegroup.
*
* The information in cell and spacegroup together make up all
* information you need to do symmetry calculations in a crystal
*/
class crystal
{
public:
/// \brief constructor using the information found in datablock @a db
crystal(const datablock &db)
: m_cell(db)
, m_spacegroup(db)
{
}
/// \brief constructor using cell @a c and spacegroup @a sg
crystal(const cell &c, const spacegroup &sg)
: m_cell(c)
, m_spacegroup(sg)
{
}
/** @cond */
crystal(const crystal &) = default;
crystal(crystal &&) = default;
crystal &operator=(const crystal &) = default;
crystal &operator=(crystal &&) = default;
/** @endcond */
const cell &get_cell() const { return m_cell; }
const spacegroup &get_spacegroup() const { return m_spacegroup; }
const cell &get_cell() const { return m_cell; } ///< Return the cell
const spacegroup &get_spacegroup() const { return m_spacegroup; } ///< Return the spacegroup
/// \brief Return the symmetry copy of point @a pt using symmetry operation @a symop
point symmetry_copy(const point &pt, sym_op symop) const
{
return m_spacegroup(pt, m_cell, symop);
}
/// \brief Return the symmetry copy of point @a pt using the inverse of symmetry operation @a symop
point inverse_symmetry_copy(const point &pt, sym_op symop) const
{
return m_spacegroup.inverse(pt, m_cell, symop);
}
std::tuple<float,point,sym_op> closest_symmetry_copy(point a, point b) const;
/// \brief Return a tuple consisting of distance, new location and symmetry operation
/// for the point @a b with respect to point @a a.
std::tuple<float, point, sym_op> closest_symmetry_copy(point a, point b) const;
private:
cell m_cell;
@@ -407,11 +526,13 @@ class crystal
// --------------------------------------------------------------------
// Symmetry operations on points
/// \brief convenience function returning the fractional point @a pt in orthogonal coordinates for cell @a c
inline point orthogonal(const point &pt, const cell &c)
{
return c.get_orthogonal_matrix() * pt;
}
/// \brief convenience function returning the orthogonal point @a pt in fractional coordinates for cell @a c
inline point fractional(const point &pt, const cell &c)
{
return c.get_fractional_matrix() * pt;

View File

@@ -38,12 +38,47 @@
#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
*/
namespace cif
{
@@ -52,18 +87,40 @@ namespace cif
// some basic utilities: Since we're using ASCII input only, we define for optimisation
// our own case conversion routines.
/// \brief return whether string @a is equal to string @a b ignoring changes in character case
bool iequals(std::string_view a, std::string_view b);
/// \brief compare string @a is to string @a b ignoring changes in character case
int icompare(std::string_view a, std::string_view b);
/// \brief return whether string @a is equal to string @a b ignoring changes in character case
bool iequals(const char *a, const char *b);
/// \brief compare string @a is to string @a b ignoring changes in character case
int icompare(const char *a, const char *b);
/// \brief convert the string @a s to lower case in situ
void to_lower(std::string &s);
/// \brief return a lower case copy of string @a s
std::string to_lower_copy(std::string_view s);
/// \brief convert the string @a s to upper case in situ
void to_upper(std::string &s);
// std::string toUpperCopy(const 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)
{
@@ -91,12 +148,41 @@ std::string join(IterType b, IterType e, std::string_view sep)
return s.str();
}
/**
* @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)
{
return join(arr.begin(), arr.end(), 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)
{
@@ -124,15 +210,23 @@ std::vector<StringType> split(std::string_view s, std::string_view separators, b
return result;
}
/**
* @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.
*/
void replace_all(std::string &s, std::string_view what, std::string_view with = {});
#if defined(__cpp_lib_starts_ends_with)
/// \brief return whether string @a s starts with @a with
inline bool starts_with(std::string s, std::string_view with)
{
return s.starts_with(with);
}
/// \brief return whether string @a s ends with @a with
inline bool ends_with(std::string_view s, std::string_view with)
{
return s.ends_with(with);
@@ -140,11 +234,13 @@ inline bool ends_with(std::string_view s, std::string_view with)
#else
/// \brief return whether string @a s starts with @a with
inline bool starts_with(std::string s, std::string_view with)
{
return s.compare(0, with.length(), with) == 0;
}
/// \brief return whether string @a s ends with @a with
inline bool ends_with(std::string_view s, std::string_view with)
{
return s.length() >= with.length() and s.compare(s.length() - with.length(), with.length(), with) == 0;
@@ -154,6 +250,7 @@ inline bool ends_with(std::string_view s, std::string_view with)
#if defined(__cpp_lib_string_contains)
/// \brief return whether string @a s contains @a q
inline bool contains(std::string_view s, std::string_view q)
{
return s.contains(q);
@@ -161,6 +258,7 @@ inline bool contains(std::string_view s, std::string_view q)
#else
/// \brief return whether string @a s contains @a q
inline bool contains(std::string_view s, std::string_view q)
{
return s.find(q) != std::string_view::npos;
@@ -168,33 +266,50 @@ inline bool contains(std::string_view s, std::string_view q)
#endif
/// \brief return whether string @a s contains @a q ignoring character case
bool icontains(std::string_view s, std::string_view q);
/// \brief trim white space at the start of string @a s in situ
void trim_left(std::string &s);
/// \brief trim white space at the end of string @a s in situ
void trim_right(std::string &s);
/// \brief trim white space at both the start and the end of string @a s in situ
void trim(std::string &s);
/// \brief return a string trimmed of white space at the start of string @a s
std::string trim_left_copy(std::string_view s);
/// \brief return a string trimmed of white space at the end of string @a s
std::string trim_right_copy(std::string_view s);
/// \brief return a string trimmed of white space at both the start and the end of string @a s
std::string trim_copy(std::string_view s);
// To make life easier, we also define iless and iset using iequals
/// \brief an operator object you can use to compare strings ignoring their character case
struct iless
{
/// \brief return the result of icompare for @a a and @a b
bool operator()(const std::string &a, const std::string &b) const
{
return icompare(a, b) < 0;
}
};
typedef std::set<std::string, iless> iset;
/// iset is a std::set of std::string but with a comparator that
/// ignores character case.
using iset = std::set<std::string, iless>;
// --------------------------------------------------------------------
// This really makes a difference, having our own tolower routines
/// \brief global list containing the lower case version of each ASCII character
extern CIFPP_EXPORT const uint8_t kCharToLowerMap[256];
/// \brief a very fast tolower implementation
inline char tolower(int ch)
{
return static_cast<char>(kCharToLowerMap[static_cast<uint8_t>(ch)]);
@@ -202,245 +317,47 @@ inline char tolower(int ch)
// --------------------------------------------------------------------
std::tuple<std::string, std::string> split_tag_name(std::string_view 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.
*/
[[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);
// --------------------------------------------------------------------
// generate a cif name, mainly used to generate asym_id's
/// \brief generate a cif name, used e.g. to generate asym_id's
std::string cif_id_for_number(int number);
// --------------------------------------------------------------------
// custom wordwrapping routine
std::vector<std::string> word_wrap(const std::string &text, size_t width);
/** \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, std::size_t width);
// --------------------------------------------------------------------
/// std::from_chars for floating point types.
/// These are optional, there's a selected_charconv class below that selects
/// the best option to used 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;
}
enum class chars_format
{
scientific = 1,
fixed = 2,
// hex,
general = fixed | scientific
};
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;
}
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;
}
template <typename T>
struct my_charconv
{
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
{
return cif::from_chars(a, b, d);
}
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
{
return cif::to_chars(first, last, value, fmt);
}
};
using from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<T &>()));
template <typename T>
struct std_charconv
@@ -449,17 +366,24 @@ struct std_charconv
{
return std::from_chars(a, b, d);
}
};
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
{
return std::to_chars(first, last, value, fmt);
}
template <typename T, typename = void>
struct ff_charconv;
template <typename 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 from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<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>
using selected_charconv = typename std::conditional_t<std::experimental::is_detected_v<from_chars_function, T>, std_charconv<T>, my_charconv<T>>;
constexpr auto from_chars(const char *s, const char *e, T &v)
{
return charconv<T>::from_chars(s, e, v);
}
} // namespace cif

View File

@@ -1,17 +1,17 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
*
* Copyright (c) 2020 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
@@ -29,11 +29,18 @@
#include "cif++/exports.hpp"
#include <filesystem>
#include <iostream>
#ifndef STDOUT_FILENO
/// @brief For systems that lack this value
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
/// @brief For systems that lack this value
#define STDERR_FILENO 2
#endif
#if _WIN32
#include <io.h>
#define isatty _isatty
@@ -46,127 +53,254 @@
#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
/** \file utilities.hpp
*
* This file contains code that is very generic in nature like a progress_bar
* and classes you can use to colourise output text.
*/
namespace cif
{
/**
* @brief The global variable VERBOSE contains the level of verbosity
* requested. A value of 0 is normal, with some output on error conditions.
* A value > 0 will result in more output, the higher the value, the more
* output. A value < 0 will make the library silent, even in error
* conditions.
*/
extern CIFPP_EXPORT int VERBOSE;
// the git 'build' number
/// return the git 'build' number
std::string get_version_nr();
// --------------------------------------------------------------------
// Code helping with terminal i/o
/// return the width of the current output terminal, or 80 if it cannot be determined
uint32_t get_terminal_width();
// --------------------------------------------------------------------
// Path of the current executable
std::string get_executable_path();
// --------------------------------------------------------------------
// some manipulators to write coloured text to terminals
enum StringColour
namespace colour
{
scBLACK = 0,
scRED,
scGREEN,
scYELLOW,
scBLUE,
scMAGENTA,
scCYAN,
scWHITE,
scNONE = 9
};
template <typename String, typename CharT>
struct ColouredString
{
static_assert(std::is_reference<String>::value or std::is_pointer<String>::value, "String type must be pointer or reference");
ColouredString(String s, StringColour fore, StringColour back, bool bold = true)
: m_s(s)
, m_fore(fore)
, m_back(back)
, m_bold(bold)
/// @brief The defined colours
enum colour_type
{
}
black = 0,
red,
green,
yellow,
blue,
magenta,
cyan,
white,
none = 9
};
ColouredString &operator=(const ColouredString &) = delete;
String m_s;
StringColour m_fore, m_back;
bool m_bold;
};
template <typename CharT, typename Traits>
std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os, const ColouredString<const CharT *, CharT> &s)
{
if (isatty(STDOUT_FILENO))
/// @brief The defined styles
enum style_type
{
std::basic_ostringstream<CharT, Traits> ostr;
ostr << "\033[" << (30 + s.m_fore) << ';' << (s.m_bold ? "1" : "22") << ';' << (40 + s.m_back) << 'm'
<< s.m_s
<< "\033[0m";
bold = 1,
underlined = 4,
blink = 5,
inverse = 7,
regular = 22,
};
return os << ostr.str();
}
else
return os << s.m_s;
}
template <typename CharT, typename Traits, typename String>
std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os, const ColouredString<String, CharT> &s)
{
if (isatty(STDOUT_FILENO))
namespace detail
{
std::basic_ostringstream<CharT, Traits> ostr;
ostr << "\033[" << (30 + s.m_fore) << ';' << (s.m_bold ? "1" : "22") << ';' << (40 + s.m_back) << 'm'
<< s.m_s
<< "\033[0m";
/**
* @brief Struct for delimited strings.
*/
struct coloured_string_t
{
/**
* @brief Construct a new coloured string t object
*/
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)
, m_style(static_cast<int>(st))
{
}
return os << ostr.str();
}
else
return os << s.m_s;
}
coloured_string_t &operator=(coloured_string_t &) = delete;
template <typename CharT>
inline auto coloured(const CharT *s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
/**
* @brief Write out the string, either coloured or not
*/
template <typename char_type, typename traits_type>
friend std::basic_ostream<char_type, traits_type> &operator<<(
std::basic_ostream<char_type, traits_type> &os, const coloured_string_t &cs)
{
bool use_colour = false;
if (os.rdbuf() == std::cout.rdbuf() and isatty(STDOUT_FILENO))
use_colour = true;
else if (os.rdbuf() == std::cerr.rdbuf() and isatty(STDERR_FILENO))
use_colour = true;
if (use_colour)
{
os << "\033[" << cs.m_fore_colour << ';' << cs.m_style << ';' << cs.m_back_colour << 'm'
<< cs.m_str
<< "\033[0m";
}
else
os << cs.m_str;
return os;
}
/// @cond
std::string_view m_str;
int m_fore_colour, m_back_colour;
int m_style;
/// @endcond
};
} // namespace detail
} // namespace colour
/**
* @brief Manipulator for coloured strings.
*
* When writing out text to the terminal it is often useful to have
* some of the text colourised. But only if the output is really a
* terminal since colouring text is done using escape sequences
* an if output is redirected to a file, these escape sequences end up
* in the file making the real text less easy to read.
*
* The code presented here is rather basic. It mimics the std::quoted
* manipulator in that it will colour a string with optionally
* requested colours and text style.
*
* Example:
*
* @code {.cpp}
* using namespace cif::colour;
* std::cout << cif::coloured("Hello, world!", white, red, bold) << '\n';
* @endcode
* @param str String to quote.
* @param fg Foreground (=text) colour to use
* @param bg Background colour to use
* @param st Text style to use
*/
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 ColouredString<const CharT *, CharT>(s, fore, back, bold);
}
template <typename CharT, typename Traits, typename Alloc>
inline auto coloured(const std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
{
return ColouredString<const std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold);
}
template <typename CharT, typename Traits, typename Alloc>
inline auto coloured(std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
{
return ColouredString<std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold);
return colour::detail::coloured_string_t(str, fg, bg, st);
}
// --------------------------------------------------------------------
// A progress bar
/**
* @brief A simple progress bar class for terminal based output
*
* Using a progress bar is very convenient for the end user when
* you have long running code. It gives feed back on how fast an
* operation is performed and may give an indication how long it
* will take before it is finished.
*
* Using this cif::progress_bar implementation is straightforward:
*
* @code {.cpp}
* using namespace std::chrono_literals;
*
* cif::progress_bar pb(10, "counting to ten");
*
* for (int i = 1; i <= 10; ++i)
* {
* pb.consumed(1);
* std::this_thread::sleep_for(1s);
* }
*
* @endcode
*
* When the progress_bar is created, it first checks
* to see if stdout is to a real TTY and if the VERBOSE
* flag is not less than zero (quiet mode). If this passes
* a thread is started that waits for updates.
*
* The first two seconds, nothing is written to the screen
* so if the work is finished within those two seconds
* the screen stays clean.
*
* After this time, a progress bar is printed that may look
* like this:
*
* @code
* step 3 ========================-------------------------------- 40% ⢁
* @endcode
*
* The first characters contain the initial action name or
* the message text if it was used afterwards.
*
* The thermometer is made up with '=' and '-' characters.
*
* A percentage is also shown and at the end there is a spinner
* that gives feedback that the program is really still working.
*
* The progress bar is removed if the max has been reached
* or if the progress bar is destructed. If any output has
* been generated, the initial action is printed out along
* with the total time spent.
*/
class progress_bar
{
public:
/**
* @brief Construct a new progress bar object
*
* Progress ranges from 0 (zero) to @a inMax
*
* The action in @a inAction is used for display
*
* @param inMax The maximum value
* @param inAction The description of what is
* going on
*/
progress_bar(int64_t inMax, const std::string &inAction);
/**
* @brief Destroy the progress bar object
*
*/
~progress_bar();
/**
* @brief Notify the progress bar that @a inConsumed
* should be added to the internal progress counter
*/
void consumed(int64_t inConsumed); // consumed is relative
/**
* @brief Notify the progress bar that the internal
* progress counter should be updated to @a inProgress
*/
void progress(int64_t inProgress); // progress is absolute
/**
* @brief Replace the action string in the progress bar
* with @a inMessage
*/
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;
@@ -177,8 +311,66 @@ class progress_bar
// --------------------------------------------------------------------
// Resources
/**
* @brief Load a resource from disk or the compiled in resources
*
* @verbatim embed:rst
.. note::
See the :doc:`documentation on resources </resources>` for more information.
@endverbatim
*
* @param name The named resource to load
* @return std::unique_ptr<std::istream> A pointer to the std::istream or empty if not found
*/
std::unique_ptr<std::istream> load_resource(std::filesystem::path name);
/**
* @brief Add a file specified by @a dataFile as the data for resource @a name
*
* @verbatim embed:rst
.. note::
See the :doc:`documentation on resources </resources>` for more information.
@endverbatim
*
* @param name The name of the resource to specify
* @param dataFile Path to a file containing the data
*/
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.
*
* @verbatim embed:rst
.. note::
See the :doc:`documentation on resources </resources>` for more information.
@endverbatim
*/
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

View File

@@ -26,190 +26,480 @@
#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>
/**
* @file validate.hpp
*
* Support for validating mmCIF files based on a dictionary. These dictionaries
* contain information about the categories and items therein, what they may
* contain and how this should be formatted. There's also information on links
* between parent and child categories.
*
*/
namespace cif
{
class category;
struct category_validator;
// --------------------------------------------------------------------
// New: error_code
class validation_error : public std::exception
/**
* @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_category_impl : public std::error_category
{
public:
validation_error(const std::string &msg);
validation_error(const std::string &cat, const std::string &item,
const std::string &msg);
const char *what() const noexcept { return m_msg.c_str(); }
std::string m_msg;
/**
* @brief User friendly name
*
* @return const char*
*/
const char *name() const noexcept override
{
return "cif::validation";
}
/**
* @brief Provide the error message as a string for the error code @a ev
*
* @param ev The error code
* @return std::string
*/
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);
};
// --------------------------------------------------------------------
/** @brief the primitive types known */
enum class DDL_PrimitiveType
{
Char,
UChar,
Numb
Char, ///< Text
UChar, ///< Text that is compared ignoring the character case
Numb ///< Nummeric values
};
/// @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;
/**
* @brief For each defined type in a dictionary a type_validator is created
*
* A type validator can check if the contents of an item are conforming the
* specification. The check is done using regular expressions.
*
* A type_validator can also be used to compare two values that conform to
* this type. Comparison is of course based on the primitive type.
*
*/
struct type_validator
{
std::string m_name;
DDL_PrimitiveType m_primitive_type;
regex_impl *m_rx;
std::string m_name; ///< The name of the type
DDL_PrimitiveType m_primitive_type; ///< The primitive_type of 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(const type_validator &tv);
/// @brief Move 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);
swap(*this, rhs);
}
type_validator &operator=(const type_validator &) = delete;
type_validator &operator=(type_validator &&rhs)
/// @brief Move constructor
type_validator &operator=(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);
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
{
return icompare(m_name, rhs.m_name) < 0;
}
/// @brief Compare the contents of @a a and @a b based on the
/// primitive type of this type. A value of zero indicates the
/// values are equal. Less than zero means @a a sorts before @a b
/// and a value larger than zero likewise means the opposite
int compare(std::string_view a, std::string_view b) const;
};
struct item_validator
/** @brief Item alias, items can be renamed over time
*/
struct item_alias
{
std::string m_tag;
bool m_mandatory;
const type_validator *m_type;
cif::iset m_enums;
std::string m_default;
bool m_default_is_null;
category_validator *m_category = nullptr;
// ItemLinked is used for non-key links
struct item_link
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_validator *m_parent;
std::string m_parent_item;
std::string m_child_item;
};
std::vector<item_link> mLinked;
bool operator<(const item_validator &rhs) const
{
return icompare(m_tag, rhs.m_tag) < 0;
}
bool operator==(const item_validator &rhs) const
{
return iequals(m_tag, rhs.m_tag);
}
item_alias(const item_alias &) = default;
item_alias &operator=(const item_alias &) = default;
void operator()(std::string_view value) const;
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.
*
* mmCIF dictionaries may indicate an item is e.g. mandatory or
* consists of a certain list of allowed values. Even default
* values can be provided.
*
*/
struct item_validator
{
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_item_name, rhs.m_item_name) < 0;
}
/// @brief Compare based on the name
bool operator==(const item_validator &rhs) const
{
return iequals(m_item_name, rhs.m_item_name);
}
/// @brief Validate the value in @a value for this item
/// Will throw a std::system_error exception if it fails
void operator()(std::string_view value) const;
/// @brief A more gentle version of value validation
bool validate_value(std::string_view value, std::error_code &ec) const noexcept;
};
/**
* @brief A validator for categories
*
* Categories can have a key, a set of items that in combination
* should be unique.
*/
struct category_validator
{
std::string m_name;
std::vector<std::string> m_keys;
cif::iset m_groups;
cif::iset m_mandatory_fields;
std::set<item_validator> m_item_validators;
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_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
bool operator<(const category_validator &rhs) const
{
return icompare(m_name, rhs.m_name) < 0;
}
void addItemValidator(item_validator &&v);
/// @brief Add item_validator @a v to the list of item validators
void add_item_validator(item_validator &&v);
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;
const std::set<item_validator> &item_validators() const
{
return m_item_validators;
}
/// @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;
};
/**
* @brief A validator for links between categories
*
* Links are defined as a set of pairs of item names in a
* parent category and a corresponding item in a child
* category. This means that the size of m_parent_keys
* is always equal to the size of m_child_keys.
*
* Multiple links may be defined between two categories.
*
*/
struct link_validator
{
int m_link_group_id;
std::string m_parent_category;
std::vector<std::string> m_parent_keys;
std::string m_child_category;
std::vector<std::string> m_child_keys;
std::string m_link_group_label;
int m_link_group_id; ///< The link group ID
std::string m_parent_category; ///< The name of the parent category
std::vector<std::string> m_parent_keys; ///< The items in the parent category making up the set of linked items
std::string m_child_category; ///< The name of the child category
std::vector<std::string> m_child_keys; ///< The items in the child category making up the set of linked items
std::string m_link_group_label; ///< The group label assigned to this link
};
// --------------------------------------------------------------------
/**
* @brief The validator class combines all the link, category and item validator classes
*
*/
class validator
{
public:
validator(std::string_view name)
: m_name(name)
/**
* @brief Construct a new validator object
*
* @param name The name of the underlying dictionary
*/
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);
validator(validator &&rhs) = default;
validator &operator=(validator &&rhs) = default;
/// @brief move constructor
validator(validator &&rhs)
{
swap(*this, rhs);
}
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);
/// @brief Return the type validator for @a type_code, may return nullptr
const type_validator *get_validator_for_type(std::string_view type_code) const;
/// @brief Add category_validator @a v to the list of category validators
void add_category_validator(category_validator &&v);
/// @brief Return the category validator for @a category, may return nullptr
const category_validator *get_validator_for_category(std::string_view category) const;
/// @brief Add link_validator @a v to the list of link validators
void add_link_validator(link_validator &&v);
/// @brief Return the list of link validators for which the parent is @a category
std::vector<const link_validator *> get_links_for_parent(std::string_view category) const;
/// @brief Return the list of link validators for which the child is @a category
std::vector<const link_validator *> get_links_for_child(std::string_view category) const;
void report_error(const std::string &msg, bool fatal) const;
/// @brief Bottleneck function to report an error in validation
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; }
void set_name(const std::string &name) { m_name = name; }
/// @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; }
void version(const std::string &version) { m_version = version; }
/// @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;
@@ -217,25 +507,40 @@ class validator
};
// --------------------------------------------------------------------
/**
* @brief Validators are globally unique objects, use the validator_factory
* class to construct them. This class is a singleton.
*/
class validator_factory
{
public:
static validator_factory &instance()
/// @brief Return the singleton 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));
}
const validator &operator[](std::string_view dictionary_name);
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;
};

View File

@@ -1,13 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
datalibdir=@datarootdir@/libcifpp
Name: libcifpp
Description: C++ library for the manipulation of mmCIF files.
Version: @PACKAGE_VERSION@
Requires: zlib
Libs: -L${libdir} -lcifpp
Cflags: -I${includedir} -pthread

316
pcre2-simple/CMakeLists.txt Normal file
View 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()

View File

@@ -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()

View File

@@ -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.

View File

@@ -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

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

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