mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 22:14:24 +08:00
Compare commits
1347 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eaa5032e11 | ||
|
|
8400247674 | ||
|
|
08e1b197ac | ||
|
|
20971e1ee9 | ||
|
|
ce6a953eff | ||
|
|
87c20c26ec | ||
|
|
025ad93d06 | ||
|
|
e98fe2608a | ||
|
|
0399d99ca6 | ||
|
|
71b24a678e | ||
|
|
dc03cb6a70 | ||
|
|
de9b33a918 | ||
|
|
56c75490f2 | ||
|
|
20695404c1 | ||
|
|
46ea0ca930 | ||
|
|
0da8ba85bf | ||
|
|
5d3734e2a5 | ||
|
|
e692ed6c87 | ||
|
|
da8e81f871 | ||
|
|
0aef601bfd | ||
|
|
39644c1bd1 | ||
|
|
421758a01c | ||
|
|
a3a0e5cc70 | ||
|
|
9268aa3cfc | ||
|
|
187d7fc314 | ||
|
|
6df8b435ec | ||
|
|
399827db41 | ||
|
|
57aaf36bde | ||
|
|
a804f6d107 | ||
|
|
0ab75e866e | ||
|
|
a092760c1e | ||
|
|
ac1eaa7ca0 | ||
|
|
1d615eeff1 | ||
|
|
d936b67e89 | ||
|
|
5ec523a7c9 | ||
|
|
3fd8d1f507 | ||
|
|
1a7fffd561 | ||
|
|
95ea353c4e | ||
|
|
1e39c43cd2 | ||
|
|
cb109bacc4 | ||
|
|
8e802331c9 | ||
|
|
eabcf437cd | ||
|
|
03e5a05238 | ||
|
|
ebdd556729 | ||
|
|
5860c83306 | ||
|
|
bb6410260e | ||
|
|
3a8527e26d | ||
|
|
3976d9edb6 | ||
|
|
2df904899d | ||
|
|
6eb8857877 | ||
|
|
2f3a755ebd | ||
|
|
9c4256b0f0 | ||
|
|
fdc3972ec0 | ||
|
|
a322d2efb8 | ||
|
|
926b8c1069 | ||
|
|
1e1a5b4cc8 | ||
|
|
3e220e69a7 | ||
|
|
d5fbf05b44 | ||
|
|
3721922174 | ||
|
|
3d7b732090 | ||
|
|
ea890b3942 | ||
|
|
92c335499d | ||
|
|
96f0ae694c | ||
|
|
c3e1c46b63 | ||
|
|
5670417f12 | ||
|
|
da7cb8741b | ||
|
|
f2a28ed2d0 | ||
|
|
c91a9ff509 | ||
|
|
64edb4ddfd | ||
|
|
8bf4399181 | ||
|
|
889de19cd0 | ||
|
|
b7680dcb92 | ||
|
|
43999dfade | ||
|
|
845b549128 | ||
|
|
b019ba9b91 | ||
|
|
7a49d064a1 | ||
|
|
fd0a95221e | ||
|
|
32acd48ce9 | ||
|
|
14be0638c1 | ||
|
|
2a0e52dff6 | ||
|
|
0fe1178bdd | ||
|
|
2f11d6d642 | ||
|
|
a46a31ac52 | ||
|
|
5ad38b4e9c | ||
|
|
702323d83a | ||
|
|
721857629e | ||
|
|
9200acf8f4 | ||
|
|
6c1d60f5a5 | ||
|
|
56cfa09976 | ||
|
|
1c8571f02c | ||
|
|
9cb5981f8d | ||
|
|
06f1a308c3 | ||
|
|
f827682a45 | ||
|
|
1aed6a593c | ||
|
|
098f8f032a | ||
|
|
a539603c4f | ||
|
|
0dc4a34071 | ||
|
|
b969df1194 | ||
|
|
2ef82c794e | ||
|
|
e157eb7700 | ||
|
|
a079543594 | ||
|
|
9f3a0b5c4c | ||
|
|
dd37d87a33 | ||
|
|
03342caf13 | ||
|
|
1e5050b221 | ||
|
|
b34eb21d96 | ||
|
|
656c82838a | ||
|
|
2a265bb5c8 | ||
|
|
7ac0717944 | ||
|
|
f190bdfd64 | ||
|
|
1d430e8c47 | ||
|
|
56aab89176 | ||
|
|
b9bcf07f84 | ||
|
|
e3e7648c5c | ||
|
|
83ee1984d8 | ||
|
|
f9741a27cd | ||
|
|
0b002afb9f | ||
|
|
a58e5a1bfc | ||
|
|
1229652444 | ||
|
|
05197a85c6 | ||
|
|
71cd4958bd | ||
|
|
61965c2391 | ||
|
|
0f60f42f9e | ||
|
|
2e61b330c4 | ||
|
|
964e7620eb | ||
|
|
8a329e7c2d | ||
|
|
8485747377 | ||
|
|
34af410d5e | ||
|
|
8f5b9eb631 | ||
|
|
388eae211e | ||
|
|
f19c6d078e | ||
|
|
73f18a4da2 | ||
|
|
8e2494532e | ||
|
|
2f7f62bdce | ||
|
|
bf9551a994 | ||
|
|
30ff5bea36 | ||
|
|
b6568664ea | ||
|
|
863f010a7c | ||
|
|
da76bbae7c | ||
|
|
e2454a2e79 | ||
|
|
9503a7e9b4 | ||
|
|
20784bdaf5 | ||
|
|
9558085105 | ||
|
|
429c31ae42 | ||
|
|
58ac1ce033 | ||
|
|
23e575858c | ||
|
|
4a31878975 | ||
|
|
9f6e1e245b | ||
|
|
8a8ca9599d | ||
|
|
00b0473438 | ||
|
|
7a9d94bc57 | ||
|
|
a3ba760ab5 | ||
|
|
913abcd1b3 | ||
|
|
510e336306 | ||
|
|
f15a76e29b | ||
|
|
915a147449 | ||
|
|
edf24ca9ff | ||
|
|
ffff2479d2 | ||
|
|
46a9318aa5 | ||
|
|
4a7f48eed8 | ||
|
|
42e66afd92 | ||
|
|
b550e9b027 | ||
|
|
452bb83ce7 | ||
|
|
6eda9aaf36 | ||
|
|
251fb55d6a | ||
|
|
f94e9aece9 | ||
|
|
c565bb96be | ||
|
|
e51f31dc4c | ||
|
|
4e128885d6 | ||
|
|
b37054228d | ||
|
|
815b33fee0 | ||
|
|
97f55c1639 | ||
|
|
89de73eb6f | ||
|
|
75f2ec3792 | ||
|
|
f4d29e8da9 | ||
|
|
b97b2638b8 | ||
|
|
ea8dea8cbd | ||
|
|
bc0222dc0e | ||
|
|
10a6b5649b | ||
|
|
ff2a233156 | ||
|
|
743e2800f8 | ||
|
|
32ac884127 | ||
|
|
bec69f7d07 | ||
|
|
a99215ad6a | ||
|
|
e3d2cbd044 | ||
|
|
5fc965789d | ||
|
|
b4596902aa | ||
|
|
cbf8b52f62 | ||
|
|
4e0fa1c916 | ||
|
|
95b007d38f | ||
|
|
b66f7a30ce | ||
|
|
ec7287c503 | ||
|
|
a41c591f0c | ||
|
|
3a6527cdd5 | ||
|
|
5f21a094c0 | ||
|
|
2203a1855d | ||
|
|
7edd2ecc18 | ||
|
|
1d2953c850 | ||
|
|
dbf59ce622 | ||
|
|
1596db8499 | ||
|
|
bd1fb5c5cd | ||
|
|
da500025c3 | ||
|
|
60eeea9a93 | ||
|
|
1220f01f1e | ||
|
|
ad0a34fe98 | ||
|
|
a7425ff1a0 | ||
|
|
1ce25f86ae | ||
|
|
cd93f72b96 | ||
|
|
23500bd303 | ||
|
|
14b4753b4f | ||
|
|
4c37d5db5f | ||
|
|
fc2c4b4172 | ||
|
|
3ac64de16b | ||
|
|
45eecd72b0 | ||
|
|
d1dd558cda | ||
|
|
d19e2c2196 | ||
|
|
72c7aca074 | ||
|
|
683a1087d0 | ||
|
|
35bc139deb | ||
|
|
45ece2fa0d | ||
|
|
11c98f553f | ||
|
|
28aa9b1036 | ||
|
|
d7b5c0a748 | ||
|
|
065e7f5f18 | ||
|
|
4b1623cfdc | ||
|
|
1de973ddcb | ||
|
|
eecc801203 | ||
|
|
5c50154ea4 | ||
|
|
0fa3d6aa94 | ||
|
|
01f5242bfb | ||
|
|
af6d8d4f71 | ||
|
|
fa8285fc0f | ||
|
|
2e7f6b8337 | ||
|
|
a6a55020eb | ||
|
|
0e84ea454d | ||
|
|
f3bf211d45 | ||
|
|
f5ef44836c | ||
|
|
070124b6e1 | ||
|
|
c8a46fcdd9 | ||
|
|
5306b59fd8 | ||
|
|
90c5df832a | ||
|
|
2aa439d51f | ||
|
|
ac2b68517c | ||
|
|
e56b568c42 | ||
|
|
63c49b2e04 | ||
|
|
559fd18a20 | ||
|
|
beb7585261 | ||
|
|
8b0f92aa9a | ||
|
|
0d8beeae5b | ||
|
|
e3da654e67 | ||
|
|
dc9e151d89 | ||
|
|
7cfaf051ba | ||
|
|
7920491309 | ||
|
|
0ee493a3fb | ||
|
|
7e23bc0c0b | ||
|
|
579f859562 | ||
|
|
752938ca44 | ||
|
|
fce58c02fe | ||
|
|
924f7c1505 | ||
|
|
8944906fd2 | ||
|
|
cb02969604 | ||
|
|
31090c6ec5 | ||
|
|
9e30d2bc1a | ||
|
|
93d703f7a1 | ||
|
|
3c241048a5 | ||
|
|
2788536799 | ||
|
|
314d435a18 | ||
|
|
37edcd8666 | ||
|
|
10e290fbdf | ||
|
|
58cda1241e | ||
|
|
3659aaabff | ||
|
|
727a39cc54 | ||
|
|
fd9ccdfff9 | ||
|
|
aabee270b3 | ||
|
|
647c58f8ec | ||
|
|
0b8024d19c | ||
|
|
d59b0bf27f | ||
|
|
398c16eac2 | ||
|
|
fa869bdc7d | ||
|
|
c20d0d2a30 | ||
|
|
000f2736c2 | ||
|
|
cfcc81bb62 | ||
|
|
82eae05868 | ||
|
|
e8fb53c49b | ||
|
|
604c97afe1 | ||
|
|
7e60cdf272 | ||
|
|
9ea7cfcc80 | ||
|
|
a7a4a16f79 | ||
|
|
6717059934 | ||
|
|
714747c280 | ||
|
|
81cd305c80 | ||
|
|
5de872bbb3 | ||
|
|
ce6a75a920 | ||
|
|
874a5cb2f2 | ||
|
|
6e2202d4f1 | ||
|
|
bcf33df701 | ||
|
|
3bdcf21c69 | ||
|
|
4b36bdc58c | ||
|
|
6d9008ee8c | ||
|
|
ee93692707 | ||
|
|
2bcc368bce | ||
|
|
6cc4467d53 | ||
|
|
425f98dc07 | ||
|
|
cf34a9f3ad | ||
|
|
3b2f347428 | ||
|
|
bd82c3cc4f | ||
|
|
af319866c7 | ||
|
|
b6ab29398e | ||
|
|
a5bb1797c0 | ||
|
|
a9647671c4 | ||
|
|
63f784e7da | ||
|
|
5da3379e0b | ||
|
|
2f3514689d | ||
|
|
89a3ea4e24 | ||
|
|
467e9555f4 | ||
|
|
5b32ca15f7 | ||
|
|
92402817d2 | ||
|
|
60ad3031d5 | ||
|
|
724cddb481 | ||
|
|
41c0521480 | ||
|
|
85ac2b1f63 | ||
|
|
13a97353aa | ||
|
|
f49c166b9b | ||
|
|
fffa326f80 | ||
|
|
da446adbb2 | ||
|
|
617fec5c69 | ||
|
|
cfefa69c9c | ||
|
|
00638a9e23 | ||
|
|
e241e03a15 | ||
|
|
b1faa3bd48 | ||
|
|
6d28f487ec | ||
|
|
b231f92f76 | ||
|
|
7d33d56c0e | ||
|
|
f86f34e5e1 | ||
|
|
5e7b52b7de | ||
|
|
0459d344e9 | ||
|
|
71e525cd76 | ||
|
|
1480706d8b | ||
|
|
96655b6d80 | ||
|
|
eed2aa0d0d | ||
|
|
de0c078a23 | ||
|
|
321e995a54 | ||
|
|
da9f1f81d7 | ||
|
|
c6d4477a24 | ||
|
|
523b073cdc | ||
|
|
2591bee21b | ||
|
|
d881ca00c9 | ||
|
|
329dbff474 | ||
|
|
d84a9fe6dc | ||
|
|
dcd812a996 | ||
|
|
6750194d9b | ||
|
|
05865c3d9b | ||
|
|
21e224bf00 | ||
|
|
f401d3fd0c | ||
|
|
fd436871f1 | ||
|
|
fcf7864a4b | ||
|
|
c4003956d9 | ||
|
|
de622b6162 | ||
|
|
41b4bdb90e | ||
|
|
af73cb3ad3 | ||
|
|
240b631963 | ||
|
|
c2a747af8c | ||
|
|
5959647826 | ||
|
|
9542e211bc | ||
|
|
d07890db7f | ||
|
|
ca241bd8f2 | ||
|
|
e444092711 | ||
|
|
a96b1e07f4 | ||
|
|
f48c31bcb5 | ||
|
|
d85ab93a35 | ||
|
|
a6804b5aca | ||
|
|
e4dcb211ee | ||
|
|
a5a5f47f7a | ||
|
|
25c900c387 | ||
|
|
4e95f7b83e | ||
|
|
66ad3b0cee | ||
|
|
e853cd1ca0 | ||
|
|
b9544033c6 | ||
|
|
17840cb8cc | ||
|
|
f85b6d94b8 | ||
|
|
6c32a9f198 | ||
|
|
cefeebbfb8 | ||
|
|
941a015b43 | ||
|
|
ae0e9fbe77 | ||
|
|
3484c3dd2e | ||
|
|
5be8f749bd | ||
|
|
cf484707a0 | ||
|
|
f12e529c0b | ||
|
|
01b90a2ba5 | ||
|
|
cd1e952812 | ||
|
|
996f1e4277 | ||
|
|
2d84694f86 | ||
|
|
65718c64cc | ||
|
|
6e30365f55 | ||
|
|
c0555b6d86 | ||
|
|
1ff9b6c071 | ||
|
|
c1a51a1dfa | ||
|
|
bfbbeb90e7 | ||
|
|
588e075325 | ||
|
|
66717fee68 | ||
|
|
844f52c955 | ||
|
|
e679cd05c1 | ||
|
|
1e72ce4830 | ||
|
|
3bb21c5403 | ||
|
|
6d1be23ad0 | ||
|
|
0472b9a4a4 | ||
|
|
c9acff49f9 | ||
|
|
7cab560595 | ||
|
|
ac98531a2f | ||
|
|
917e0ba79c | ||
|
|
3ebceb7522 | ||
|
|
92bd52da12 | ||
|
|
fb56a9cd6e | ||
|
|
a4680f7d38 | ||
|
|
da8a72a8aa | ||
|
|
ac497932b5 | ||
|
|
9927b5061a | ||
|
|
cedaab9642 | ||
|
|
50bf2145ec | ||
|
|
dc77729f50 | ||
|
|
e3330d667a | ||
|
|
9822f397a1 | ||
|
|
a3b5ce9959 | ||
|
|
9eb06e929a | ||
|
|
629e06d647 | ||
|
|
51ccb92184 | ||
|
|
3cd27f13fd | ||
|
|
ae668530c0 | ||
|
|
4a8b1c056c | ||
|
|
d7a5e598bc | ||
|
|
3f1ee32cc6 | ||
|
|
725d6ead98 | ||
|
|
baf70579de | ||
|
|
cd28ab58a3 | ||
|
|
a78fa0a81d | ||
|
|
82130be5f5 | ||
|
|
510ce62dfb | ||
|
|
93375a5087 | ||
|
|
be738e7fb1 | ||
|
|
9c78131df3 | ||
|
|
d94f6f4d19 | ||
|
|
9a3eced350 | ||
|
|
2fed7a76fb | ||
|
|
f02e59df1b | ||
|
|
04147a2fe9 | ||
|
|
0e83bc31dc | ||
|
|
75a5f7960f | ||
|
|
3f93c27b07 | ||
|
|
ab781d4516 | ||
|
|
446438bf8c | ||
|
|
4e012cbd48 | ||
|
|
12ee4a792c | ||
|
|
e59750386f | ||
|
|
4e19d54867 | ||
|
|
db603e5438 | ||
|
|
5320cb123a | ||
|
|
30a2ebdbb4 | ||
|
|
a5d43998a3 | ||
|
|
2792caec70 | ||
|
|
fb2b1e984c | ||
|
|
13ab1caf95 | ||
|
|
5d4534fac4 | ||
|
|
f450643861 | ||
|
|
fc14a65511 | ||
|
|
bbd1e27c5e | ||
|
|
369a83b718 | ||
|
|
afc541b956 | ||
|
|
7e4d2ffb4d | ||
|
|
e09913a94f | ||
|
|
b4d1c4cc04 | ||
|
|
22537c0e7e | ||
|
|
39c0db8d6a | ||
|
|
9db12761f7 | ||
|
|
0f8a7c4817 | ||
|
|
47e59a55c5 | ||
|
|
b3496f4e5d | ||
|
|
e866228afd | ||
|
|
4aeaa5251e | ||
|
|
b36988e64a | ||
|
|
393aefce8f | ||
|
|
227ff1b8be | ||
|
|
82086a93b0 | ||
|
|
abd97cc1c9 | ||
|
|
3315fae83e | ||
|
|
d8c3c3f7f0 | ||
|
|
23459879f8 | ||
|
|
f1ca916d58 | ||
|
|
6aae012ae5 | ||
|
|
516983427a | ||
|
|
05d78c92f9 | ||
|
|
dc57144472 | ||
|
|
dd260ca45e | ||
|
|
3bc2fc4151 | ||
|
|
6c58eaa7e8 | ||
|
|
e1a1c11a01 | ||
|
|
95a6b4264d | ||
|
|
4782a4e07d | ||
|
|
dbc14206dc | ||
|
|
f4296d8858 | ||
|
|
75c4c2286d | ||
|
|
b14237e8e6 | ||
|
|
df3263e4bd | ||
|
|
ff7b413abf | ||
|
|
07224779e6 | ||
|
|
c031a3c24e | ||
|
|
1e74f7912c | ||
|
|
d91f8d0876 | ||
|
|
43d4644fba | ||
|
|
61a924d208 | ||
|
|
2692f2c1bf | ||
|
|
88b3c87bae | ||
|
|
7fd7dfd937 | ||
|
|
9a76f02709 | ||
|
|
81cc1c73c1 | ||
|
|
eabda8f0f7 | ||
|
|
cb3917457b | ||
|
|
2c4f36a8f9 | ||
|
|
d458be99bc | ||
|
|
a7f4531767 | ||
|
|
08f5a1ad06 | ||
|
|
f2de24c851 | ||
|
|
ed1eca8fb5 | ||
|
|
f792e6f13d | ||
|
|
b1782b7a97 | ||
|
|
f3c3966e00 | ||
|
|
8a9f72c96b | ||
|
|
402d3a16ae | ||
|
|
458e228b91 | ||
|
|
a817f09441 | ||
|
|
413ba85538 | ||
|
|
c1807bf1c3 | ||
|
|
09dd65499a | ||
|
|
640552abad | ||
|
|
faee1848e5 | ||
|
|
c7a217fea7 | ||
|
|
e4ae19a625 | ||
|
|
24fe6ee583 | ||
|
|
9cba754eb6 | ||
|
|
9e6bb5e844 | ||
|
|
a74ee255fb | ||
|
|
b9fc0c0365 | ||
|
|
2ce16c74f7 | ||
|
|
6d0ea5c6f9 | ||
|
|
b83ef112a9 | ||
|
|
dd9110a3a8 | ||
|
|
88c23e1b0f | ||
|
|
dbe40e3ad6 | ||
|
|
958d3b05c8 | ||
|
|
4e7b0baafb | ||
|
|
b3dc38f2d8 | ||
|
|
6044d3dce3 | ||
|
|
29446f2122 | ||
|
|
abb8673549 | ||
|
|
ffc8f9dcdf | ||
|
|
288b2bb720 | ||
|
|
fb3b7bda68 | ||
|
|
6d5efe1cbd | ||
|
|
1ceec22184 | ||
|
|
951ff9b953 | ||
|
|
641f06a7e7 | ||
|
|
915ba4ac21 | ||
|
|
824637d83f | ||
|
|
0871406fe3 | ||
|
|
1ad7e47b2e | ||
|
|
f72a2c69d0 | ||
|
|
84d9275cb8 | ||
|
|
1b7c387c8b | ||
|
|
2f1adbd22c | ||
|
|
65031523a6 | ||
|
|
02cc0fa0f6 | ||
|
|
1e1afa023f | ||
|
|
41f343c2cd | ||
|
|
a73c4deaca | ||
|
|
01a21aebc4 | ||
|
|
49434043f2 | ||
|
|
2e23877912 | ||
|
|
b737dd7df4 | ||
|
|
137ffaf768 | ||
|
|
747c6d30d2 | ||
|
|
4585968b11 | ||
|
|
84af564aee | ||
|
|
86d957675e | ||
|
|
bc33e608db | ||
|
|
0b5d28338e | ||
|
|
bdbf22e705 | ||
|
|
160f6016ee | ||
|
|
0855965edf | ||
|
|
fe3cbdab78 | ||
|
|
a8c25f910d | ||
|
|
cb82ec9b01 | ||
|
|
e84282cb9a | ||
|
|
8b2e02e1b0 | ||
|
|
1addd2be89 | ||
|
|
2aebfc29ac | ||
|
|
26a5410b38 | ||
|
|
f44e6d0948 | ||
|
|
d496ebf6dd | ||
|
|
1719ed6979 | ||
|
|
821895bb1b | ||
|
|
3f437277d1 | ||
|
|
39fc56084a | ||
|
|
e2fca07fad | ||
|
|
ec0d75ce95 | ||
|
|
877a64adaa | ||
|
|
0fcf9ed5ad | ||
|
|
c99de817fa | ||
|
|
600c86a185 | ||
|
|
1ae755b0a5 | ||
|
|
7186057dd3 | ||
|
|
768fec9c58 | ||
|
|
7197dd877b | ||
|
|
b7aa7eac9f | ||
|
|
818dc2f952 | ||
|
|
9dc5d11829 | ||
|
|
8565e1b408 | ||
|
|
bfc7133786 | ||
|
|
15a49f1bb4 | ||
|
|
db1dff16fe | ||
|
|
8d7d9d3a31 | ||
|
|
078bf8a559 | ||
|
|
1f314a5e9b | ||
|
|
0adb50ac01 | ||
|
|
d91707cd06 | ||
|
|
c0e7ee4eeb | ||
|
|
c143a7223e | ||
|
|
2c951ba146 | ||
|
|
660aadcd9c | ||
|
|
91d6adb980 | ||
|
|
b79ddd55c5 | ||
|
|
0ca645c634 | ||
|
|
676c0c8dc8 | ||
|
|
5c366ad9b1 | ||
|
|
836aed6ea9 | ||
|
|
50df250415 | ||
|
|
2409fc5b7b | ||
|
|
8a1184a24c | ||
|
|
d2fbc54765 | ||
|
|
1bcb26ba75 | ||
|
|
32f4749d84 | ||
|
|
da12be879a | ||
|
|
94a38ad4e8 | ||
|
|
20ef79a172 | ||
|
|
92bf25476e | ||
|
|
b55e074dd7 | ||
|
|
7b654a837d | ||
|
|
ae9d247d22 | ||
|
|
16b7deafe8 | ||
|
|
f2cfe28458 | ||
|
|
2e8a52949e | ||
|
|
441e142767 | ||
|
|
bf9bdd2aae | ||
|
|
ce14593f0b | ||
|
|
1c02a451e1 | ||
|
|
448855a2d3 | ||
|
|
8ac8e89f2b | ||
|
|
2281f59401 | ||
|
|
4cb0673370 | ||
|
|
76c5706f7c | ||
|
|
2bf4284ff4 | ||
|
|
d9e2fc97f3 | ||
|
|
85dfdf4174 | ||
|
|
1bede3efda | ||
|
|
505f0fdd31 | ||
|
|
eed7ec3a4a | ||
|
|
fdb057e0e2 | ||
|
|
3fddd1a628 | ||
|
|
2440706b87 | ||
|
|
cf628fa95c | ||
|
|
2b0b47d20d | ||
|
|
a8abf2804f | ||
|
|
22d7757949 | ||
|
|
0b0d170c96 | ||
|
|
1e8e9adf62 | ||
|
|
0f03fc31e0 | ||
|
|
518432e0fb | ||
|
|
10ef3464ef | ||
|
|
226abbd577 | ||
|
|
8d66f42ab1 | ||
|
|
0f14d06f9a | ||
|
|
c53be78496 | ||
|
|
a38f31ce48 | ||
|
|
1258bd5047 | ||
|
|
d25cbeb14c | ||
|
|
9b60a07fb6 | ||
|
|
c0dd41ce50 | ||
|
|
4cff92bbcc | ||
|
|
9aa8a223c7 | ||
|
|
fb59adcfdd | ||
|
|
4acca8a3e3 | ||
|
|
c1030d2b08 | ||
|
|
16a185c6c0 | ||
|
|
174e818bd0 | ||
|
|
7f829bf5df | ||
|
|
71908282bb | ||
|
|
db3ae446af | ||
|
|
bc7d291307 | ||
|
|
cfd4702279 | ||
|
|
54eefb546d | ||
|
|
6af0d96a4e | ||
|
|
eb50bee4a3 | ||
|
|
b6143f3652 | ||
|
|
348aa7afb6 | ||
|
|
66912b68cc | ||
|
|
84dd218758 | ||
|
|
106ae38976 | ||
|
|
f1a52245ea | ||
|
|
cea38e5bb2 | ||
|
|
ed5aac358c | ||
|
|
5eb128251e | ||
|
|
cfa46ec954 | ||
|
|
07cc60e264 | ||
|
|
90973dc547 | ||
|
|
12e3d71b00 | ||
|
|
9addc8f873 | ||
|
|
343465cef0 | ||
|
|
bec5159415 | ||
|
|
f8da8360e6 | ||
|
|
fb2ad7b75d | ||
|
|
24aa7a70e5 | ||
|
|
5ade3d6cdd | ||
|
|
0d8e548ffc | ||
|
|
b09650812f | ||
|
|
acc9ad5c08 | ||
|
|
67b6c4bd27 | ||
|
|
7a1d3dbdfa | ||
|
|
4bf10df0c5 | ||
|
|
d84faad109 | ||
|
|
e01ace7ea4 | ||
|
|
e004e1591e | ||
|
|
4613084e1b | ||
|
|
637b795a8f | ||
|
|
4de981a3c0 | ||
|
|
15db026e27 | ||
|
|
d88d520553 | ||
|
|
46cd98ea1d | ||
|
|
d10328d891 | ||
|
|
e418a17256 | ||
|
|
627d3b9df2 | ||
|
|
ba28ade414 | ||
|
|
7c11130357 | ||
|
|
151915beea | ||
|
|
4f9aacb338 | ||
|
|
1f8e491ddc | ||
|
|
05cfa92182 | ||
|
|
e8031aeb49 | ||
|
|
85885406aa | ||
|
|
636f17d78d | ||
|
|
29559a5339 | ||
|
|
19f2fd75c9 | ||
|
|
8a60bae335 | ||
|
|
fa5ff60550 | ||
|
|
f6e0568964 | ||
|
|
fa27a11fea | ||
|
|
19706559cb | ||
|
|
0a06a0a51d | ||
|
|
b045177734 | ||
|
|
7ee5fa8765 | ||
|
|
3e690048a6 | ||
|
|
7ec3bfea9f | ||
|
|
098f3fd496 | ||
|
|
5476eef049 | ||
|
|
33c1eea9a1 | ||
|
|
d3432ed87c | ||
|
|
f05363ea93 | ||
|
|
77389c20a4 | ||
|
|
7c5f1ba85e | ||
|
|
e7c34cc15c | ||
|
|
72fd03a6b2 | ||
|
|
61f464ae4d | ||
|
|
19cdf66f10 | ||
|
|
0c036df6a8 | ||
|
|
4c1b9d83d1 | ||
|
|
b976b4657b | ||
|
|
eba04950d5 | ||
|
|
0c70df27ec | ||
|
|
d83f34722b | ||
|
|
652b6021d3 | ||
|
|
7fe9c87b6e | ||
|
|
9b2ae6d7fd | ||
|
|
8fd5b9a34b | ||
|
|
dffbf52d04 | ||
|
|
57ac5f0112 | ||
|
|
d5a71b0b24 | ||
|
|
d95b7be2e4 | ||
|
|
2f0a23f56a | ||
|
|
13b218f643 | ||
|
|
92a836ecdc | ||
|
|
c88a46f155 | ||
|
|
8882a34984 | ||
|
|
2d4a1731d9 | ||
|
|
be1e3073f1 | ||
|
|
6fe5a04cc0 | ||
|
|
426432885e | ||
|
|
9bc3381814 | ||
|
|
f3a492fd67 | ||
|
|
8cd2aa46b6 | ||
|
|
d638d634ba | ||
|
|
35196789e0 | ||
|
|
e907ce6c29 | ||
|
|
b80bc20d17 | ||
|
|
3a87eaa435 | ||
|
|
143eb57f04 | ||
|
|
6cc550bf18 | ||
|
|
7f5336661b | ||
|
|
e44539ef2c | ||
|
|
a2f5850173 | ||
|
|
283f4883f7 | ||
|
|
ce9842f671 | ||
|
|
b784433fd7 | ||
|
|
8c064e7c0a | ||
|
|
c15a8bd127 | ||
|
|
64e40e7b31 | ||
|
|
06d254e0de | ||
|
|
eaa342ca32 | ||
|
|
782f7c467b | ||
|
|
c45d02cb70 | ||
|
|
5b4c131eea | ||
|
|
bbe71af99e | ||
|
|
49912d019f | ||
|
|
d4758e09d7 | ||
|
|
f0a913cc07 | ||
|
|
8b0b8e3688 | ||
|
|
de4fc8a015 | ||
|
|
bf1e56ec53 | ||
|
|
040b4e4ff9 | ||
|
|
4666ee3145 | ||
|
|
2958c56a92 | ||
|
|
9cff8768ab | ||
|
|
cc671b8006 | ||
|
|
728abe6d0e | ||
|
|
7b8f3f2538 | ||
|
|
98db98f916 | ||
|
|
96a67b23ca | ||
|
|
2c3d7542e5 | ||
|
|
f84d83b723 | ||
|
|
b1837ba029 | ||
|
|
260438fa44 | ||
|
|
23d82beb04 | ||
|
|
19db5d736b | ||
|
|
6946c40657 | ||
|
|
bd3723ee20 | ||
|
|
1f078d4827 | ||
|
|
3c62a38667 | ||
|
|
7ffda74e3d | ||
|
|
560f6debc6 | ||
|
|
ea1ac33de8 | ||
|
|
7ea30237ae | ||
|
|
bc668487e2 | ||
|
|
1769f9864b | ||
|
|
75ffd97802 | ||
|
|
cfd5b7da0f | ||
|
|
26b7d1df26 | ||
|
|
0747929cd6 | ||
|
|
5bcfb102f4 | ||
|
|
908fb1ccea | ||
|
|
af8389baa4 | ||
|
|
24ca1017cd | ||
|
|
85c21aeb01 | ||
|
|
2f249048d9 | ||
|
|
974cb40ab3 | ||
|
|
c01c16ea60 | ||
|
|
bd157c249c | ||
|
|
b0ac33c1b1 | ||
|
|
82e73a9525 | ||
|
|
adc316d671 | ||
|
|
6a0b6b99ac | ||
|
|
08dd9dd5b4 | ||
|
|
557a1c2d00 | ||
|
|
f77bbfedda | ||
|
|
3aa3fe19e2 | ||
|
|
35fcc0493e | ||
|
|
9485bec2fa | ||
|
|
4b759e731c | ||
|
|
7dd6a8a1aa | ||
|
|
96725ae8b9 | ||
|
|
b3a0ded9a8 | ||
|
|
184c491803 | ||
|
|
f944b3ce00 | ||
|
|
2557f41863 | ||
|
|
2b92cee3f7 | ||
|
|
8071768579 | ||
|
|
71c8541b68 | ||
|
|
3d66c77188 | ||
|
|
8701512961 | ||
|
|
b317c780ba | ||
|
|
681aa3bf8b | ||
|
|
a68e053471 | ||
|
|
25a90e3b32 | ||
|
|
2f62759dfe | ||
|
|
cf9ec46ab8 | ||
|
|
ecbef51b10 | ||
|
|
dfff8c9587 | ||
|
|
cc5d52bbf9 | ||
|
|
a9e9f86c93 | ||
|
|
a2c52713b2 | ||
|
|
545aca88d8 | ||
|
|
ac27248784 | ||
|
|
5758bfbaea | ||
|
|
8d3a079774 | ||
|
|
718c138510 | ||
|
|
29aac70e67 | ||
|
|
700575adfe | ||
|
|
9fe6e5df85 | ||
|
|
ce7434a463 | ||
|
|
ad7d876d07 | ||
|
|
0dc19e86fa | ||
|
|
a12acaa5c7 | ||
|
|
ff62efe720 | ||
|
|
2407877184 | ||
|
|
5fde050738 | ||
|
|
a855f88073 | ||
|
|
cfa2acd61d | ||
|
|
d9db2fe2e7 | ||
|
|
15d62cd3b6 | ||
|
|
19a89aeb7e | ||
|
|
677c61c32f | ||
|
|
4dd4f66397 | ||
|
|
04b7828abc | ||
|
|
9c621ecab8 | ||
|
|
ab9c4d9416 | ||
|
|
e5eb62255a | ||
|
|
98ff79432b | ||
|
|
24fa80ba2a | ||
|
|
3999d792ef | ||
|
|
4db3732749 | ||
|
|
07131e8b40 | ||
|
|
39b91e74c9 | ||
|
|
d4bb7ec3bc | ||
|
|
6175b7e359 | ||
|
|
10442d506a | ||
|
|
573a695c3d | ||
|
|
a76bef0d01 | ||
|
|
e20111b566 | ||
|
|
4a1d9c8f75 | ||
|
|
26c86282e3 | ||
|
|
0eaeb1650d | ||
|
|
f4a6533f6b | ||
|
|
df1b6a13e1 | ||
|
|
e8f24f617c | ||
|
|
9454fdc217 | ||
|
|
22543d8fe5 | ||
|
|
60d1dc82e6 | ||
|
|
87486f87ef | ||
|
|
80e7da0f13 | ||
|
|
3745beae66 | ||
|
|
3965840bfa | ||
|
|
a88c6f3d32 | ||
|
|
ed6c6f0026 | ||
|
|
bdda9d72b5 | ||
|
|
fd080e778e | ||
|
|
9f72df2ecd | ||
|
|
617db012f0 | ||
|
|
9d15541237 | ||
|
|
35c99564c6 | ||
|
|
1d8fe334d6 | ||
|
|
d86bb314ac | ||
|
|
0ef8eb59f8 | ||
|
|
b5fe4a9a87 | ||
|
|
11fea31b98 | ||
|
|
f629275ed5 | ||
|
|
a5f6166469 | ||
|
|
501050e591 | ||
|
|
e1b240b2b2 | ||
|
|
3d79278ed7 | ||
|
|
5e0b197a43 | ||
|
|
9c4170d9e2 | ||
|
|
af721eb196 | ||
|
|
788e315f5e | ||
|
|
4a82a8d5a8 | ||
|
|
11019a26f8 | ||
|
|
6f8909dce9 | ||
|
|
5525103aaf | ||
|
|
291ef737b1 | ||
|
|
af125bdd57 | ||
|
|
79089bbb8c | ||
|
|
1f08498d00 | ||
|
|
49ba714a03 | ||
|
|
85fd9296b2 | ||
|
|
1cda14867f | ||
|
|
2d2b26f7dc | ||
|
|
93b33af44a | ||
|
|
eb80490bcd | ||
|
|
ba2b06f5af | ||
|
|
fecc762db1 | ||
|
|
1e406253ab | ||
|
|
6e3b85f43d | ||
|
|
58f1b626e2 | ||
|
|
c104a08e16 | ||
|
|
dd0f6ca1e6 | ||
|
|
f02ea91b51 | ||
|
|
6768a501a3 | ||
|
|
879e15c759 | ||
|
|
89285b4abc | ||
|
|
c584714f91 | ||
|
|
f5016403b7 | ||
|
|
c8f66ae6bb | ||
|
|
858c967e71 | ||
|
|
f9ca5de5bf | ||
|
|
252c3476a1 | ||
|
|
19210df6db | ||
|
|
15c5730749 | ||
|
|
3764adb7ef | ||
|
|
9160adb1cf | ||
|
|
3ebf4338ab | ||
|
|
2eb4b7b39b | ||
|
|
c241e49b48 | ||
|
|
238c881132 | ||
|
|
49dc733536 | ||
|
|
755bd78f60 | ||
|
|
77f80cd51f | ||
|
|
3df6000635 | ||
|
|
5efee2b40d | ||
|
|
f3c2e59184 | ||
|
|
24ab660e6e | ||
|
|
6c0a418068 | ||
|
|
07a180991e | ||
|
|
4732004b67 | ||
|
|
faa9cd0431 | ||
|
|
e0c3c2394d | ||
|
|
2dec584f54 | ||
|
|
5ab2ccae40 | ||
|
|
1017d08626 | ||
|
|
32b1bbd943 | ||
|
|
1abf31ffa5 | ||
|
|
aec60829d2 | ||
|
|
888c3c38c2 | ||
|
|
e2c4648037 | ||
|
|
f7b98c0530 | ||
|
|
d4bd3faa16 | ||
|
|
c4f3b1cd7b | ||
|
|
74add69a83 | ||
|
|
a490b19d24 | ||
|
|
44cfa2c1a2 | ||
|
|
6dd9522b3f | ||
|
|
5e352cb8e4 | ||
|
|
2fad7315b8 | ||
|
|
520759dfe8 | ||
|
|
577b44ae11 | ||
|
|
66f742d6c0 | ||
|
|
7ba9f688c7 | ||
|
|
883f0307a2 | ||
|
|
c9719f873f | ||
|
|
123d25f853 | ||
|
|
56da42db84 | ||
|
|
7f820449ca | ||
|
|
ecb2cf5f11 | ||
|
|
7f27da9b3b | ||
|
|
01eb499c69 | ||
|
|
1ff6f70682 | ||
|
|
ddde996e10 | ||
|
|
1c9212c7e0 | ||
|
|
a568143991 | ||
|
|
2b6f1bd9ee | ||
|
|
2527aa5ea6 | ||
|
|
4c28091ecd | ||
|
|
d49725423e | ||
|
|
fcb4dc61b5 | ||
|
|
b7330c074f | ||
|
|
e8f4123030 | ||
|
|
975057c4c4 | ||
|
|
a0e01668d1 | ||
|
|
2c77491416 | ||
|
|
be19e4a9cb | ||
|
|
61ce91a9d7 | ||
|
|
18f1d07e85 | ||
|
|
b596976194 | ||
|
|
1f6b86d516 | ||
|
|
31499b977d | ||
|
|
f83850e380 | ||
|
|
1a4ccd86fe | ||
|
|
5c3c6fec09 | ||
|
|
f97e742daa | ||
|
|
7f39d401e2 | ||
|
|
af412c284d | ||
|
|
874cd3bae5 | ||
|
|
ea28ebdd13 | ||
|
|
3ba468933f | ||
|
|
45f33e4bea | ||
|
|
021487ed16 | ||
|
|
cb3443ffb1 | ||
|
|
6b2c9dc3e3 | ||
|
|
7513cc1947 | ||
|
|
c98b8ae5c9 | ||
|
|
ab2dd4b75f | ||
|
|
be77316545 | ||
|
|
cdfb0d9497 | ||
|
|
71f7e7c741 | ||
|
|
cff099596e | ||
|
|
e182604455 | ||
|
|
45a7defb7e | ||
|
|
906f6ac1ea | ||
|
|
8d96e513bd | ||
|
|
cdefd063e2 | ||
|
|
8bbcba76cf | ||
|
|
c767e89a5d | ||
|
|
b78a603dca | ||
|
|
18088457d3 | ||
|
|
056697d901 | ||
|
|
2681cfad50 | ||
|
|
8aaa7925a3 | ||
|
|
d4f73e471b | ||
|
|
750be0c4a4 | ||
|
|
0f4a2a26fc | ||
|
|
6adb56341d | ||
|
|
4524357cd3 | ||
|
|
0b05b6f6e3 | ||
|
|
6382170157 | ||
|
|
c2eeb69dcc | ||
|
|
f32261fc59 | ||
|
|
90c967c8c6 | ||
|
|
4ac90128db | ||
|
|
3d71db1bb7 | ||
|
|
5e35ea5168 | ||
|
|
2fc88d52eb | ||
|
|
567b0f3b57 | ||
|
|
8f29386998 | ||
|
|
d2427d57d9 | ||
|
|
14a9499962 | ||
|
|
0fafb80d44 | ||
|
|
b5454f0943 | ||
|
|
b698260d73 | ||
|
|
ccdd1b74a0 | ||
|
|
298fe20a1b | ||
|
|
12a7c45452 | ||
|
|
02a28c2fd6 | ||
|
|
68e182b0bd | ||
|
|
b0ec88f469 | ||
|
|
4feee6ac22 | ||
|
|
ee8a85ec2f | ||
|
|
0245d4a881 | ||
|
|
e8f0058956 | ||
|
|
9c75dbaae0 | ||
|
|
5bd39b598e | ||
|
|
25a43abffd | ||
|
|
9a7ca022e2 | ||
|
|
46fe0d7caf | ||
|
|
0371cec415 | ||
|
|
2b1020cbb9 | ||
|
|
8c3ce2a87d | ||
|
|
d633622e27 | ||
|
|
19b652f615 | ||
|
|
37f7dd0631 | ||
|
|
4c99710fb3 | ||
|
|
59865cdb44 | ||
|
|
c3434507da | ||
|
|
79ecf20b85 | ||
|
|
1de9681bb7 | ||
|
|
345c4778e6 | ||
|
|
0ccb2f88ca | ||
|
|
f7bef8b0e9 | ||
|
|
9da8608f8f | ||
|
|
496cb0b909 | ||
|
|
583cafa91e | ||
|
|
01da665243 | ||
|
|
e900cd1e3d | ||
|
|
a8a838b33e | ||
|
|
072be25335 | ||
|
|
5f50429cdb | ||
|
|
db3fb04172 | ||
|
|
839385c3fb | ||
|
|
d508b7b2df | ||
|
|
b1456b87c0 | ||
|
|
58d2dcaef2 | ||
|
|
a9468d1cbb | ||
|
|
a29e3e8da3 | ||
|
|
dd5df1bb2a | ||
|
|
d5d6f3a7b3 | ||
|
|
9d2f2b3026 | ||
|
|
74717a3047 | ||
|
|
c13ee92f1e | ||
|
|
0ca04bed4f | ||
|
|
89850de660 | ||
|
|
8bb4ebd897 | ||
|
|
6a67208d24 | ||
|
|
139f32c3e8 | ||
|
|
81c0d01944 | ||
|
|
1d2f997efb | ||
|
|
f126b1dac3 | ||
|
|
bbc38262ce | ||
|
|
caeafd3189 | ||
|
|
98e3c47cdf | ||
|
|
390b230cac | ||
|
|
c5c3950c91 | ||
|
|
2aea0b3b1f | ||
|
|
6b16e02b34 | ||
|
|
bb2f81318a | ||
|
|
ec91d0fb22 | ||
|
|
760e23693e | ||
|
|
cfba00ae46 | ||
|
|
dc1cfb60ff | ||
|
|
92148304ee | ||
|
|
9329c0c0f6 | ||
|
|
de3ac001fc | ||
|
|
b1047154a4 | ||
|
|
c361af3792 | ||
|
|
73487fc24b | ||
|
|
73513fd700 | ||
|
|
6b7723eb2a | ||
|
|
7056c15366 | ||
|
|
8539e050ae | ||
|
|
5d4c2641f6 | ||
|
|
bc32071576 | ||
|
|
3b2c57314f | ||
|
|
36351a0608 | ||
|
|
047b454c1d | ||
|
|
3f5e620102 | ||
|
|
851a43ba4b | ||
|
|
47ae50f704 | ||
|
|
33bdd6ae82 | ||
|
|
433021727e | ||
|
|
7f23c84287 | ||
|
|
74bd2585e7 | ||
|
|
ebb27638ff | ||
|
|
3eb7e4c5bf | ||
|
|
112f859b19 | ||
|
|
fd08678ff6 | ||
|
|
2e2fc11fe1 | ||
|
|
d44ed57cf9 | ||
|
|
aa31acb056 | ||
|
|
232003cb2e | ||
|
|
db21dd1659 | ||
|
|
2f3279a5ff | ||
|
|
ab21317156 | ||
|
|
43cb312225 | ||
|
|
ce28cb7a48 | ||
|
|
1e47fa557c | ||
|
|
1ae3cf7b99 | ||
|
|
915d6504a2 | ||
|
|
5e63ca7a82 | ||
|
|
e0777e74c2 | ||
|
|
cf465134fd | ||
|
|
873ac70d18 | ||
|
|
9ca3c50c83 | ||
|
|
cc1c7c39b1 | ||
|
|
2c6222984d | ||
|
|
58d7e17165 | ||
|
|
57618095bf | ||
|
|
492a1ad8ec | ||
|
|
71da0ce345 | ||
|
|
7dc574b534 | ||
|
|
ff8a7a1bfd | ||
|
|
0f963eeab1 | ||
|
|
8f02665e6d | ||
|
|
8604c3ab03 | ||
|
|
7a61129388 | ||
|
|
516db3d8be | ||
|
|
34bdc5056a | ||
|
|
9402fd5cf3 | ||
|
|
a6faa5ce0c | ||
|
|
5735a70e47 | ||
|
|
8f997658d7 | ||
|
|
5069316326 | ||
|
|
143f17fb2a | ||
|
|
900d7fa07a | ||
|
|
a4389542fd | ||
|
|
b7f4e40917 | ||
|
|
a0447ba91c | ||
|
|
17c9d208ad | ||
|
|
e89311fcff | ||
|
|
bab750fa6c | ||
|
|
0caaf23767 | ||
|
|
c5676f1dfb | ||
|
|
86854581f8 | ||
|
|
ef81944826 | ||
|
|
b3b53ebcc0 | ||
|
|
3bc0384100 | ||
|
|
24b1c2ae58 | ||
|
|
c996bfcfaf | ||
|
|
3814635aa0 | ||
|
|
2b6c09cfad | ||
|
|
9ee474081e | ||
|
|
5bab298f74 | ||
|
|
fd42b7f443 | ||
|
|
edcea220f6 | ||
|
|
a92e85f8db | ||
|
|
6fbe8bb192 | ||
|
|
5f45fd9b5b | ||
|
|
46925331c7 | ||
|
|
84123df996 | ||
|
|
641b446195 | ||
|
|
34bbf06793 | ||
|
|
53a88e236b | ||
|
|
c2069a12b4 | ||
|
|
791ab245ca | ||
|
|
43287736bb | ||
|
|
34ee3321d8 | ||
|
|
6e433ae784 | ||
|
|
cd370275da | ||
|
|
7ed0f4c8ae | ||
|
|
ea7d8ce766 | ||
|
|
f12e877251 | ||
|
|
57ce90ce7c | ||
|
|
b61321e360 | ||
|
|
6416056958 | ||
|
|
4fdfd03c04 | ||
|
|
a1d2438341 | ||
|
|
952aa15d6e | ||
|
|
b3e45eb0b6 | ||
|
|
a548b39677 | ||
|
|
d5d96c58e4 | ||
|
|
9b61a06ef1 | ||
|
|
3dbf19ac0b | ||
|
|
7dc999ef39 | ||
|
|
697028b706 | ||
|
|
c260fccdb5 | ||
|
|
d9bf7c941b | ||
|
|
af64151c60 | ||
|
|
da94d65c6b | ||
|
|
d51340000f | ||
|
|
6f93fa3758 | ||
|
|
598f953cc1 | ||
|
|
c39304281d | ||
|
|
5e5e5c21ed | ||
|
|
299e270594 | ||
|
|
bd8a4e3639 | ||
|
|
b3b5d05bfc | ||
|
|
268cefcb51 | ||
|
|
f4e860bc2c | ||
|
|
b65aa46daa | ||
|
|
faef95a84d | ||
|
|
25dfdd2ff6 | ||
|
|
88879a5de9 | ||
|
|
52919f96a7 | ||
|
|
402505098a | ||
|
|
e8d8b8be60 | ||
|
|
5ff7d01bd2 | ||
|
|
3f8849680b | ||
|
|
e450fee020 | ||
|
|
d7c162c71c | ||
|
|
f211fa4b5e | ||
|
|
c3963bc453 | ||
|
|
23bd51ac9c | ||
|
|
9e200b947e | ||
|
|
2e661d5ff4 | ||
|
|
766d5a4d7e | ||
|
|
1f24937e65 | ||
|
|
aba35c3440 | ||
|
|
3a8fd0ebb1 | ||
|
|
69a2d53277 | ||
|
|
0b66d67ef3 | ||
|
|
1f22326db6 | ||
|
|
b4dfdb5515 | ||
|
|
25512340c8 | ||
|
|
d2d322ba30 | ||
|
|
96a26eae4a | ||
|
|
71a46cd10e | ||
|
|
013af6af46 |
22
.clang-format
Normal file
22
.clang-format
Normal file
@@ -0,0 +1,22 @@
|
||||
BasedOnStyle: LLVM
|
||||
UseTab: AlignWithSpaces
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
BreakBeforeBraces: Allman
|
||||
ColumnLimit: 0
|
||||
NamespaceIndentation: Inner
|
||||
FixNamespaceComments: true
|
||||
AccessModifierOffset: -2
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
IndentCaseLabels: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BraceWrapping:
|
||||
BeforeLambdaBody: false
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
Cpp11BracedListStyle: false
|
||||
IncludeBlocks: Regroup
|
||||
LambdaBodyIndentation: Signature
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
IndentPPDirectives: AfterHash
|
||||
PPIndentWidth: 1
|
||||
18
.clang-tidy
Normal file
18
.clang-tidy
Normal file
@@ -0,0 +1,18 @@
|
||||
Checks: '-*,
|
||||
bugprone-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
cert-*,
|
||||
modernize*,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-use-designated-initializers,
|
||||
performance
|
||||
'
|
||||
|
||||
# HeaderFilterRegex: '.*'
|
||||
ExcludeHeaderFilterRegex: 'Eigen|Eigen/Eigenvalues|eigen3/Eigen/Eigenvalues|sqlite3.h'
|
||||
CheckOptions:
|
||||
- key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
|
||||
value: false
|
||||
- key: bugprone-narrowing-conversions.WarnOnIntegerToFloatingPointNarrowingConversion
|
||||
value: false
|
||||
65
.github/workflows/build-documentation.yml
vendored
Normal file
65
.github/workflows/build-documentation.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
|
||||
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
|
||||
name: publish docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "trunk" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set reusable strings
|
||||
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
|
||||
id: strings
|
||||
shell: bash
|
||||
run: |
|
||||
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install dependencies Ubuntu
|
||||
run: sudo apt-get update && sudo apt-get install cmake doxygen
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
cache: 'pip' # caching pip dependencies
|
||||
- run: pip install -r docs/requirements.txt
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake -S . -B ${{ steps.strings.outputs.build-output-dir }} -DBUILD_DOCUMENTATION=ON -DBUILD_TESTING=OFF
|
||||
|
||||
- name: Run Sphinx
|
||||
run: |
|
||||
cmake --build ${{ steps.strings.outputs.build-output-dir }} --target Sphinx-cifpp
|
||||
ls -l ${{ steps.strings.outputs.build-output-dir }}
|
||||
ls -l ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ${{ steps.strings.outputs.build-output-dir }}/docs/sphinx
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
needs: docs
|
||||
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
64
.github/workflows/cmake-multi-platform.yml
vendored
Normal file
64
.github/workflows/cmake-multi-platform.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: multi platform test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "trunk", "develop" ]
|
||||
pull_request:
|
||||
branches: [ "trunk" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
include:
|
||||
- os: windows-latest
|
||||
cpp_compiler: cl
|
||||
- os: ubuntu-latest
|
||||
cpp_compiler: g++
|
||||
- os: macos-latest
|
||||
cpp_compiler: clang++
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set reusable strings
|
||||
id: strings
|
||||
shell: bash
|
||||
run: echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install dependencies Ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: sudo apt-get update && sudo apt-get install mrc catch2 libsqlite3-dev
|
||||
|
||||
- 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 fast_float
|
||||
|
||||
- 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
|
||||
30
.gitignore
vendored
30
.gitignore
vendored
@@ -1,14 +1,18 @@
|
||||
obj.dbg/
|
||||
obj/
|
||||
.libs/
|
||||
build/
|
||||
.vscode/
|
||||
autom4te.cache/
|
||||
GNUmakefile
|
||||
include/cif++/Config.hpp
|
||||
tools/symop-map-generator
|
||||
test/unit-test
|
||||
libcif++.pc
|
||||
libcif++.la
|
||||
config.status
|
||||
config.log
|
||||
libtool
|
||||
.vs/
|
||||
tools/update-libcifpp-data
|
||||
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/
|
||||
|
||||
|
||||
34
.travis.yml
34
.travis.yml
@@ -1,34 +0,0 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
dist: focal
|
||||
|
||||
osx_image:
|
||||
- xcode12
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
# - clang
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libboost-all-dev
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install boost make; fi
|
||||
|
||||
script:
|
||||
- ./configure
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then gmake ; else make ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then gmake test ; else make test ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then sudo gmake install; else sudo make install; fi
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
- os: osx
|
||||
|
||||
578
CMakeLists.txt
Normal file
578
CMakeLists.txt
Normal file
@@ -0,0 +1,578 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
# Copyright (c) 2021 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
|
||||
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 10.0.4
|
||||
LANGUAGES CXX C)
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
include(FindAtomic)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GenerateExportHeader)
|
||||
include(CTest)
|
||||
include(ExternalProject)
|
||||
include(FetchContent)
|
||||
include(VersionString)
|
||||
|
||||
# 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()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
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()
|
||||
|
||||
# Build documentation?
|
||||
set(BUILD_DOCUMENTATION OFF CACHE BOOL "Build the documentation")
|
||||
|
||||
# Build examples?
|
||||
set(BUILD_EXAMPLES ON CACHE BOOL "Build the example applications")
|
||||
|
||||
# Optionally build a version to be installed inside CCP4
|
||||
set(BUILD_FOR_CCP4 OFF CACHE BOOL "Build a version to be installed in CCP4")
|
||||
|
||||
# Create the cql/sqlite interface
|
||||
set(BUILD_SQLITE_INTERFACE ON CACHE BOOL "Build the sqlite interface")
|
||||
|
||||
# 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()
|
||||
|
||||
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()
|
||||
unset(CIFPP_DOWNLOAD_CCD)
|
||||
unset(CIFPP_INSTALL_UPDATE_SCRIPT)
|
||||
endif()
|
||||
|
||||
# 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 "cifpp: A CCP4 built was requested but CCP4 was not sourced")
|
||||
else()
|
||||
list(PREPEND CMAKE_MODULE_PATH "$ENV{CCP4}")
|
||||
list(PREPEND CMAKE_PREFIX_PATH "$ENV{CCP4}")
|
||||
set(CMAKE_INSTALL_PREFIX "$ENV{CCP4}")
|
||||
|
||||
if(WIN32)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Now include the GNUInstallDirs module
|
||||
include(GNUInstallDirs)
|
||||
|
||||
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- /bigobj)
|
||||
add_link_options(/NODEFAULTLIB:library)
|
||||
endif()
|
||||
|
||||
# Libraries
|
||||
|
||||
if(MSVC)
|
||||
# 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)
|
||||
endif()
|
||||
|
||||
# Normal search.
|
||||
set(_ZLIB_x86 "(x86)")
|
||||
set(_ZLIB_SEARCH_NORMAL
|
||||
PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Zlib;InstallPath]"
|
||||
"$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)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Using fast_float for float parsing, but only if needed
|
||||
try_compile(STD_CHARCONV_COMPILING
|
||||
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/test-charconv.cpp
|
||||
CXX_STANDARD 20
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(NOT STD_CHARCONV_COMPILING)
|
||||
message(NOTICE "libcifpp: Using fast_float for std::from_chars")
|
||||
find_package(FastFloat 8.0 REQUIRED CONFIG)
|
||||
endif()
|
||||
|
||||
find_package(Threads)
|
||||
find_package(ZLIB QUIET)
|
||||
|
||||
if(NOT ZLIB_FOUND)
|
||||
message(FATAL_ERROR "cifpp: The zlib development files were not found you this system, please install them and try again (hint: on debian/ubuntu use apt-get install zlib1g-dev)")
|
||||
endif()
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PCRE2 IMPORTED_TARGET libpcre2-8)
|
||||
endif()
|
||||
|
||||
if(NOT PCRE2_FOUND)
|
||||
add_subdirectory(pcre2-simple)
|
||||
endif()
|
||||
|
||||
# Using Eigen3 is a bit of a thing. We don't want to build it completely since
|
||||
# we only need a couple of header files. Nothing special. But often, eigen3 is
|
||||
# already installed and then we prefer that.
|
||||
find_package(Eigen3 3.4 QUIET)
|
||||
|
||||
if(Eigen3_FOUND AND TARGET Eigen3::Eigen)
|
||||
get_target_property(EIGEN_INCLUDE_DIR Eigen3::Eigen
|
||||
INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
# Use ExternalProject since FetchContent always tries to install the result...
|
||||
ExternalProject_Add(my-eigen3
|
||||
URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.zip
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
ExternalProject_Get_Property(my-eigen3 SOURCE_DIR)
|
||||
set(EIGEN_INCLUDE_DIR ${SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# SymOp data table
|
||||
if(CIFPP_RECREATE_SYMOP_DATA)
|
||||
# The tool to create the table
|
||||
add_executable(symop-map-generator
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/symop-map-generator.cpp")
|
||||
|
||||
target_compile_features(symop-map-generator PUBLIC cxx_std_20)
|
||||
|
||||
add_custom_command(
|
||||
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
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symop_table_data.hpp
|
||||
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib"
|
||||
"$ENV{CLIBD}/symop.lib")
|
||||
endif()
|
||||
|
||||
# Create a revision file, containing the current git version info
|
||||
write_version_header("${CMAKE_CURRENT_SOURCE_DIR}/src/" LIB_NAME "LibCIFPP")
|
||||
|
||||
add_library(cifpp)
|
||||
add_library(cifpp::cifpp ALIAS cifpp)
|
||||
|
||||
# Sources
|
||||
list(APPEND project_sources
|
||||
${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
|
||||
)
|
||||
|
||||
list(APPEND project_headers
|
||||
include/cif++.hpp
|
||||
include/cif++/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++/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.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
|
||||
)
|
||||
|
||||
if(BUILD_SQLITE_INTERFACE)
|
||||
find_package(SQLite3 QUIET)
|
||||
if(SQLite3_FOUND)
|
||||
target_link_libraries(cifpp PRIVATE SQLite::SQLite3)
|
||||
else()
|
||||
FetchContent_Populate(SQLite3
|
||||
URL https://sqlite.org/2025/sqlite-amalgamation-3510100.zip
|
||||
URL_HASH SHA3_256=856b52ffe7383d779bb86a0ed1ddc19c41b0e5751fa14ce6312f27534e629b64
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
list(APPEND project_sources $<BUILD_INTERFACE:${sqlite3_SOURCE_DIR}>/sqlite3.c)
|
||||
target_include_directories(cifpp PRIVATE $<BUILD_INTERFACE:${sqlite3_SOURCE_DIR}>)
|
||||
endif()
|
||||
|
||||
list(APPEND project_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/cql.cpp)
|
||||
list(APPEND project_headers include/cif++/cql.hpp)
|
||||
endif()
|
||||
|
||||
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_23)
|
||||
|
||||
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:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
PRIVATE "${EIGEN_INCLUDE_DIR}")
|
||||
|
||||
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)
|
||||
get_target_property(FF_INC_DIR FastFloat::fast_float INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(cifpp PRIVATE ${FF_INC_DIR})
|
||||
target_compile_definitions(cifpp PRIVATE USE_FAST_FLOAT)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
endif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
|
||||
if(CIFPP_DOWNLOAD_CCD)
|
||||
# download the components.cif file from CCD
|
||||
set(COMPONENTS_CIF ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/components.cif)
|
||||
|
||||
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()
|
||||
endif()
|
||||
|
||||
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
|
||||
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()
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
|
||||
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 cifpp
|
||||
FILE_SET cifpp_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:cifpp>
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OPTIONAL)
|
||||
endif()
|
||||
|
||||
# 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)
|
||||
|
||||
if(OLD_CONFIG_FILES)
|
||||
message(
|
||||
STATUS "cifpp: Installation will remove old config files: ${OLD_CONFIG_FILES}")
|
||||
install(CODE "file(REMOVE ${OLD_CONFIG_FILES})")
|
||||
endif()
|
||||
|
||||
install(EXPORT cifpp
|
||||
NAMESPACE cifpp::
|
||||
FILE "cifpp-targets.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ddl.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_pdbx.dic
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rsrc/mmcif_ma.dic
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
|
||||
if(CIFPP_DATA_DIR AND CIFPP_DOWNLOAD_CCD)
|
||||
install(FILES ${COMPONENTS_CIF}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libcifpp)
|
||||
endif()
|
||||
|
||||
set(CONFIG_TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cifpp-config.cmake.in)
|
||||
|
||||
configure_package_config_file(
|
||||
${CONFIG_TEMPLATE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake
|
||||
INSTALL_DESTINATION lib/cmake/cifpp
|
||||
PATH_VARS CIFPP_DATA_DIR)
|
||||
|
||||
install(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
DESTINATION lib/cmake/cifpp)
|
||||
|
||||
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)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifpp-config-version.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
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)
|
||||
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 "cifpp: Don't know where to install the update script")
|
||||
endif()
|
||||
|
||||
# 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 ${CMAKE_INSTALL_SYSCONFDIR})
|
||||
install(
|
||||
CODE "message(\"cifpp: A configuration file has been written to ${CIFPP_ETC_DIR}/libcifpp.conf, please edit this file to enable automatic updates\")"
|
||||
)
|
||||
|
||||
install(DIRECTORY DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/libcifpp/cache-update.d)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
endif()
|
||||
|
||||
if(BUILD_DOCUMENTATION)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
229
GNUmakefile.in
229
GNUmakefile.in
@@ -1,229 +0,0 @@
|
||||
# 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
|
||||
# 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.
|
||||
|
||||
# makefile for libcif++
|
||||
|
||||
.PHONY: firstTarget
|
||||
firstTarget: all
|
||||
|
||||
CXX = @CXX@
|
||||
CXXFLAGS = @CXXFLAGS@ @BOOST_CPPFLAGS@ @LIBBZ2_CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@ @LIBS@ @BOOST_LDFLAGS@ @LIBBZ2_LDFLAGS@
|
||||
LIBS = @LIBS@ \
|
||||
@BOOST_IOSTREAMS_LIB@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libdir = @libdir@
|
||||
includedir = @includedir@
|
||||
datarootdir = @datarootdir@
|
||||
datadir = @datadir@
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
||||
LIB_NAME = @PACKAGE_NAME@
|
||||
LIB_TARGET = $(LIB_NAME).la
|
||||
|
||||
CCP4DIR = @CCP4@
|
||||
CLIBD ?= $(CCP4DIR)/lib/data
|
||||
|
||||
DATADIR = $(datadir)/libcifpp
|
||||
|
||||
ifeq "$(CHECK_CONFIG)" "1"
|
||||
|
||||
GNUmakefile: config.status GNUmakefile.in
|
||||
$(SHELL) ./config.status
|
||||
|
||||
config.status: configure
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
configure: configure.ac
|
||||
autoconf
|
||||
|
||||
LIBTOOL_DEPS = @LIBTOOL_DEPS@
|
||||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
endif
|
||||
|
||||
# libtool stuff
|
||||
|
||||
LIBTOOL = $(SHELL) ./libtool
|
||||
CXXCOMPILE = $(LIBTOOL) --silent --tag=CXX --mode=compile $(CXX) $(CXXFLAGS)
|
||||
CXXLINK = $(LIBTOOL) --silent --tag=CXX --mode=link $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@
|
||||
|
||||
# main build variables
|
||||
CXXFLAGS += -I. -pthread -I include/
|
||||
CXXFLAGS += -Wall -Wno-multichar
|
||||
|
||||
# Use the DEBUG flag to build debug versions of the code
|
||||
DEBUG = @DEBUG@
|
||||
|
||||
ifeq "$(DEBUG)" "1"
|
||||
DEFINES += DEBUG
|
||||
CXXFLAGS += -g -O0
|
||||
LDFLAGS += -g
|
||||
else
|
||||
CXXFLAGS += -O2
|
||||
DEFINES += NDEBUG
|
||||
endif
|
||||
|
||||
# targets
|
||||
|
||||
VPATH += src:test
|
||||
|
||||
CXXFLAGS += $(DEFINES:%=-D%)
|
||||
|
||||
OBJDIR = obj
|
||||
ifeq "$(DEBUG)" "1"
|
||||
OBJDIR := $(OBJDIR).dbg
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
LIBCIF_SRC = AtomType.cpp \
|
||||
Cif2PDB.cpp \
|
||||
Cif++.cpp \
|
||||
CifParser.cpp \
|
||||
CifUtils.cpp \
|
||||
CifValidator.cpp \
|
||||
Compound.cpp \
|
||||
PDB2Cif.cpp \
|
||||
PDB2CifRemark3.cpp \
|
||||
Point.cpp \
|
||||
Secondary.cpp \
|
||||
Structure.cpp \
|
||||
Symmetry.cpp \
|
||||
TlsParser.cpp
|
||||
|
||||
SOURCES = $(addprefix src/,$(LIBCIF_SRC))
|
||||
OBJECTS = $(addprefix $(OBJDIR)/, $(notdir $(SOURCES:%.cpp=%.lo)))
|
||||
|
||||
ifneq "$(CCP4DIR)" ""
|
||||
|
||||
# Special rules to generate symmetry operation number table
|
||||
tools/symop-map-generator: tools/symop-map-generator.cpp
|
||||
|
||||
src/SymOpTable_data.cpp: tools/symop-map-generator $(CLIBD)/symop.lib
|
||||
tools/symop-map-generator > $@
|
||||
|
||||
$(OBJDIR)/Symmetry.lo: src/SymOpTable_data.cpp
|
||||
|
||||
endif
|
||||
|
||||
$(LIB_TARGET): $(OBJECTS)
|
||||
$(CXXLINK) -rpath $(libdir) $(OBJECTS) $(LIBS)
|
||||
|
||||
lib: $(LIB_TARGET)
|
||||
.PHONY: libs
|
||||
|
||||
all: lib
|
||||
.PHONY: all
|
||||
|
||||
-include $(OBJECTS:%.lo=%.d)
|
||||
|
||||
$(OBJECTS:.lo=.d):
|
||||
|
||||
$(OBJDIR)/%.lo: %.cpp | $(OBJDIR)
|
||||
@ echo ">>" $<
|
||||
@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(OBJDIR)/$*.d -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp | $(OBJDIR)
|
||||
@ echo ">>" $<
|
||||
@ $(CXX) $(CXXFLAGS) -MT $@ -MD -MP -MF $(OBJDIR)/$*.d -c -o $@ $<
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf .libs $(OBJDIR)/* $(LIB_TARGET)
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
rm -f libtool config.lt
|
||||
rm -f config.status config.cache config.log configure.lineno config.status.lineno
|
||||
rm -f GNUmakefile
|
||||
|
||||
# Test rules
|
||||
|
||||
define TEST_template =
|
||||
|
||||
-include $$(OBJDIR)/$(1)-test.d
|
||||
|
||||
$(1)_OBJECTS = $$(OBJDIR)/$(1)-test.o
|
||||
|
||||
test/$(1)-test: $(LIB_TARGET) $$($(1)_OBJECTS)
|
||||
@ echo ">>> building $(1)-test"
|
||||
$(LIBTOOL) --silent --tag=CXX --mode=link $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $$@ $$($(1)_OBJECTS) -L.libs -lcif++ $(LIBS)
|
||||
|
||||
.PHONY: $(1)-test
|
||||
$(1)-test: test/$(1)-test
|
||||
cd test; ./$(1)-test $$($(1)_PARAMS)
|
||||
|
||||
endef
|
||||
|
||||
TESTS = unit
|
||||
|
||||
$(foreach part,$(TESTS),$(eval $(call TEST_template,$(part))))
|
||||
|
||||
.PHONY: test
|
||||
test: $(TESTS:%=%-test)
|
||||
|
||||
HEADERS = \
|
||||
AtomType.hpp \
|
||||
CifParser.hpp \
|
||||
Compound.hpp \
|
||||
PDB2CifRemark3.hpp \
|
||||
Structure.hpp \
|
||||
Cif2PDB.hpp \
|
||||
CifUtils.hpp \
|
||||
Config.hpp \
|
||||
Point.hpp \
|
||||
Symmetry.hpp \
|
||||
Cif++.hpp \
|
||||
CifValidator.hpp \
|
||||
PDB2Cif.hpp \
|
||||
Secondary.hpp \
|
||||
TlsParser.hpp
|
||||
|
||||
.PHONY: install-lib
|
||||
install-lib: lib
|
||||
install -d $(libdir)
|
||||
$(LIBTOOL) --mode=install install $(LIB_TARGET) $(libdir)
|
||||
install -d $(DATADIR)/dictionaries
|
||||
for d in mmcif_ddl.dic mmcif_pdbx.dic; do \
|
||||
install -m644 rsrc/dictionaries/$$d $(DATADIR)/dictionaries/$$d; \
|
||||
done
|
||||
|
||||
.PHONY: install-dev
|
||||
install-dev:
|
||||
install -d $(includedir)/cif++
|
||||
for f in $(HEADERS); do install include/cif++/$$f $(includedir)/cif++/$$f; done
|
||||
install -d $(pkgconfigdir)
|
||||
install -m 644 $(LIB_NAME).pc $(pkgconfigdir)/$(LIB_NAME).pc
|
||||
|
||||
.PHONY: install
|
||||
install: install-lib install-dev
|
||||
|
||||
dist-clean: clean
|
||||
|
||||
FORCE:
|
||||
5
LICENSE
5
LICENSE
@@ -1,6 +1,7 @@
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
BSD-2-Clause License
|
||||
|
||||
Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@@ -20,4 +21,4 @@ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
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.
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
229
README.md
229
README.md
@@ -1,32 +1,219 @@
|
||||
[](https://travis-ci.org/PDB-REDO/libcifpp)
|
||||
[](https://github.com/pdb-redo/libcifpp/actions)
|
||||
[](https://github.com/pdb-redo/libcifpp/LICENSE)
|
||||
|
||||
libcif++
|
||||
========
|
||||
# libcifpp
|
||||
|
||||
This library contains code to work with mmCIF and PDB files.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
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>
|
||||
#include <iostream>
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
exit(1);
|
||||
|
||||
// Read file, can be PDB or mmCIF and can even be compressed with gzip.
|
||||
cif::file file = cif::pdb::read(argv[1]);
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Take the first datablock in the file
|
||||
auto &db = file.front();
|
||||
|
||||
// Use the atom_site category
|
||||
auto &atom_site = db["atom_site"];
|
||||
|
||||
// Count the atoms with atom-id "OXT"
|
||||
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\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++
|
||||
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 << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 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.3 and clang 9.0
|
||||
have been used.
|
||||
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`.
|
||||
|
||||
- GNU make version 4.1 or higher.
|
||||
- Boost libraries, at least version 1.71
|
||||
- [mrc](https://github.com/mhekkel/mrc), a resource compiler that
|
||||
allows including data files into the executable making them easier to
|
||||
install. Strictly this is optional, but at the expense of a lot of
|
||||
functionality.
|
||||
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.
|
||||
|
||||
Building
|
||||
--------
|
||||
Other libraries you might want to install beforehand are:
|
||||
|
||||
Simply configure, make and make install.
|
||||
- [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](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`.
|
||||
|
||||
There's one configure flag that might be of interest: if you specify
|
||||
DEBUG=1 the make will create a debug version by default. Otherwise,
|
||||
you can run make with DEBUG=1 to create a debug version.
|
||||
### Building
|
||||
|
||||
First you need to download the code:
|
||||
|
||||
```console
|
||||
git clone https://github.com/PDB-REDO/libcifpp.git
|
||||
cd libcifpp
|
||||
```
|
||||
|
||||
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*.
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
1685
aclocal.m4
vendored
1685
aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
322
changelog
Normal file
322
changelog
Normal file
@@ -0,0 +1,322 @@
|
||||
Version 10.0.4
|
||||
- Fixed find_by_value in the index of a category,
|
||||
avoid swapping columns in the search keys
|
||||
|
||||
Version 10.0.3
|
||||
- Clear pdbx_nonpoly_scheme before filling it in reconstruction
|
||||
- Changed handling of numbers with a preceding plus character,
|
||||
these are now stored as strings to avoid inadvertently
|
||||
mutilating phone numbers.
|
||||
|
||||
Version 10.0.2
|
||||
- Fixed regression in reconstruction introduced in 10.0.1
|
||||
- Fixed symmetry operations
|
||||
- Added validation for pdbx_item_enumeration as well as
|
||||
case-sensitive checks for enumerations when needed.
|
||||
|
||||
Version 10.0.1
|
||||
- Fixed some regressions, like assigning to items.
|
||||
- At emplace time (in category) values that are
|
||||
in the wrong type according to a dictionary
|
||||
will be converted/casted. May fail of course.
|
||||
|
||||
Version 10.0.0
|
||||
- Major rewrite of the internal storage of values.
|
||||
Used to be strings only, now there are several
|
||||
basic types.
|
||||
- Modernised code and cleaned up warnings using lint
|
||||
tools
|
||||
|
||||
Version 9.0.6
|
||||
- Various small fixes
|
||||
Version 10.0.0
|
||||
- Added a SQLite interface.
|
||||
|
||||
Version 9.0.5
|
||||
- Added exists to compound_factory
|
||||
- Added sub_matrix, fix and extend determinant calculation
|
||||
- Added yet another structure::create_non_poly
|
||||
- Remove revision.hpp file in make clean (new VersionString.cmake)
|
||||
|
||||
Version 9.0.4
|
||||
- Fix various stopping and reconstruction errors
|
||||
|
||||
Version 9.0.3
|
||||
- Reconstruction fixed when some entity ids are missing
|
||||
|
||||
Version 9.0.2
|
||||
- Fix code that reconstructs sequences, could throw a map::at
|
||||
- Many optimisations in validation and reconstruction code.
|
||||
|
||||
Version 9.0.1
|
||||
- Use pcre2 from pkg-config if available, if not
|
||||
build a version from the original code.
|
||||
|
||||
Version 9.0.0
|
||||
- Rename fields of cif::mm::polymer to match the naming
|
||||
in mmcif_pdbx.dic. Also, related, fix building mm::structure
|
||||
using the correct mapping between atom_site and residues.
|
||||
- _atom_site.auth_alt_id does not exist, it should be
|
||||
_atom_site.pdbx_auth_alt_id of course.
|
||||
- Added a more lightweight fixup for mmcif_pdbx files
|
||||
that lack certain categories.
|
||||
|
||||
Version 8.0.1
|
||||
- Fix cif::mm::structure::cleanup_empty_categories, removed too much
|
||||
- Add default value for B_iso_or_equiv in residue::create_new_atom
|
||||
- Reconstruct some branch records in bare pdbx files
|
||||
- Fix parsing PDB files (bug due to missing validator in dest. cat.)
|
||||
- Do not fail conversion of PDB files when compound info is missing
|
||||
|
||||
Version 8.0.0
|
||||
- A dictionary is for a datablock and a file can have
|
||||
datablocks with differing dictionaries.
|
||||
|
||||
Version 7.0.10
|
||||
- Deal with missing _entity.type in reconstructing mmCIF files
|
||||
- Replace code creating quaternions from rotation matrices
|
||||
that might sometimes give incorrect results. Or at least,
|
||||
the test code failed on this particular kind of code. Sometimes.
|
||||
- Fix reconstruction to build pdbx_nonpoly_scheme
|
||||
|
||||
Version 7.0.9
|
||||
- Using cif::file::load_dictionary it is now possible to
|
||||
load a dictionary along with its extensions in one go.
|
||||
E.g. file.load_dictionary("mmcif_pdbx;dssp-extension")
|
||||
- Fix in compound factory to avoid errors with lower case
|
||||
compound id's
|
||||
- Fix sac_parser's index to be case insensitive
|
||||
|
||||
Version 7.0.8
|
||||
- Fix PDB Remark 3 parser
|
||||
- Added three way comparison for point
|
||||
|
||||
Version 7.0.7
|
||||
- Set CIFPP_DATA_DIR on target cifpp for use in projects that include
|
||||
libcifpp directly
|
||||
|
||||
Version 7.0.6
|
||||
- Fix linking to std::atomic
|
||||
|
||||
Version 7.0.5
|
||||
- Fix case where category index was not updated for updated value
|
||||
|
||||
Version 7.0.4
|
||||
- Do not install headers and library in case we're not the top project
|
||||
|
||||
Version 7.0.3
|
||||
- Fix installation, write exports.hpp again
|
||||
|
||||
Version 7.0.2
|
||||
- Fix in testing error_code results.
|
||||
|
||||
Version 7.0.1
|
||||
- Various reconstruction fixes
|
||||
- category order in output fixed
|
||||
- better implementation of constructors for file, datablock and category
|
||||
- small optimisation in iterator
|
||||
|
||||
Version 7.0.0
|
||||
- Renaming many methods and parameters to be more
|
||||
consistent with the mmCIF dictionaries.
|
||||
(Most notably, item used to be called column or
|
||||
tag sometimes).
|
||||
- validation_error is now a std::system_error error
|
||||
value. The exception is gone.
|
||||
- Added repairSequenceInfo to repair invalid files
|
||||
|
||||
Version 6.1.0
|
||||
- Add formula weight to entity in pdb2cif
|
||||
- Change order of categories inside a datablock to match order in file
|
||||
- Change default order to write out categories in a file based on
|
||||
parent/child relationship
|
||||
- Added validate_pdbx and recover_pdbx
|
||||
- Fixed a serious bug in category_index when moving categories
|
||||
|
||||
Version 6.0.0
|
||||
- Drop the use of CCP4's monomer library for compound information
|
||||
|
||||
Version 5.2.5
|
||||
- Correctly import the Eigen3 library
|
||||
|
||||
Version 5.2.4
|
||||
- Changes required to build on Windows
|
||||
|
||||
Version 5.2.3
|
||||
- New constructors for cif::item, one taking std::optional values
|
||||
and another taking only a name resulting in a value '.' (i.e. inapplicable).
|
||||
- added cif::cell::get_volume
|
||||
|
||||
Version 5.2.2
|
||||
- Remove dependency on Eigen3 for users of libcifpp
|
||||
- Fix typos in documentation
|
||||
- Do not build latex files in documentation
|
||||
- Fixed conversion from string to integer, would fail on +2 e.g.
|
||||
- sqrt is not constexpr, thus kGoldenRatio should be const, not constexpr
|
||||
|
||||
Version 5.2.1
|
||||
- New versionstring module
|
||||
- small fixes for generating documentation
|
||||
- correctly setting SONAME
|
||||
|
||||
Version 5.2.0
|
||||
- With lots of documentation
|
||||
- Refactored coloured text output
|
||||
- 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
|
||||
|
||||
Version 5.1.1
|
||||
- Added missing include <compare> in symmetry.hpp
|
||||
- Added empty() to matrix
|
||||
- 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
|
||||
- Fix in unique ID generator
|
||||
|
||||
Version 5.0.10
|
||||
- Fix in progress_bar, was using too much CPU
|
||||
- Optimised mmCIF parser
|
||||
|
||||
Version 5.0.9
|
||||
- Fix in dihedral angle calculations
|
||||
- Added create_water to model
|
||||
- Writing twin domain info in PDB files and more PDB fixes
|
||||
- remove_atom improved (remove struct_conn records)
|
||||
- Added a specialisation for category::find1<std::optional>
|
||||
- fix memory leak in category
|
||||
|
||||
Version 5.0.8
|
||||
- implemented find_first, find_min, find_max and count in category
|
||||
- find1 now throws an exception if condition does not not exactly match one row
|
||||
- Change in writing out PDB files, now looking up the original auth_seq_num
|
||||
via the pdbx_xxx_scheme categories based on the atom_site.auth_seq_num ->
|
||||
pdbx_xxx_scheme.pdb_seq_num relationship.
|
||||
- fix memory leak in category
|
||||
|
||||
Version 5.0.7.1
|
||||
- Use the implementation from zeep for std::experimental::is_detected
|
||||
|
||||
Version 5.0.7
|
||||
- Reintroduce exports file. For DLL's
|
||||
|
||||
Version 5.0.6
|
||||
- Fix file::contains, using iequals
|
||||
- Fix is_cis
|
||||
|
||||
Version 5.0.5
|
||||
- Fix code to work on 32 bit machines
|
||||
|
||||
Version 5.0.4
|
||||
- Revert removal of CIFPP_SHARE_DIR export
|
||||
|
||||
Version 5.0.3
|
||||
- Fix installation of libcifpp into the correct locations
|
||||
|
||||
Version 5.0.2
|
||||
- Fix export of CISPEP records in PDB format
|
||||
- Better support for exporting package_source
|
||||
|
||||
Version 5.0.1
|
||||
- Fix loading dictionaries
|
||||
- Support for cifv1.0 files
|
||||
|
||||
Version 5.0.0
|
||||
- Total rewrite of cif part
|
||||
- Removed DSSP code, moved into dssp project itself
|
||||
|
||||
Version 4.2.1
|
||||
- Improved REMARK 3 parser (for TLS in large molecules)
|
||||
|
||||
Version 4.2.0
|
||||
- Yet another rewrite of resource loading
|
||||
|
||||
Version 4.1.1
|
||||
- Fall back to zero charge for scattering factors if the atom
|
||||
was not found in the table.
|
||||
- Improve code to locate resources, failing less.
|
||||
|
||||
Version 4.1.0
|
||||
- Some interface changes for mmcif::Atom
|
||||
|
||||
Version 4.0.1
|
||||
- Added a bunch of const methods to Datablock and Category.
|
||||
- Changed PDB writing interface to accept Datablock instead of File.
|
||||
|
||||
Version 4.0.0
|
||||
- getResidue in mmcif::Structure now requires both a
|
||||
sequence ID and an auth sequence ID. As a result the code was cleaned
|
||||
up considerably.
|
||||
|
||||
Version 3.0.5
|
||||
- mmcif::Structure redesign. It is now a wrapper around a cif::Datablock.
|
||||
|
||||
Version 3.0.4
|
||||
- Fix in mmCIF parser, now correctly handles the unquoted
|
||||
string ??
|
||||
|
||||
Version 3.0.3
|
||||
- Better configuration checks, for atomic e.g.
|
||||
- Fixed a problem introduced in refactoring mmcif::Atom
|
||||
- Version string creation
|
||||
|
||||
Version 3.0.2
|
||||
- refactored mmcif::Atom for performance reasons
|
||||
|
||||
Version 3.0.1
|
||||
- Fixed processing of proline restraints file from CCP4, proline
|
||||
is a peptide, really.
|
||||
- Added code to facilitate DSSP
|
||||
|
||||
Version 3.0.0
|
||||
- Replaced many strings in the API with string_view for
|
||||
performance reasons.
|
||||
- Upgraded mmcif::Structure
|
||||
- various other small fixes
|
||||
|
||||
Version 2.0.5
|
||||
- Backporting updated CMakeLists.txt file
|
||||
|
||||
Version 2.0.4
|
||||
- Reverted a too strict test when reading cif files.
|
||||
|
||||
Version 2.0.3
|
||||
- Fixed reading mmCIF files where model numbers are used and
|
||||
model number 1 is missing.
|
||||
|
||||
Version 2.0.2
|
||||
- Added configuration flag to disable downloading CCD data during build
|
||||
Note that there are now two flags for CCD data:
|
||||
DOWNLOAD_CCD to enable downloading during build
|
||||
INSTALL_UPDATE_SCRIPT to install an update mechanism for this file
|
||||
- Updated unit tests to work even if no CCD data is available
|
||||
|
||||
Version 2.0.1
|
||||
- Fixed the generator for the symmetry operator table
|
||||
|
||||
Version 2.0.0
|
||||
- New API interface for accessing query results
|
||||
- Removed bzip2 support
|
||||
- improved makefiles
|
||||
|
||||
Version 1.1.1
|
||||
- Now with full support for MS Windows
|
||||
|
||||
Version 1.1.0
|
||||
- Changed from GNU configure to CMake.
|
||||
- Loading compound information from CCD file
|
||||
|
||||
Version 1.0.1
|
||||
- Changed the way resources are looked up, local dir first,
|
||||
then /var/cache and finally compiled in resources (with mrc).
|
||||
|
||||
Version 1.0.0
|
||||
- First public release
|
||||
87
cmake/FindAtomic.cmake
Normal file
87
cmake/FindAtomic.cmake
Normal file
@@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
|
||||
# Simple check to see if we need a library for std::atomic
|
||||
|
||||
if(TARGET std::atomic)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckIncludeFileCXX)
|
||||
include(CheckCXXSourceRuns)
|
||||
|
||||
cmake_push_check_state()
|
||||
|
||||
check_include_file_cxx("atomic" _CXX_ATOMIC_HAVE_HEADER)
|
||||
mark_as_advanced(_CXX_ATOMIC_HAVE_HEADER)
|
||||
|
||||
set(code [[
|
||||
#include <atomic>
|
||||
int main(int argc, char** argv) {
|
||||
std::atomic<long long> s;
|
||||
++s;
|
||||
return 0;
|
||||
}
|
||||
]])
|
||||
|
||||
check_cxx_source_runs("${code}" _CXX_ATOMIC_BUILTIN)
|
||||
|
||||
if(_CXX_ATOMIC_BUILTIN)
|
||||
set(_found 1)
|
||||
else()
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES atomic)
|
||||
list(APPEND FOLLY_LINK_LIBRARIES atomic)
|
||||
|
||||
check_cxx_source_runs("${code}" _CXX_ATOMIC_LIB_NEEDED)
|
||||
if (NOT _CXX_ATOMIC_LIB_NEEDED)
|
||||
message(FATAL_ERROR "unable to link C++ std::atomic code: you may need \
|
||||
to install GNU libatomic")
|
||||
else()
|
||||
set(_found 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_found)
|
||||
add_library(std::atomic INTERFACE IMPORTED)
|
||||
set_property(TARGET std::atomic APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_14)
|
||||
|
||||
if(_CXX_ATOMIC_BUILTIN)
|
||||
# Nothing to add...
|
||||
elseif(_CXX_ATOMIC_LIB_NEEDED)
|
||||
set_target_properties(std::atomic PROPERTIES IMPORTED_LIBNAME atomic)
|
||||
set(STDCPPATOMIC_LIBRARY atomic)
|
||||
endif()
|
||||
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")
|
||||
endif()
|
||||
36
cmake/FindPCRE2.cmake
Normal file
36
cmake/FindPCRE2.cmake
Normal file
@@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
#
|
||||
# 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})
|
||||
36
cmake/FindSphinx.cmake
Normal file
36
cmake/FindSphinx.cmake
Normal file
@@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
#
|
||||
#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)
|
||||
275
cmake/VersionString.cmake
Normal file
275
cmake/VersionString.cmake
Normal file
@@ -0,0 +1,275 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
# Copyright (c) 2021-2023 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.
|
||||
|
||||
# This cmake extension writes out a revision.hpp file in a specified directory.
|
||||
# The file will contain a C++ inline function that can be used to write out
|
||||
# version information.
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# We want the revision.hpp file to be updated whenever the status of the
|
||||
# git repository changes. Use the same technique as in GetGitRevisionDescription.cmake
|
||||
# from https://github.com/rpavlik/cmake-modules
|
||||
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
.. command:: write_version_header
|
||||
|
||||
Write a file named revision.hpp containing version info::
|
||||
|
||||
write_version_header(<destdir>
|
||||
[FILE_NAME <file-name>]
|
||||
[LIB_NAME <library-name>]
|
||||
)
|
||||
|
||||
This command will generate the code to write a file name
|
||||
revision.hpp in the directory ``<destdir>``.
|
||||
|
||||
``FILE_NAME``
|
||||
Specify the name of the file to create, default is ``revision.hpp``.
|
||||
|
||||
``LIB_NAME``
|
||||
Specify the library name which will be used as a prefix part for the
|
||||
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)
|
||||
|
||||
set(cur_dir "${_start_dir}")
|
||||
set(git_dir "${_start_dir}/.git")
|
||||
|
||||
while(NOT EXISTS "${git_dir}")
|
||||
# .git dir not found, search parent directories
|
||||
set(prev_dir "${cur_dir}")
|
||||
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||
if(cur_dir STREQUAL prev_dir OR cur_dir STREQUAL ${_start_dir})
|
||||
# we are not in git since we either hit root or
|
||||
# the ${_start_dir} which should be the top
|
||||
set(${_variable} "" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(git_dir "${cur_dir}/.git")
|
||||
endwhile()
|
||||
|
||||
set(${_variable} "${git_dir}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Locate the git refspec hash and load the hash
|
||||
# This code locates the file containing the git refspec/hash
|
||||
# and loads it. Doing it this way assures that each time the git
|
||||
# repository changes the revision.hpp file gets out of date.
|
||||
function(_get_git_hash _data_dir _variable)
|
||||
|
||||
# Be pessimistic
|
||||
set(_variable "" PARENT_SCOPE)
|
||||
|
||||
# Load git package if needed
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
|
||||
# And fail if not found
|
||||
if(NOT GIT_FOUND)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Locate the nearest .git file or directory
|
||||
_get_git_dir(${CMAKE_CURRENT_SOURCE_DIR} GIT_DIR)
|
||||
|
||||
# And fail if not found
|
||||
if("${GIT_DIR}" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check if the current source dir is a git submodule or a worktree.
|
||||
# In both cases .git is a file instead of a directory.
|
||||
#
|
||||
if(IS_DIRECTORY ${GIT_DIR})
|
||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||
else()
|
||||
# The following git command will return a non empty string that
|
||||
# points to the super project working tree if the current
|
||||
# source dir is inside a git submodule.
|
||||
# Otherwise the command will return an empty string.
|
||||
#
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||
--show-superproject-working-tree
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT "${out}" STREQUAL "")
|
||||
# If out is not empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||
${submodule})
|
||||
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||
ABSOLUTE)
|
||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||
else()
|
||||
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||
file(READ ${GIT_DIR} worktree_ref)
|
||||
# The .git directory contains a path to the worktree information directory
|
||||
# inside the parent git repo of the worktree.
|
||||
#
|
||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||
${worktree_ref})
|
||||
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||
_get_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Fail if the 'head' file was not found
|
||||
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Make a copy of the head file
|
||||
set(HEAD_FILE "${_data_dir}/HEAD")
|
||||
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
# Now we create a cmake file that will read the contents of this
|
||||
# head file in the appropriate way
|
||||
file(WRITE "${_data_dir}/grab-ref.cmake.in" [[
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@VERSION_STRING_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@VERSION_STRING_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@VERSION_STRING_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@VERSION_STRING_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@VERSION_STRING_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
]])
|
||||
|
||||
configure_file("${VERSION_STRING_DATA}/grab-ref.cmake.in"
|
||||
"${VERSION_STRING_DATA}/grab-ref.cmake" @ONLY)
|
||||
|
||||
# Include the aforementioned file, this will define
|
||||
# the HEAD_HASH variable we're looking for
|
||||
include("${VERSION_STRING_DATA}/grab-ref.cmake")
|
||||
|
||||
set(${_variable} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Create a revision file, containing the current git version info, if any
|
||||
function(write_version_header dir)
|
||||
|
||||
set(flags )
|
||||
set(options LIB_NAME FILE_NAME)
|
||||
set(sources )
|
||||
cmake_parse_arguments(VERSION_STRING_OPTION "${flags}" "${options}" "${sources}" ${ARGN})
|
||||
|
||||
# parameter check
|
||||
if(NOT IS_DIRECTORY ${dir})
|
||||
message(FATAL_ERROR "First parameter to write_version_header should be a directory where the final revision.hpp file will be placed")
|
||||
endif()
|
||||
|
||||
if(VERSION_STRING_OPTION_FILE_NAME)
|
||||
set(file_name "${VERSION_STRING_OPTION_FILE_NAME}")
|
||||
else()
|
||||
set(file_name "revision.hpp")
|
||||
endif()
|
||||
|
||||
# Where to store intermediate files
|
||||
set(VERSION_STRING_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/VersionString")
|
||||
if(NOT EXISTS "${VERSION_STRING_DATA}")
|
||||
file(MAKE_DIRECTORY "${VERSION_STRING_DATA}")
|
||||
endif()
|
||||
|
||||
# Load the git hash using the wizzard-like code above.
|
||||
_get_git_hash("${VERSION_STRING_DATA}" GIT_HASH)
|
||||
|
||||
# If git was found, fetch the git description string
|
||||
if(GIT_HASH)
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" describe --dirty --match=build
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if(res EQUAL 0)
|
||||
set(REVISION_STRING "${out}")
|
||||
else()
|
||||
message(STATUS "Git hash not found, does this project have a 'build' tag?")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Git hash not found")
|
||||
endif()
|
||||
|
||||
# Check the revision string, if it matches we fill in the required info
|
||||
if(REVISION_STRING MATCHES "build-([0-9]+)-g([0-9a-f]+)(-dirty)?")
|
||||
set(BUILD_NUMBER ${CMAKE_MATCH_1})
|
||||
if(CMAKE_MATCH_3)
|
||||
set(REVISION_GIT_TAGREF "${CMAKE_MATCH_2}*")
|
||||
else()
|
||||
set(REVISION_GIT_TAGREF "${CMAKE_MATCH_2}")
|
||||
endif()
|
||||
|
||||
string(TIMESTAMP REVISION_DATE_TIME "%Y-%m-%dT%H:%M:%SZ" UTC)
|
||||
else()
|
||||
set(REVISION_GIT_TAGREF "")
|
||||
set(BUILD_NUMBER 0)
|
||||
set(REVISION_DATE_TIME "")
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
configure_file("${_current_cmake_module_dir}/revision.hpp.in" "${dir}/${file_name}" @ONLY)
|
||||
endfunction()
|
||||
|
||||
13
cmake/cifpp-config.cmake.in
Normal file
13
cmake/cifpp-config.cmake.in
Normal file
@@ -0,0 +1,13 @@
|
||||
@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)
|
||||
find_dependency(SQLite3 REQUIRED)
|
||||
|
||||
check_required_components(cifpp)
|
||||
125
cmake/revision.hpp.in
Normal file
125
cmake/revision.hpp.in
Normal file
@@ -0,0 +1,125 @@
|
||||
// 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) noexcept
|
||||
: m_name(name)
|
||||
, m_version(version)
|
||||
, m_build_number(build_number)
|
||||
, m_git_tag(git_tag)
|
||||
, m_revision_date(revision_date)
|
||||
{
|
||||
if (is_main)
|
||||
registered_main() = this;
|
||||
else
|
||||
{
|
||||
auto &s_head = registered_libraries();
|
||||
m_next = s_head;
|
||||
s_head = this;
|
||||
}
|
||||
}
|
||||
|
||||
void write(std::ostream &os, bool verbose)
|
||||
{
|
||||
os << m_name << " version " << m_version << '\n';
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
if (m_build_number != 0)
|
||||
{
|
||||
os << "build: " << m_build_number << ' ' << m_revision_date << '\n';
|
||||
if (m_git_tag[0] != 0)
|
||||
os << "git tag: " << m_git_tag << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using version_info_ptr = version_info_base *;
|
||||
|
||||
static version_info_ptr ®istered_main() noexcept
|
||||
{
|
||||
static version_info_ptr s_main = nullptr;
|
||||
return s_main;
|
||||
}
|
||||
|
||||
static version_info_ptr ®istered_libraries() noexcept
|
||||
{
|
||||
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;
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
version_info(const char *name, const char *version, int build_number,
|
||||
const char *git_tag, const char *revision_date, bool is_main) noexcept
|
||||
: 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() noexcept
|
||||
: 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;
|
||||
43
cmake/test-charconv.cpp
Normal file
43
cmake/test-charconv.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 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.
|
||||
*/
|
||||
|
||||
#include <charconv>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
int main()
|
||||
{
|
||||
float v;
|
||||
char s[] = "1.0";
|
||||
|
||||
auto r = std::from_chars(s, s + strlen(s), v);
|
||||
|
||||
assert(r.ec == std::errc{});
|
||||
assert(r.ptr = s + strlen(s));
|
||||
assert(v == 1.0f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#include <algorithm>
|
||||
|
||||
template<typename COMP>
|
||||
class foo
|
||||
{
|
||||
public:
|
||||
foo(int a, COMP&& b)
|
||||
: m_a(a), m_b(std::move(b)) {}
|
||||
|
||||
int m_a;
|
||||
COMP m_b;
|
||||
};
|
||||
|
||||
void bar(const int& b)
|
||||
{
|
||||
int c = 1;
|
||||
auto f = new foo(c, [tag = c, b](const int& x)
|
||||
{ x < b; });
|
||||
}
|
||||
1480
config/config.guess
vendored
1480
config/config.guess
vendored
File diff suppressed because it is too large
Load Diff
1801
config/config.sub
vendored
1801
config/config.sub
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,518 +0,0 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2018-03-11.20; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
# Note that $RANDOM variable is not portable (e.g. dash); Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
|
||||
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p' feature.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
11251
config/ltmain.sh
11251
config/ltmain.sh
File diff suppressed because it is too large
Load Diff
8394
config/m4/libtool.m4
vendored
8394
config/m4/libtool.m4
vendored
File diff suppressed because it is too large
Load Diff
437
config/m4/ltoptions.m4
vendored
437
config/m4/ltoptions.m4
vendored
@@ -1,437 +0,0 @@
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8 ltoptions.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
|
||||
|
||||
|
||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ------------------------------------------
|
||||
m4_define([_LT_MANGLE_OPTION],
|
||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
|
||||
# ---------------------------------------
|
||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
|
||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
|
||||
# saved as a flag.
|
||||
m4_define([_LT_SET_OPTION],
|
||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
|
||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
_LT_MANGLE_DEFUN([$1], [$2]),
|
||||
[m4_warning([Unknown $1 option '$2'])])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
|
||||
# ------------------------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
m4_define([_LT_IF_OPTION],
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
|
||||
|
||||
|
||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
|
||||
# -------------------------------------------------------
|
||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
|
||||
# are set.
|
||||
m4_define([_LT_UNLESS_OPTIONS],
|
||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
|
||||
[m4_define([$0_found])])])[]dnl
|
||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
|
||||
])[]dnl
|
||||
])
|
||||
|
||||
|
||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
|
||||
# ----------------------------------------
|
||||
# OPTION-LIST is a space-separated list of Libtool options associated
|
||||
# with MACRO-NAME. If any OPTION has a matching handler declared with
|
||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
|
||||
# the unknown option and exit.
|
||||
m4_defun([_LT_SET_OPTIONS],
|
||||
[# Set options
|
||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
||||
[_LT_SET_OPTION([$1], _LT_Option)])
|
||||
|
||||
m4_if([$1],[LT_INIT],[
|
||||
dnl
|
||||
dnl Simply set some default values (i.e off) if boolean options were not
|
||||
dnl specified:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
|
||||
])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
|
||||
])
|
||||
dnl
|
||||
dnl If no reference was made to various pairs of opposing options, then
|
||||
dnl we run the default mode handler for the pair. For example, if neither
|
||||
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
|
||||
dnl archives by default:
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
|
||||
[_LT_ENABLE_FAST_INSTALL])
|
||||
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
|
||||
[_LT_WITH_AIX_SONAME([aix])])
|
||||
])
|
||||
])# _LT_SET_OPTIONS
|
||||
|
||||
|
||||
## --------------------------------- ##
|
||||
## Macros to handle LT_INIT options. ##
|
||||
## --------------------------------- ##
|
||||
|
||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
|
||||
# -----------------------------------------
|
||||
m4_define([_LT_MANGLE_DEFUN],
|
||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
|
||||
|
||||
|
||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
|
||||
# -----------------------------------------------
|
||||
m4_define([LT_OPTION_DEFINE],
|
||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
|
||||
])# LT_OPTION_DEFINE
|
||||
|
||||
|
||||
# dlopen
|
||||
# ------
|
||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_DLOPEN],
|
||||
[_LT_SET_OPTION([LT_INIT], [dlopen])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'dlopen' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
|
||||
|
||||
|
||||
# win32-dll
|
||||
# ---------
|
||||
# Declare package support for building win32 dll's.
|
||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
|
||||
[enable_win32_dll=yes
|
||||
|
||||
case $host in
|
||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
|
||||
AC_CHECK_TOOL(AS, as, false)
|
||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
||||
AC_CHECK_TOOL(OBJDUMP, objdump, false)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -z "$AS" && AS=as
|
||||
_LT_DECL([], [AS], [1], [Assembler program])dnl
|
||||
|
||||
test -z "$DLLTOOL" && DLLTOOL=dlltool
|
||||
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
|
||||
|
||||
test -z "$OBJDUMP" && OBJDUMP=objdump
|
||||
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
|
||||
])# win32-dll
|
||||
|
||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
|
||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
_LT_SET_OPTION([LT_INIT], [win32-dll])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'win32-dll' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
|
||||
|
||||
|
||||
# _LT_ENABLE_SHARED([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-shared flag, and supports the 'shared' and
|
||||
# 'disable-shared' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_SHARED],
|
||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([shared],
|
||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
|
||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_shared=yes ;;
|
||||
no) enable_shared=no ;;
|
||||
*)
|
||||
enable_shared=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_shared=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
|
||||
|
||||
_LT_DECL([build_libtool_libs], [enable_shared], [0],
|
||||
[Whether or not to build shared libraries])
|
||||
])# _LT_ENABLE_SHARED
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_SHARED],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-shared])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
|
||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_STATIC([DEFAULT])
|
||||
# ----------------------------
|
||||
# implement the --enable-static flag, and support the 'static' and
|
||||
# 'disable-static' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_STATIC],
|
||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([static],
|
||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
|
||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_static=yes ;;
|
||||
no) enable_static=no ;;
|
||||
*)
|
||||
enable_static=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_static=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
|
||||
|
||||
_LT_DECL([build_old_libs], [enable_static], [0],
|
||||
[Whether or not to build static libraries])
|
||||
])# _LT_ENABLE_STATIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
|
||||
|
||||
# Old names:
|
||||
AC_DEFUN([AC_ENABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
|
||||
])
|
||||
|
||||
AC_DEFUN([AC_DISABLE_STATIC],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-static])
|
||||
])
|
||||
|
||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
|
||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
|
||||
|
||||
|
||||
|
||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --enable-fast-install flag, and support the 'fast-install'
|
||||
# and 'disable-fast-install' LT_INIT options.
|
||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
||||
m4_define([_LT_ENABLE_FAST_INSTALL],
|
||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
||||
AC_ARG_ENABLE([fast-install],
|
||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
|
||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
|
||||
[p=${PACKAGE-default}
|
||||
case $enableval in
|
||||
yes) enable_fast_install=yes ;;
|
||||
no) enable_fast_install=no ;;
|
||||
*)
|
||||
enable_fast_install=no
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for pkg in $enableval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$pkg" = "X$p"; then
|
||||
enable_fast_install=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
|
||||
|
||||
_LT_DECL([fast_install], [enable_fast_install], [0],
|
||||
[Whether or not to optimize for fast installation])dnl
|
||||
])# _LT_ENABLE_FAST_INSTALL
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
|
||||
|
||||
# Old names:
|
||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
|
||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
||||
the 'disable-fast-install' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
|
||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
|
||||
|
||||
|
||||
# _LT_WITH_AIX_SONAME([DEFAULT])
|
||||
# ----------------------------------
|
||||
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
|
||||
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
|
||||
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
|
||||
m4_define([_LT_WITH_AIX_SONAME],
|
||||
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
|
||||
shared_archive_member_spec=
|
||||
case $host,$enable_shared in
|
||||
power*-*-aix[[5-9]]*,yes)
|
||||
AC_MSG_CHECKING([which variant of shared library versioning to provide])
|
||||
AC_ARG_WITH([aix-soname],
|
||||
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
|
||||
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
|
||||
[case $withval in
|
||||
aix|svr4|both)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
|
||||
;;
|
||||
esac
|
||||
lt_cv_with_aix_soname=$with_aix_soname],
|
||||
[AC_CACHE_VAL([lt_cv_with_aix_soname],
|
||||
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
|
||||
with_aix_soname=$lt_cv_with_aix_soname])
|
||||
AC_MSG_RESULT([$with_aix_soname])
|
||||
if test aix != "$with_aix_soname"; then
|
||||
# For the AIX way of multilib, we name the shared archive member
|
||||
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
|
||||
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
|
||||
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
|
||||
# the AIX toolchain works better with OBJECT_MODE set (default 32).
|
||||
if test 64 = "${OBJECT_MODE-32}"; then
|
||||
shared_archive_member_spec=shr_64
|
||||
else
|
||||
shared_archive_member_spec=shr
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
with_aix_soname=aix
|
||||
;;
|
||||
esac
|
||||
|
||||
_LT_DECL([], [shared_archive_member_spec], [0],
|
||||
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
|
||||
])# _LT_WITH_AIX_SONAME
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
|
||||
|
||||
|
||||
# _LT_WITH_PIC([MODE])
|
||||
# --------------------
|
||||
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
|
||||
# LT_INIT options.
|
||||
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
|
||||
m4_define([_LT_WITH_PIC],
|
||||
[AC_ARG_WITH([pic],
|
||||
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
|
||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
|
||||
[lt_p=${PACKAGE-default}
|
||||
case $withval in
|
||||
yes|no) pic_mode=$withval ;;
|
||||
*)
|
||||
pic_mode=default
|
||||
# Look at the argument we got. We use all the common list separators.
|
||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
||||
for lt_pkg in $withval; do
|
||||
IFS=$lt_save_ifs
|
||||
if test "X$lt_pkg" = "X$lt_p"; then
|
||||
pic_mode=yes
|
||||
fi
|
||||
done
|
||||
IFS=$lt_save_ifs
|
||||
;;
|
||||
esac],
|
||||
[pic_mode=m4_default([$1], [default])])
|
||||
|
||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
|
||||
])# _LT_WITH_PIC
|
||||
|
||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
|
||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
|
||||
|
||||
# Old name:
|
||||
AU_DEFUN([AC_LIBTOOL_PICMODE],
|
||||
[_LT_SET_OPTION([LT_INIT], [pic-only])
|
||||
AC_DIAGNOSE([obsolete],
|
||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
put the 'pic-only' option into LT_INIT's first parameter.])
|
||||
])
|
||||
|
||||
dnl aclocal-1.4 backwards compatibility:
|
||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
|
||||
|
||||
## ----------------- ##
|
||||
## LTDL_INIT Options ##
|
||||
## ----------------- ##
|
||||
|
||||
m4_define([_LTDL_MODE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
|
||||
[m4_define([_LTDL_MODE], [nonrecursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
|
||||
[m4_define([_LTDL_MODE], [recursive])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
|
||||
[m4_define([_LTDL_MODE], [subproject])])
|
||||
|
||||
m4_define([_LTDL_TYPE], [])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [installable],
|
||||
[m4_define([_LTDL_TYPE], [installable])])
|
||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
|
||||
[m4_define([_LTDL_TYPE], [convenience])])
|
||||
124
config/m4/ltsugar.m4
vendored
124
config/m4/ltsugar.m4
vendored
@@ -1,124 +0,0 @@
|
||||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Gary V. Vaughan, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 6 ltsugar.m4
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
|
||||
|
||||
|
||||
# lt_join(SEP, ARG1, [ARG2...])
|
||||
# -----------------------------
|
||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
|
||||
# associated separator.
|
||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
|
||||
# versions in m4sugar had bugs.
|
||||
m4_define([lt_join],
|
||||
[m4_if([$#], [1], [],
|
||||
[$#], [2], [[$2]],
|
||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
m4_define([_lt_join],
|
||||
[m4_if([$#$2], [2], [],
|
||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
|
||||
|
||||
|
||||
# lt_car(LIST)
|
||||
# lt_cdr(LIST)
|
||||
# ------------
|
||||
# Manipulate m4 lists.
|
||||
# These macros are necessary as long as will still need to support
|
||||
# Autoconf-2.59, which quotes differently.
|
||||
m4_define([lt_car], [[$1]])
|
||||
m4_define([lt_cdr],
|
||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
|
||||
[$#], 1, [],
|
||||
[m4_dquote(m4_shift($@))])])
|
||||
m4_define([lt_unquote], $1)
|
||||
|
||||
|
||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
|
||||
# ------------------------------------------
|
||||
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
|
||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended
|
||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
|
||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
|
||||
# than defined and empty).
|
||||
#
|
||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier
|
||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
|
||||
m4_define([lt_append],
|
||||
[m4_define([$1],
|
||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
|
||||
|
||||
|
||||
|
||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
|
||||
# ----------------------------------------------------------
|
||||
# Produce a SEP delimited list of all paired combinations of elements of
|
||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
|
||||
# has the form PREFIXmINFIXSUFFIXn.
|
||||
# Needed until we can rely on m4_combine added in Autoconf 2.62.
|
||||
m4_define([lt_combine],
|
||||
[m4_if(m4_eval([$# > 3]), [1],
|
||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
|
||||
[[m4_foreach([_Lt_prefix], [$2],
|
||||
[m4_foreach([_Lt_suffix],
|
||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
|
||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
|
||||
|
||||
|
||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
|
||||
# -----------------------------------------------------------------------
|
||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
|
||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
|
||||
m4_define([lt_if_append_uniq],
|
||||
[m4_ifdef([$1],
|
||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
|
||||
[lt_append([$1], [$2], [$3])$4],
|
||||
[$5])],
|
||||
[lt_append([$1], [$2], [$3])$4])])
|
||||
|
||||
|
||||
# lt_dict_add(DICT, KEY, VALUE)
|
||||
# -----------------------------
|
||||
m4_define([lt_dict_add],
|
||||
[m4_define([$1($2)], [$3])])
|
||||
|
||||
|
||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
|
||||
# --------------------------------------------
|
||||
m4_define([lt_dict_add_subkey],
|
||||
[m4_define([$1($2:$3)], [$4])])
|
||||
|
||||
|
||||
# lt_dict_fetch(DICT, KEY, [SUBKEY])
|
||||
# ----------------------------------
|
||||
m4_define([lt_dict_fetch],
|
||||
[m4_ifval([$3],
|
||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
|
||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
|
||||
|
||||
|
||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
|
||||
# -----------------------------------------------------------------
|
||||
m4_define([lt_if_dict_fetch],
|
||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
|
||||
[$5],
|
||||
[$6])])
|
||||
|
||||
|
||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
|
||||
# --------------------------------------------------------------
|
||||
m4_define([lt_dict_filter],
|
||||
[m4_if([$5], [], [],
|
||||
[lt_join(m4_quote(m4_default([$4], [[, ]])),
|
||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
|
||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
|
||||
])
|
||||
23
config/m4/ltversion.m4
vendored
23
config/m4/ltversion.m4
vendored
@@ -1,23 +0,0 @@
|
||||
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
||||
#
|
||||
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# @configure_input@
|
||||
|
||||
# serial 4179 ltversion.m4
|
||||
# This file is part of GNU Libtool
|
||||
|
||||
m4_define([LT_PACKAGE_VERSION], [2.4.6])
|
||||
m4_define([LT_PACKAGE_REVISION], [2.4.6])
|
||||
|
||||
AC_DEFUN([LTVERSION_VERSION],
|
||||
[macro_version='2.4.6'
|
||||
macro_revision='2.4.6'
|
||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
||||
_LT_DECL(, macro_revision, 0)
|
||||
])
|
||||
99
config/m4/lt~obsolete.m4
vendored
99
config/m4/lt~obsolete.m4
vendored
@@ -1,99 +0,0 @@
|
||||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
||||
#
|
||||
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
|
||||
# Foundation, Inc.
|
||||
# Written by Scott James Remnant, 2004.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 5 lt~obsolete.m4
|
||||
|
||||
# These exist entirely to fool aclocal when bootstrapping libtool.
|
||||
#
|
||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
|
||||
# which have later been changed to m4_define as they aren't part of the
|
||||
# exported API, or moved to Autoconf or Automake where they belong.
|
||||
#
|
||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
||||
# using a macro with the same name in our local m4/libtool.m4 it'll
|
||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
||||
# and doesn't know about Autoconf macros at all.)
|
||||
#
|
||||
# So we provide this file, which has a silly filename so it's always
|
||||
# included after everything else. This provides aclocal with the
|
||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
||||
# because those macros already exist, or will be overwritten later.
|
||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
||||
#
|
||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
||||
# Yes, that means every name once taken will need to remain here until
|
||||
# we give up compatibility with versions before 1.7, at which point
|
||||
# we need to keep only those names which we still refer to.
|
||||
|
||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
||||
|
||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
||||
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
|
||||
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
|
||||
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
|
||||
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
|
||||
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
|
||||
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
|
||||
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
|
||||
57
configure.ac
57
configure.ac
@@ -1,57 +0,0 @@
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
AC_INIT([libcif++], 1.0, [m.hekkelman@nki.nl])
|
||||
|
||||
dnl Switch to a C++ compiler, and check if it works.
|
||||
AC_LANG(C++)
|
||||
AX_CXX_COMPILE_STDCXX_17([noext])
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-fstandalone-debug], [ CXXFLAGS="$CXXFLAGS -fstandalone-debug" ], , [-Werror])
|
||||
|
||||
AC_CONFIG_SRCDIR([src/Cif++.cpp])
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
AC_CONFIG_MACRO_DIR([config/m4])
|
||||
AC_CONFIG_HEADERS([include/cif++/Config.hpp])
|
||||
|
||||
AC_PREFIX_DEFAULT(/usr/local)
|
||||
|
||||
dnl AC_DEFUN([read_test], [AC_LANG_SOURCE(
|
||||
dnl esyscmd(tools/m4esc.sh config-tests/$1))])
|
||||
dnl
|
||||
dnl AC_MSG_CHECKING([compiler standards compliance])
|
||||
dnl AC_COMPILE_IFELSE(
|
||||
dnl [read_test(cpp-17-test.cpp)], [],
|
||||
dnl [AC_MSG_ERROR([Your c++ compiler is not capable of compiling libcifpp, please upgrade])])
|
||||
dnl AC_MSG_RESULT(ok)
|
||||
|
||||
AC_PROG_INSTALL
|
||||
AC_ENABLE_STATIC
|
||||
AC_DISABLE_SHARED
|
||||
AC_PROG_LIBTOOL
|
||||
AC_SUBST(LIBTOOL_DEPS)
|
||||
|
||||
AC_ARG_VAR([DEBUG], [Build a debug version of the library])
|
||||
|
||||
AC_ARG_VAR([CCP4], [The location where CCP4 is installed])
|
||||
|
||||
AC_PATH_PROG([PKG_CONFIG], [pkg-config])
|
||||
|
||||
AC_CHECK_FUNCS([floor pow rint sqrt strchr strerror])
|
||||
AC_CHECK_HEADERS([sys/ioctl.h])
|
||||
AC_CHECK_HEADERS([termios.h])
|
||||
AC_CHECK_HEADER_STDBOOL
|
||||
AC_CHECK_TYPES([ptrdiff_t])
|
||||
AC_PROG_MAKE_SET
|
||||
|
||||
AX_BOOST_BASE([1.71], [], [
|
||||
AC_MSG_ERROR([Sorry, your boost is not found or not up-to-date.])
|
||||
])
|
||||
AX_BOOST_IOSTREAMS
|
||||
|
||||
AX_CHECK_LIBRARY([LIBZ], [zlib.h], [z], [],
|
||||
[AC_MSG_ERROR([libz not found - compressed files not supported])])
|
||||
AX_CHECK_LIBRARY([LIBBZ2], [bzlib.h], [bz2], [],
|
||||
[AC_MSG_ERROR([libbz2 not found - compressed files not supported])])
|
||||
|
||||
AC_OUTPUT([GNUmakefile
|
||||
libcif++.pc])
|
||||
5
debian/changelog
vendored
5
debian/changelog
vendored
@@ -1,5 +0,0 @@
|
||||
libcifpp (0.1.0-1) unstable; urgency=medium
|
||||
|
||||
* Initial release. (Closes: #XXXXXX)
|
||||
|
||||
-- Maarten L. Hekkelman <maarten@hekkelman.com> Mon, 28 Sep 2020 08:34:16 +0200
|
||||
44
debian/control
vendored
44
debian/control
vendored
@@ -1,44 +0,0 @@
|
||||
Source: libcifpp
|
||||
Maintainer: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
|
||||
Uploaders: Maarten L. Hekkelman <maarten@hekkelman.com>,
|
||||
Andreas Tille <tille@debian.org>
|
||||
Section: libs
|
||||
Priority: optional
|
||||
Build-Depends: debhelper-compat (= 13),
|
||||
autoconf-archive,
|
||||
libboost-dev,
|
||||
libboost-iostreams-dev,
|
||||
libboost-system-dev,
|
||||
zlib1g-dev,
|
||||
libbz2-dev
|
||||
Standards-Version: 4.5.0
|
||||
Vcs-Browser: https://salsa.debian.org/med-team/libcifpp
|
||||
Vcs-Git: https://salsa.debian.org/med-team/libcifpp.git
|
||||
Homepage: https://github.com/PDB-REDO/libcifpp
|
||||
Rules-Requires-Root: no
|
||||
|
||||
Package: libcifpp-dev
|
||||
Architecture: any
|
||||
Section: libdevel
|
||||
Depends: ${misc:Depends},
|
||||
libcifpp0.1 (= ${binary:Version}),
|
||||
libboost-dev,
|
||||
libboost-iostreams-dev,
|
||||
pkg-config
|
||||
Suggests: libcifpp-doc
|
||||
Description: Development files for libcifpp
|
||||
Libcifpp is a C++ library used to create and manipulate
|
||||
mmCIF and PDB files containing macro molecular structure information.
|
||||
.
|
||||
This specific package contains all files needed to develop new
|
||||
software using libcifpp.
|
||||
|
||||
Package: libcifpp0.1
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Library files for libcifpp
|
||||
Libcifpp is a C++ library used to create and manipulate
|
||||
mmCIF and PDB files containing macro molecular structure information.
|
||||
.
|
||||
This package contains the library file only.
|
||||
0
debian/copyright
vendored
0
debian/copyright
vendored
1
debian/libcifpp-dev.docs
vendored
1
debian/libcifpp-dev.docs
vendored
@@ -1 +0,0 @@
|
||||
README.md
|
||||
1
debian/libcifpp0.1.docs
vendored
1
debian/libcifpp0.1.docs
vendored
@@ -1 +0,0 @@
|
||||
README.md
|
||||
39
debian/rules
vendored
39
debian/rules
vendored
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
DH_VERBOSE := 1
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
|
||||
# Fixing reproducible builds
|
||||
LC_ALL := C.UTF-8
|
||||
export LC_ALL
|
||||
|
||||
export LIBRARY_VERSION=0.1
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --enable-documentation
|
||||
|
||||
override_dh_auto_install:
|
||||
$(MAKE) DESTDIR=$(CURDIR)/debian/libcifpp0.1 install-lib
|
||||
$(MAKE) DESTDIR=$(CURDIR)/debian/libcifpp-dev install-dev
|
||||
|
||||
override_dh_auto_configure-arch:
|
||||
dh_auto_configure -- --enable-shared
|
||||
|
||||
override_dh_auto_configure-indep:
|
||||
dh_auto_configure -- --enable-shared
|
||||
|
||||
override_dh_auto_test:
|
||||
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
|
||||
$(MAKE) test
|
||||
endif
|
||||
|
||||
override_dh_install:
|
||||
## cleaning up dependency_libs filed in *.la files
|
||||
sed -i "/dependency_libs/ s/'.*'/''/" `find . -name '*.la'`
|
||||
dh_install
|
||||
|
||||
override_dh_makeshlibs:
|
||||
dh_makeshlibs -- -v$(LIBRARY_VERSION)
|
||||
1
debian/source/format
vendored
1
debian/source/format
vendored
@@ -1 +0,0 @@
|
||||
3.0 (quilt)
|
||||
0
debian/source/include-binaries
vendored
0
debian/source/include-binaries
vendored
2
debian/source/options
vendored
2
debian/source/options
vendored
@@ -1,2 +0,0 @@
|
||||
extend-diff-ignore = "(^|/)(\.gitignore|\.travis\.yml)$"
|
||||
|
||||
5
debian/upstream/metadata
vendored
5
debian/upstream/metadata
vendored
@@ -1,5 +0,0 @@
|
||||
---
|
||||
Bug-Database: https://github.com/PDB-REDO/libcifpp/issues
|
||||
Bug-Submit: https://github.com/PDB-REDO/libcifpp/issues/new
|
||||
Repository: https://github.com/PDB-REDO/libcifpp.git
|
||||
Repository-Browse: https://github.com/PDB-REDO/libcifpp
|
||||
3
debian/watch
vendored
3
debian/watch
vendored
@@ -1,3 +0,0 @@
|
||||
version=4
|
||||
opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/libcifpp-$1\.tar\.gz/ \
|
||||
https://github.com/PDB-REDO/libcifpp/tags .*/v?(\d\S+)\.tar\.gz
|
||||
74
docs/CMakeLists.txt
Normal file
74
docs/CMakeLists.txt
Normal file
@@ -0,0 +1,74 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
|
||||
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}
|
||||
DEPENDS ${CIFPP_PUBLIC_HEADERS} ${DOXYGEN_OUTPUT_DIR} ${DOXYFILE_OUT}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
|
||||
MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
|
||||
COMMENT "Generating docs")
|
||||
|
||||
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-cifpp" ALL
|
||||
COMMAND ${SPHINX_EXECUTABLE} -b html
|
||||
-Dbreathe_projects.cifpp=${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")
|
||||
|
||||
set_property(TARGET Sphinx-cifpp APPEND PROPERTY ADDITIONAL_CLEAN_FILES
|
||||
${DOXYGEN_OUTPUT_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api)
|
||||
|
||||
install(
|
||||
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
PATTERN .doctrees EXCLUDE
|
||||
PATTERN .buildinfo EXCLUDE)
|
||||
67
docs/Doxyfile.in
Normal file
67
docs/Doxyfile.in
Normal file
@@ -0,0 +1,67 @@
|
||||
# EXCLUDE_SYMBOLS = cif::detail::*, std*
|
||||
FILE_PATTERNS = *.hpp
|
||||
STRIP_FROM_PATH = @DOXYGEN_INPUT_DIR@
|
||||
RECURSIVE = YES
|
||||
GENERATE_XML = YES
|
||||
GENERATE_LATEX = NO
|
||||
MACRO_EXPANSION = YES
|
||||
PREDEFINED += and=&& or=|| not=! CIFPP_EXPORT= HAVE_LIBCLIPPER=1
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
INPUT = @DOXYGEN_INPUT_DIR@
|
||||
|
||||
|
||||
# # Doxyfile
|
||||
|
||||
# PROJECT_NAME = "libcifpp"
|
||||
# PROJECT_BRIEF = "C++ library for using mmCIF files"
|
||||
|
||||
# GENERATE_LATEX = NO
|
||||
|
||||
# EXTRACT_ALL = YES
|
||||
# EXTRACT_STATIC = YES
|
||||
# HIDE_UNDOC_CLASSES = NO
|
||||
# SHOW_NAMESPACES = YES
|
||||
# EXTRACT_TEMPLATE_PARAMS = YES
|
||||
|
||||
# CREATE_SUBDIRS = NO
|
||||
# INLINE_GROPUED_CLASSES = YES
|
||||
# INLINE_SIMPLE_STRUCTS = YES
|
||||
|
||||
# NUM_PROC_THREADS = 0
|
||||
|
||||
# EXTRACT_LOCAL_CLASSES = NO
|
||||
# HIDE_IN_BODY_DOCS = YES
|
||||
|
||||
# SHOW_HEADERFILE = NO
|
||||
|
||||
# INPUT = @DOXYGEN_INPUT_DIR@/c++
|
||||
# RECURSIVE = YES
|
||||
# EXAMPLE_PATH = @DOXYGEN_INPUT_DIR@/../examples
|
||||
|
||||
# EXAMPLE_PATTERNS = *.cpp
|
||||
|
||||
# # USE_MDFILE_AS_MAINPAGE = ../README.md
|
||||
|
||||
# ENABLE_PREPROCESSING = YES
|
||||
# MACRO_EXPANSION = YES
|
||||
# INCLUDE_PATH = @DOXYGEN_INPUT_DIR@
|
||||
# INCLUDE_FILE_PATTERNS = *.hpp
|
||||
|
||||
# SKIP_FUNCTION_MACROS = NO
|
||||
|
||||
# # CLANG_ASSISTED_PARSING = YES
|
||||
# # CLANG_ADD_INC_PATHS = YES
|
||||
# # CLANG_OPTIONS = -O0 -std=c++23
|
||||
|
||||
# # GENERATE_HTML = YES
|
||||
# # GENERATE_TREEVIEW = YES
|
||||
|
||||
# GENERATE_XML = YES
|
||||
|
||||
# # EXCLUDE_SYMBOLS = cif::detail::*, std*
|
||||
# # # FILE_PATTERNS = *.hpp
|
||||
# # STRIP_FROM_PATH = @DOXYGEN_INPUT_DIR@
|
||||
# # PREDEFINED += and=&& or=|| not=! CIFPP_EXPORT= HAVE_LIBCLIPPER=1
|
||||
# # GENERATE_HTML = NO
|
||||
# # GENERATE_TODOLIST = NO
|
||||
4
docs/_static/.gitignore
vendored
Normal file
4
docs/_static/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
400
docs/basics.rst
Normal file
400
docs/basics.rst
Normal 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++/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"].get<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++/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
49
docs/bitsandpieces.rst
Normal file
@@ -0,0 +1,49 @@
|
||||
Bits & Pieces
|
||||
=============
|
||||
|
||||
The *libcifpp* library offers some extra code that makes the life of developers a bit easier.
|
||||
|
||||
gzio
|
||||
----
|
||||
|
||||
To work with compressed data files a *std::streambuf* implemenation was added based on the code in `gxrio <https://github.com/mhekkel/gxrio>`_. This allows you to read and write compressed data streams transparently.
|
||||
|
||||
When working with files you can use :cpp:class:`cif::gzio::ifstream` and :cpp:class:`cif::gzio::ofstream`. The selection of whether to use compression or not is based on the file extension. If it is ``.gz`` gzip compression is used:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cif::gzio::ifstream file("my-file.txt.gz");
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line))
|
||||
std::cout << line << '\n';
|
||||
|
||||
Writing is equally easy:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cif::gzio::ofstream file("/tmp/output.txt.gz");
|
||||
file << "Hello, world!";
|
||||
file.close();
|
||||
|
||||
You can also use the :cpp:class:`cif::gzio::istream` and feed it a *std::streambuf* object that may or may not contain compressed data. In that case the first bytes of the input are sniffed and if it is gzip compressed data, decompression will be done.
|
||||
|
||||
A progress bar
|
||||
--------------
|
||||
|
||||
Applications based on *libcifpp* may have a longer run time. To give some feedback to the user running your application in a terminal you can use the :cpp:class:`cif::progress_bar`. This class will display an ASCII progress bar along with optional status messages, but only if output is to a real TTY (terminal).
|
||||
|
||||
A progress bar is also shown only if the duration is more than two seconds. To avoid having flashing progress bars for short actions.
|
||||
|
||||
The progress bar uses an internal progress counter that starts at zero and ends when the max value has been reached after which it will be removed from the screen. Updating this internal progress counter can be done by adding a number of steps calling :cpp:func:`cif::progress_bar::consumed` or by setting the exact value for the counter by calling :cpp:func:`cif::progress_bar::progress`.
|
||||
|
||||
Colouring output
|
||||
----------------
|
||||
|
||||
It is also nice to emphasise some output in the terminal by using colours. For this you can create output manipulators using :cpp:func:`cif::coloured`. To write a string in white, and bold letters on a red background you can do:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
using namespace cif::colour;
|
||||
std::cout << cif::coloured("Hello, world!", white, red, bold) << '\n';
|
||||
|
||||
33
docs/compound.rst
Normal file
33
docs/compound.rst
Normal file
@@ -0,0 +1,33 @@
|
||||
Chemical Compounds
|
||||
==================
|
||||
|
||||
The data in *CIF* and *mmCIF* files often describes the structure of some chemical compounds. The structure is recorded in the categories *atom_site* and friends. Records in these categories refer to chemical compounds using a compound ID. This compound ID is the ID field of the *chem_comp* category. For all of the known compounds in the PDB there is an entry in the Chemical Compounds Dictionary or `CCD <https://www.wwpdb.org/data/ccd>`_. If *libcifpp* was properly installed you have a copy of this file somewhere on your disk. And if you have installed the update scripts, a fresh version of this file will be retrieved weekly.
|
||||
|
||||
As an alternative to CCD there are the monomer library files from `CCP4 <https://www.ccp4.ac.uk/>`_. These contain somewhat different data but the overlap is good enough for usage in *libcifpp*.
|
||||
|
||||
Information about compounds is captured in the :cpp:class:`cif::compound`. An instance of a compound object for a certain compound ID can be obtained by using the singleton :cpp:class:`cif::compound_factory`.
|
||||
|
||||
If the compound you want to use is not available in the CCD or in CCP4, you can add that information yourself. For this you can use the method :cpp:func:`cif::compound_factory::push_dictionary`.
|
||||
|
||||
So, given that we have CCD, CCP4 monomer library and used defined compound definitions, what will you get when you try to retrieve such a compound by ID? The answer is, the factory has a stack of compound generators. The first thrown on the stack is the one for a CCD file (*components.cif*) if it can be found. Then, if the *CLIBD_MON* environmental variable is defined, a generator for monomer library files is added to the stack. And then all generators for files you added using *push_dictionary* are added in order. The generators are searched in the reverse order in which they were added to see if it creates a compound object for the ID. If no compound was created at all, nullptr is returned.
|
||||
|
||||
Updating CCD
|
||||
------------
|
||||
|
||||
The CCD data is stored in a single file called *components.cif* and can be downloaded from `CCD <https://www.wwpdb.org/data/ccd>`_.
|
||||
|
||||
As can be read in the section on resources (:doc:`/resources`) files in libcifpp are loaded in a specific order. If the CCD datafile was downloaded during installation, a copy can be found in the directory */usr/share/libcifpp/* (if you installed in */usr*). This is a static file and will not be updated until the next installation of libcifpp.
|
||||
|
||||
When configuring libcifpp, you can specify the *CIFPP_INSTALL_UPDATE_SCRIPT* option, as in:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cmake -S . -B build -DCIFPP_INSTALL_UPDATE_SCRIPT=ON # ... more options?
|
||||
|
||||
This will install a script named *update-libcifpp-data* in */etc/cron.weekly* or */etc/periodic/weekly*. This file uses a config file named */etc/libcifpp.conf* which you then need to edit. In this config file the following line needs to be uncommented:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# update=true
|
||||
|
||||
After that, the update script will weekly download the latest components.cif file to */var/cache/libcifpp*.
|
||||
68
docs/conf.py.in
Normal file
68
docs/conf.py.in
Normal file
@@ -0,0 +1,68 @@
|
||||
# Configuration file
|
||||
|
||||
project = '@PROJECT_NAME@'
|
||||
copyright = '2026, Maarten L. Hekkelman'
|
||||
author = 'Maarten L. Hekkelman'
|
||||
release = '@PROJECT_VERSION@'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
extensions = [
|
||||
"breathe",
|
||||
"exhale",
|
||||
"myst_parser"
|
||||
]
|
||||
|
||||
breathe_projects = {
|
||||
"@PROJECT_NAME@": "@DOXYGEN_OUTPUT_DIR@"
|
||||
}
|
||||
|
||||
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::'
|
||||
# ]
|
||||
|
||||
33
docs/cql.rst
Normal file
33
docs/cql.rst
Normal file
@@ -0,0 +1,33 @@
|
||||
CQL
|
||||
===
|
||||
|
||||
The structure of cif files (even of STAR files, from which this format is derived) looks suspiciously like a relational database. When you consider categories to be tables and items to be columns you're almost there. The only problem is linking tables, in common cif files this is done based on multiple columns and the rules are a bit fuzzy allowing for empty columns to still match related columns that do have a value.
|
||||
|
||||
An early version of the tool *mmCQL* contained a SQL like language interpreter to SELECT and UPDATE values in cif files. This functionality has been expanded by implementing a full SQL interface using the `SQLite <https://sqlite.org>`_ library. Libcifpp categories are exposed as virtual tables in a SQLite environment and can be queried and manipulated using SQL syntax.
|
||||
|
||||
The current limitation is that CREATE TABLE and ALTER TABLE are not supported yet. Since SQLite has no way of supporting this, we will have to write a preprocessor to intercept these statements. That's on the to-do list.
|
||||
|
||||
The new *mmcql* tools in `cif-tools <https://github.com/PDB-REDO/cif-tools>`_ uses this new backend and is a command line application you can use similar to the *sqlite* or e.g. *psql* tools for regular SQLite files and postgresql databanks respectively.
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
.. literalinclude:: ../examples/example-cql.cpp
|
||||
:language: c++
|
||||
:start-at: #include <cif++/cif++.hpp>
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To start using CQL, you will first have to create a :cpp:class:`connection` to a :cpp:class:`cif::cql::datablock`. Using this connection you can create a :cpp:class:`transaction`. And with the transaction can execute SQL statements using :cpp:func:`cif::cql::transaction::exec`. Or you can use the :cpp:func:`cif::cql::transaction::stream` function to directly pull values from the result.
|
||||
|
||||
The result of :cpp:func:`cif::cql::transaction::exec` is a :cpp:class:`cif::cql::result` class which uses a :cpp:class:`cif::category` as storage class.
|
||||
|
||||
Implementation Details
|
||||
----------------------
|
||||
|
||||
When the datablock contains a validator (i.e. you loaded a dictionary) the SQL engine knows about all possible items/columns that are allowed. It also knows about links/relations between categories, just like the regular libcifpp query mechanism. So, updating and deleting will cascade automatically.
|
||||
|
||||
Another point is data types. cif files can have numbers, strings or NULL values. Same goes for SQLite. However, when a file was loaded without a dictionary, the type of an item is dependent on its content. If something was parsed as being a number, the type will be numeric. If however, the file does contain a dictionary/validator, the type is determined by this dictionary. So, even if it looks like a number, it still might be a string internally. Good example is the ID field in atom_site, or the auth_seq_id/auth_seq_num fields. In the WHERE clause this may have unexpected results, so you may have to fall back to using `CAST <https://sqlite.org/lang_expr.html#castexpr>`_.
|
||||
|
||||
The API for this functionality is a bit new, there may be room for improvement. Ideas are welcome.
|
||||
2
docs/genindex.rst
Normal file
2
docs/genindex.rst
Normal file
@@ -0,0 +1,2 @@
|
||||
Index
|
||||
=====
|
||||
47
docs/index.rst
Normal file
47
docs/index.rst
Normal file
@@ -0,0 +1,47 @@
|
||||
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
|
||||
cql.rst
|
||||
resources.rst
|
||||
symmetry.rst
|
||||
bitsandpieces.rst
|
||||
api/library_root.rst
|
||||
genindex.rst
|
||||
|
||||
36
docs/model.rst
Normal file
36
docs/model.rst
Normal file
@@ -0,0 +1,36 @@
|
||||
Molecular Model
|
||||
===============
|
||||
|
||||
Theoretically it is possible to get along with only the classes *cif::file*, *cif::datablock* and *cif::category*. But to keep your data complete and valid you then have to update lots of categories for all but the simplest manipulations. For this *libcifpp* comes with a higher level API modelling atoms, residues, monomers, polymers and complete structures in their respective classes.
|
||||
|
||||
Note that these classes only work properly if you are using *mmCIF* files and have an mmcif_pdbx dictionary available, either compiled in using `mrc <https://github.com/mhekkel/mrc.git>`_ or installed in the proper location.
|
||||
|
||||
.. note::
|
||||
|
||||
This part of *libcifpp* is the least developed part. What is available should work but functionality should eventually be extended.
|
||||
|
||||
Atom
|
||||
----
|
||||
|
||||
The :cpp:class:`cif::mm::atom` is a lightweight proxy class giving access to the data stored in *atom_site* and *atom_site_anisotrop*. It only caches the most often used item data and every modification is directly written back into the *mmCIF* categories.
|
||||
|
||||
Atoms can be copied by value with low cost. The atom class only contains a pointer to an implementation that is reference counted.
|
||||
|
||||
Residue, Monomer and Polymer
|
||||
----------------------------
|
||||
|
||||
The :cpp:class:`cif::mm::residue`, :cpp:class:`cif::mm::monomer` and :cpp:class:`cif::mm::polymer` implement what you'd expect. A monomer is a residue that is part of a polymer and thus has a sequence number and siblings.
|
||||
|
||||
Sugars & Branches
|
||||
-----------------
|
||||
|
||||
There are also classes for modelling sugars and sugar branches. You can create sugar branches
|
||||
|
||||
Structure
|
||||
---------
|
||||
|
||||
The :cpp:class:`cif::mm::structure` can be used to load one of the models from an *mmCIF* file. By default the first model is loaded. (Multiple models are often only available files containing structures defined using NMR).
|
||||
|
||||
A structure holds a reference to a *cif::datablock* and retrieves its data from this datablock and writes any modification back into that datablock.
|
||||
|
||||
One of the most useful parts of the structure class is the ability to create and modify residues. This updates related *chem_comp* and *entity* categories as well.
|
||||
5
docs/requirements.in
Normal file
5
docs/requirements.in
Normal 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
93
docs/requirements.txt
Normal 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
47
docs/resources.rst
Normal 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
108
docs/symmetry.rst
Normal 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);
|
||||
}
|
||||
BIN
examples/1cbs.cif.gz
Normal file
BIN
examples/1cbs.cif.gz
Normal file
Binary file not shown.
36
examples/CMakeLists.txt
Normal file
36
examples/CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(cifpp_example LANGUAGES CXX)
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL AND NOT (TARGET cifpp OR cifpp_FOUND))
|
||||
find_package(cifpp REQUIRED)
|
||||
endif()
|
||||
|
||||
add_executable(example example.cpp)
|
||||
target_link_libraries(example cifpp::cifpp)
|
||||
|
||||
add_executable(example-cql example-cql.cpp)
|
||||
target_link_libraries(example-cql cifpp::cifpp)
|
||||
64
examples/example-cql.cpp
Normal file
64
examples/example-cql.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 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.
|
||||
*/
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: example <inputfile>\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cif::file file(argv[1]);
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto &db = file.front();
|
||||
cif::cql::connection c(db);
|
||||
cif::cql::transaction tx(c);
|
||||
|
||||
auto N = tx.exec("SELECT COUNT(*) FROM atom_site").one_field().get<std::size_t>();
|
||||
auto M = tx.exec("SELECT COUNT(*) FROM atom_site WHERE label_atom_id = 'OXT'").one_field().get<std::size_t>();
|
||||
|
||||
std::cout << "File contains " << N << " atoms of which " << M << (M == 1 ? " is" : " are") << " OXT\n"
|
||||
<< "residues with an OXT are:\n";
|
||||
|
||||
for (const auto &[asym, comp, seqnr] : tx.stream<std::string, std::string, int>(
|
||||
"SELECT label_asym_id, label_comp_id, label_seq_id FROM atom_site WHERE label_atom_id = 'OXT'"))
|
||||
{
|
||||
std::cout << asym << ' ' << comp << ' ' << seqnr << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
62
examples/example.cpp
Normal file
62
examples/example.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 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.
|
||||
*/
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
#include <cif++/cif++.hpp>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: example <inputfile>\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cif::file file(argv[1]);
|
||||
|
||||
if (file.empty())
|
||||
{
|
||||
std::cerr << "Empty file\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto &db = file.front();
|
||||
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\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 << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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
|
||||
@@ -26,9 +26,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
#warning "Using this file is deprecated, use #include <cif++/cif++.hpp> instead"
|
||||
|
||||
int GetSpacegroupNumber(std::string spacegroup); // alternative for clipper's parsing code
|
||||
|
||||
}
|
||||
// IWYU pragma: begin_exports
|
||||
#include "cif++/cif++.hpp"
|
||||
// IWYU pragma: end_exports
|
||||
@@ -1,247 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Lib for working with structures as contained in mmCIF and PDB files
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "cif++/Config.hpp"
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
enum AtomType : uint8_t
|
||||
{
|
||||
Nn = 0, // Unknown
|
||||
|
||||
H = 1, // Hydrogen
|
||||
He = 2, // Helium
|
||||
|
||||
Li = 3, // Lithium
|
||||
Be = 4, // Beryllium
|
||||
B = 5, // Boron
|
||||
C = 6, // Carbon
|
||||
N = 7, // Nitrogen
|
||||
O = 8, // Oxygen
|
||||
F = 9, // Fluorine
|
||||
Ne = 10, // Neon
|
||||
|
||||
Na = 11, // Sodium
|
||||
Mg = 12, // Magnesium
|
||||
Al = 13, // Aluminium
|
||||
Si = 14, // Silicon
|
||||
P = 15, // Phosphorus
|
||||
S = 16, // Sulfur
|
||||
Cl = 17, // Chlorine
|
||||
Ar = 18, // Argon
|
||||
|
||||
K = 19, // Potassium
|
||||
Ca = 20, // Calcium
|
||||
Sc = 21, // Scandium
|
||||
Ti = 22, // Titanium
|
||||
V = 23, // Vanadium
|
||||
Cr = 24, // Chromium
|
||||
Mn = 25, // Manganese
|
||||
Fe = 26, // Iron
|
||||
Co = 27, // Cobalt
|
||||
Ni = 28, // Nickel
|
||||
Cu = 29, // Copper
|
||||
Zn = 30, // Zinc
|
||||
Ga = 31, // Gallium
|
||||
Ge = 32, // Germanium
|
||||
As = 33, // Arsenic
|
||||
Se = 34, // Selenium
|
||||
Br = 35, // Bromine
|
||||
Kr = 36, // Krypton
|
||||
|
||||
Rb = 37, // Rubidium
|
||||
Sr = 38, // Strontium
|
||||
Y = 39, // Yttrium
|
||||
Zr = 40, // Zirconium
|
||||
Nb = 41, // Niobium
|
||||
Mo = 42, // Molybdenum
|
||||
Tc = 43, // Technetium
|
||||
Ru = 44, // Ruthenium
|
||||
Rh = 45, // Rhodium
|
||||
Pd = 46, // Palladium
|
||||
Ag = 47, // Silver
|
||||
Cd = 48, // Cadmium
|
||||
In = 49, // Indium
|
||||
Sn = 50, // Tin
|
||||
Sb = 51, // Antimony
|
||||
Te = 52, // Tellurium
|
||||
I = 53, // Iodine
|
||||
Xe = 54, // Xenon
|
||||
Cs = 55, // Caesium
|
||||
Ba = 56, // Barium
|
||||
La = 57, // Lanthanum
|
||||
|
||||
Hf = 72, // Hafnium
|
||||
Ta = 73, // Tantalum
|
||||
W = 74, // Tungsten
|
||||
Re = 75, // Rhenium
|
||||
Os = 76, // Osmium
|
||||
Ir = 77, // Iridium
|
||||
Pt = 78, // Platinum
|
||||
Au = 79, // Gold
|
||||
Hg = 80, // Mercury
|
||||
Tl = 81, // Thallium
|
||||
Pb = 82, // Lead
|
||||
Bi = 83, // Bismuth
|
||||
Po = 84, // Polonium
|
||||
At = 85, // Astatine
|
||||
Rn = 86, // Radon
|
||||
Fr = 87, // Francium
|
||||
Ra = 88, // Radium
|
||||
Ac = 89, // Actinium
|
||||
|
||||
Rf = 104, // Rutherfordium
|
||||
Db = 105, // Dubnium
|
||||
Sg = 106, // Seaborgium
|
||||
Bh = 107, // Bohrium
|
||||
Hs = 108, // Hassium
|
||||
Mt = 109, // Meitnerium
|
||||
Ds = 110, // Darmstadtium
|
||||
Rg = 111, // Roentgenium
|
||||
Cn = 112, // Copernicium
|
||||
Nh = 113, // Nihonium
|
||||
Fl = 114, // Flerovium
|
||||
Mc = 115, // Moscovium
|
||||
Lv = 116, // Livermorium
|
||||
Ts = 117, // Tennessine
|
||||
Og = 118, // Oganesson
|
||||
|
||||
Ce = 58, // Cerium
|
||||
Pr = 59, // Praseodymium
|
||||
Nd = 60, // Neodymium
|
||||
Pm = 61, // Promethium
|
||||
Sm = 62, // Samarium
|
||||
Eu = 63, // Europium
|
||||
Gd = 64, // Gadolinium
|
||||
Tb = 65, // Terbium
|
||||
Dy = 66, // Dysprosium
|
||||
Ho = 67, // Holmium
|
||||
Er = 68, // Erbium
|
||||
Tm = 69, // Thulium
|
||||
Yb = 70, // Ytterbium
|
||||
Lu = 71, // Lutetium
|
||||
|
||||
Th = 90, // Thorium
|
||||
Pa = 91, // Protactinium
|
||||
U = 92, // Uranium
|
||||
Np = 93, // Neptunium
|
||||
Pu = 94, // Plutonium
|
||||
Am = 95, // Americium
|
||||
Cm = 96, // Curium
|
||||
Bk = 97, // Berkelium
|
||||
Cf = 98, // Californium
|
||||
Es = 99, // Einsteinium
|
||||
Fm = 100, // Fermium
|
||||
Md = 101, // Mendelevium
|
||||
No = 102, // Nobelium
|
||||
Lr = 103, // Lawrencium
|
||||
|
||||
D = 129, // Deuterium
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// AtomTypeInfo
|
||||
|
||||
enum RadiusType {
|
||||
eRadiusCalculated,
|
||||
eRadiusEmpirical,
|
||||
eRadiusCovalentEmpirical,
|
||||
|
||||
eRadiusSingleBond,
|
||||
eRadiusDoubleBond,
|
||||
eRadiusTripleBond,
|
||||
|
||||
eRadiusVanderWaals,
|
||||
|
||||
eRadiusTypeCount
|
||||
};
|
||||
|
||||
struct AtomTypeInfo
|
||||
{
|
||||
AtomType type;
|
||||
std::string name;
|
||||
std::string symbol;
|
||||
float weight;
|
||||
bool metal;
|
||||
float radii[eRadiusTypeCount];
|
||||
};
|
||||
|
||||
extern const AtomTypeInfo kKnownAtoms[];
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// AtomTypeTraits
|
||||
|
||||
class AtomTypeTraits
|
||||
{
|
||||
public:
|
||||
AtomTypeTraits(AtomType a);
|
||||
AtomTypeTraits(const std::string& symbol);
|
||||
|
||||
AtomType type() const { return mInfo->type; }
|
||||
std::string name() const { return mInfo->name; }
|
||||
std::string symbol() const { return mInfo->symbol; }
|
||||
float weight() const { return mInfo->weight; }
|
||||
|
||||
bool isMetal() const { return mInfo->metal; }
|
||||
|
||||
static bool isElement(const std::string& symbol);
|
||||
static bool isMetal(const std::string& symbol);
|
||||
|
||||
float radius(RadiusType type = eRadiusSingleBond) const
|
||||
{
|
||||
if (type >= eRadiusTypeCount)
|
||||
throw std::invalid_argument("invalid radius requested");
|
||||
return mInfo->radii[type] / 100.f;
|
||||
}
|
||||
|
||||
// data type encapsulating the Waasmaier & Kirfel scattering factors
|
||||
// in a simplified form (only a and b).
|
||||
// Added the electrion scattering factors as well
|
||||
struct SFData
|
||||
{
|
||||
double a[6], b[6];
|
||||
};
|
||||
|
||||
// to get the Cval and Siva values, use this constant as charge:
|
||||
enum { kWKSFVal = -99 };
|
||||
|
||||
const SFData& wksf(int charge = 0) const;
|
||||
const SFData& elsf() const;
|
||||
|
||||
private:
|
||||
const struct AtomTypeInfo* mInfo;
|
||||
};
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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++/Cif++.hpp"
|
||||
|
||||
#include <stack>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class CifParserError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
CifParserError(uint32_t lineNr, const std::string& message);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
extern const uint32_t kMaxLineLength;
|
||||
|
||||
extern const uint8_t kCharTraitsTable[128];
|
||||
|
||||
enum CharTraitsMask: uint8_t {
|
||||
kOrdinaryMask = 1 << 0,
|
||||
kNonBlankMask = 1 << 1,
|
||||
kTextLeadMask = 1 << 2,
|
||||
kAnyPrintMask = 1 << 3
|
||||
};
|
||||
|
||||
inline bool isWhite(int ch)
|
||||
{
|
||||
return std::isspace(ch) or ch == '#';
|
||||
}
|
||||
|
||||
inline bool isOrdinary(int ch)
|
||||
{
|
||||
return ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kOrdinaryMask) != 0;
|
||||
}
|
||||
|
||||
inline bool isNonBlank(int ch)
|
||||
{
|
||||
return ch > 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kNonBlankMask) != 0;
|
||||
}
|
||||
|
||||
inline bool isTextLead(int ch)
|
||||
{
|
||||
return ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kTextLeadMask) != 0;
|
||||
}
|
||||
|
||||
inline bool isAnyPrint(int ch)
|
||||
{
|
||||
return ch == '\t' or
|
||||
(ch >= 0x20 and ch <= 0x7f and (kCharTraitsTable[ch - 0x20] & kAnyPrintMask) != 0);
|
||||
}
|
||||
|
||||
inline bool isUnquotedString(const char* s)
|
||||
{
|
||||
bool result = isOrdinary(*s++);
|
||||
while (result and *s != 0)
|
||||
{
|
||||
result = isNonBlank(*s);
|
||||
++s;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<std::string,std::string> splitTagName(const std::string& tag);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// sac Parser, analogous to SAX Parser (simple api for xml)
|
||||
|
||||
class SacParser
|
||||
{
|
||||
public:
|
||||
SacParser(std::istream& is);
|
||||
virtual ~SacParser() {}
|
||||
|
||||
enum CIFToken
|
||||
{
|
||||
eCIFTokenUnknown,
|
||||
|
||||
eCIFTokenEOF,
|
||||
|
||||
eCIFTokenDATA,
|
||||
eCIFTokenLOOP,
|
||||
eCIFTokenGLOBAL,
|
||||
eCIFTokenSAVE,
|
||||
eCIFTokenSTOP,
|
||||
eCIFTokenTag,
|
||||
eCIFTokenValue,
|
||||
};
|
||||
|
||||
static const char* kTokenName[];
|
||||
|
||||
enum CIFValueType
|
||||
{
|
||||
eCIFValueInt,
|
||||
eCIFValueFloat,
|
||||
eCIFValueNumeric,
|
||||
eCIFValueString,
|
||||
eCIFValueTextField,
|
||||
eCIFValueInapplicable,
|
||||
eCIFValueUnknown
|
||||
};
|
||||
|
||||
static const char* kValueName[];
|
||||
|
||||
int getNextChar();
|
||||
|
||||
void retract();
|
||||
void restart();
|
||||
|
||||
CIFToken getNextToken();
|
||||
void match(CIFToken token);
|
||||
|
||||
void parseFile();
|
||||
void parseGlobal();
|
||||
void parseDataBlock();
|
||||
|
||||
virtual void parseSaveFrame();
|
||||
|
||||
void parseDictionary();
|
||||
|
||||
void error(const std::string& msg);
|
||||
|
||||
// production methods, these are pure virtual here
|
||||
|
||||
virtual void produceDatablock(const std::string& name) = 0;
|
||||
virtual void produceCategory(const std::string& name) = 0;
|
||||
virtual void produceRow() = 0;
|
||||
virtual void produceItem(const std::string& category, const std::string& item, const std::string& value) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
enum State
|
||||
{
|
||||
eStateStart,
|
||||
eStateWhite,
|
||||
eStateComment,
|
||||
eStateQuestionMark,
|
||||
eStateDot,
|
||||
eStateQuotedString,
|
||||
eStateQuotedStringQuote,
|
||||
eStateUnquotedString,
|
||||
eStateTag,
|
||||
eStateTextField,
|
||||
eStateFloat = 100,
|
||||
eStateInt = 110,
|
||||
// eStateNumericSuffix = 200,
|
||||
eStateValue = 300
|
||||
};
|
||||
|
||||
std::istream& mData;
|
||||
|
||||
// Parser state
|
||||
bool mValidate;
|
||||
uint32_t mLineNr;
|
||||
bool mBol;
|
||||
int mState, mStart;
|
||||
CIFToken mLookahead;
|
||||
std::string mTokenValue;
|
||||
CIFValueType mTokenType;
|
||||
std::stack<int> mBuffer;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class Parser : public SacParser
|
||||
{
|
||||
public:
|
||||
Parser(std::istream& is, File& f);
|
||||
|
||||
virtual void produceDatablock(const std::string& name);
|
||||
virtual void produceCategory(const std::string& name);
|
||||
virtual void produceRow();
|
||||
virtual void produceItem(const std::string& category, const std::string& item, const std::string& value);
|
||||
|
||||
protected:
|
||||
File& mFile;
|
||||
Datablock* mDataBlock;
|
||||
Datablock::iterator mCat;
|
||||
Row mRow;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class DictParser : public Parser
|
||||
{
|
||||
public:
|
||||
|
||||
DictParser(Validator& validator, std::istream& is);
|
||||
~DictParser();
|
||||
|
||||
void loadDictionary();
|
||||
|
||||
private:
|
||||
|
||||
virtual void parseSaveFrame();
|
||||
|
||||
bool collectItemTypes();
|
||||
void linkItems();
|
||||
|
||||
Validator& mValidator;
|
||||
File mFile;
|
||||
struct DictParserDataImpl* mImpl;
|
||||
bool mCollectedItemTypes = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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++/Config.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
struct rsrc_imp
|
||||
{
|
||||
unsigned int m_next;
|
||||
unsigned int m_child;
|
||||
unsigned int m_name;
|
||||
unsigned int m_size;
|
||||
unsigned int m_data;
|
||||
};
|
||||
|
||||
#if USE_RSRC
|
||||
extern const rsrc_imp gResourceIndex[];
|
||||
extern const char gResourceData[];
|
||||
extern const char gResourceName[];
|
||||
#endif
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// some basic utilities: Since we're using ASCII input only, we define for optimisation
|
||||
// our own case conversion routines.
|
||||
|
||||
bool iequals(const std::string& a, const std::string& b);
|
||||
int icompare(const std::string& a, const std::string& b);
|
||||
|
||||
bool iequals(const char* a, const char* b);
|
||||
int icompare(const char* a, const char* b);
|
||||
|
||||
void toLower(std::string& s);
|
||||
std::string toLowerCopy(const std::string& s);
|
||||
|
||||
// To make life easier, we also define iless and iset using iequals
|
||||
|
||||
struct iless
|
||||
{
|
||||
bool operator()(const std::string& a, const std::string& b) const
|
||||
{
|
||||
return icompare(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set<std::string, iless> iset;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// This really makes a difference, having our own tolower routines
|
||||
|
||||
extern const uint8_t kCharToLowerMap[256];
|
||||
|
||||
inline char tolower(char ch)
|
||||
{
|
||||
return static_cast<char>(kCharToLowerMap[static_cast<uint8_t>(ch)]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
std::tuple<std::string,std::string> splitTagName(const std::string& tag);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// custom wordwrapping routine
|
||||
|
||||
std::vector<std::string> wordWrap(const std::string& text, unsigned int width);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Code helping with terminal i/o
|
||||
|
||||
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 {
|
||||
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) {}
|
||||
|
||||
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))
|
||||
{
|
||||
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";
|
||||
|
||||
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))
|
||||
{
|
||||
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";
|
||||
|
||||
return os << ostr.str();
|
||||
}
|
||||
else
|
||||
return os << s.m_s;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
inline auto coloured(const CharT* s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// A progress bar
|
||||
|
||||
class Progress
|
||||
{
|
||||
public:
|
||||
Progress(int64_t inMax, const std::string& inAction);
|
||||
virtual ~Progress();
|
||||
|
||||
void consumed(int64_t inConsumed); // consumed is relative
|
||||
void progress(int64_t inProgress); // progress is absolute
|
||||
|
||||
void message(const std::string& inMessage);
|
||||
|
||||
private:
|
||||
Progress(const Progress&);
|
||||
Progress& operator=(const Progress&);
|
||||
|
||||
struct ProgressImpl* mImpl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// The new default is to load 'resource' files from the file system
|
||||
// since not everyone likes mrc. But if you do want to use mrc to load
|
||||
// resources, specify the compile time flag USE_RSRC.
|
||||
|
||||
/// \brief Simple class containing the data for a resource
|
||||
class rsrc
|
||||
{
|
||||
public:
|
||||
rsrc()
|
||||
: m_data(nullptr), m_size(0) {}
|
||||
rsrc(const char* data, size_t size)
|
||||
: m_data(data), m_size(size) {}
|
||||
rsrc(const rsrc& rhs)
|
||||
: m_data(rhs.m_data), m_size(rhs.m_size) {}
|
||||
|
||||
rsrc& operator=(const rsrc& rhs)
|
||||
{
|
||||
m_data = rhs.m_data;
|
||||
m_size = rhs.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool()
|
||||
{
|
||||
return m_data != nullptr and m_size > 0;
|
||||
}
|
||||
|
||||
const char* data() const { return m_data; }
|
||||
size_t size() const { return m_size; }
|
||||
|
||||
private:
|
||||
const char* m_data;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
/// \brief loader types
|
||||
enum class rsrc_loader_type { mrsrc, file };
|
||||
|
||||
/// \brief loader info
|
||||
struct rsrc_loader_info
|
||||
{
|
||||
rsrc_loader_type type;
|
||||
std::string info;
|
||||
const void* ptrs[3];
|
||||
};
|
||||
|
||||
class rsrc_loader
|
||||
{
|
||||
public:
|
||||
|
||||
static void init(std::initializer_list<rsrc_loader_info> loaders =
|
||||
{
|
||||
{ rsrc_loader_type::file, "." },
|
||||
#if USE_RSRC
|
||||
{ rsrc_loader_type::mrsrc, "", { gResourceIndex, gResourceData, gResourceName } }
|
||||
#endif
|
||||
})
|
||||
{
|
||||
assert(not s_instance);
|
||||
s_instance.reset(new rsrc_loader(loaders));
|
||||
}
|
||||
|
||||
static rsrc load(const std::string& name)
|
||||
{
|
||||
assert(s_instance);
|
||||
if (not s_instance)
|
||||
init();
|
||||
|
||||
return s_instance->do_load(name);
|
||||
}
|
||||
|
||||
~rsrc_loader();
|
||||
|
||||
private:
|
||||
|
||||
rsrc_loader(const std::initializer_list<rsrc_loader_info>& loaders);
|
||||
|
||||
rsrc do_load(const std::string& name);
|
||||
|
||||
static std::unique_ptr<rsrc_loader> s_instance;
|
||||
|
||||
std::list<struct rsrc_loader_impl*> m_loaders;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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++/Cif++.hpp"
|
||||
|
||||
//// the std regex of gcc is crashing....
|
||||
// #include <boost/regex.hpp>
|
||||
|
||||
#include <regex>
|
||||
#include <set>
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
struct ValidateCategory;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class ValidationError : public std::exception
|
||||
{
|
||||
public:
|
||||
ValidationError(const std::string& msg);
|
||||
ValidationError(const std::string& cat, const std::string& item,
|
||||
const std::string& msg);
|
||||
const char* what() const noexcept { return mMsg.c_str(); }
|
||||
std::string mMsg;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
enum DDL_PrimitiveType
|
||||
{
|
||||
ptChar, ptUChar, ptNumb
|
||||
};
|
||||
|
||||
DDL_PrimitiveType mapToPrimitiveType(const std::string& s);
|
||||
|
||||
struct ValidateType
|
||||
{
|
||||
std::string mName;
|
||||
DDL_PrimitiveType mPrimitiveType;
|
||||
std::regex mRx;
|
||||
|
||||
bool operator<(const ValidateType& rhs) const
|
||||
{
|
||||
return icompare(mName, rhs.mName) < 0;
|
||||
}
|
||||
|
||||
// compare values based on type
|
||||
// int compare(const std::string& a, const std::string& b) const
|
||||
// {
|
||||
// return compare(a.c_str(), b.c_str());
|
||||
// }
|
||||
|
||||
int compare(const char* a, const char* b) const;
|
||||
};
|
||||
|
||||
struct ValidateItem
|
||||
{
|
||||
std::string mTag;
|
||||
bool mMandatory;
|
||||
const ValidateType* mType;
|
||||
cif::iset mEnums;
|
||||
std::string mDefault;
|
||||
bool mDefaultIsNull;
|
||||
ValidateCategory* mCategory = nullptr;
|
||||
|
||||
// ItemLinked is used for non-key links
|
||||
struct ItemLinked
|
||||
{
|
||||
ValidateItem* mParent;
|
||||
std::string mParentItem;
|
||||
std::string mChildItem;
|
||||
};
|
||||
|
||||
std::vector<ItemLinked> mLinked;
|
||||
|
||||
bool operator<(const ValidateItem& rhs) const
|
||||
{
|
||||
return icompare(mTag, rhs.mTag) < 0;
|
||||
}
|
||||
|
||||
bool operator==(const ValidateItem& rhs) const
|
||||
{
|
||||
return iequals(mTag, rhs.mTag);
|
||||
}
|
||||
|
||||
void operator()(std::string value) const;
|
||||
};
|
||||
|
||||
struct ValidateCategory
|
||||
{
|
||||
std::string mName;
|
||||
std::vector<std::string> mKeys;
|
||||
cif::iset mGroups;
|
||||
cif::iset mMandatoryFields;
|
||||
std::set<ValidateItem> mItemValidators;
|
||||
|
||||
bool operator<(const ValidateCategory& rhs) const
|
||||
{
|
||||
return icompare(mName, rhs.mName) < 0;
|
||||
}
|
||||
|
||||
void addItemValidator(ValidateItem&& v);
|
||||
|
||||
const ValidateItem* getValidatorForItem(std::string tag) const;
|
||||
|
||||
const std::set<ValidateItem>& itemValidators() const
|
||||
{
|
||||
return mItemValidators;
|
||||
}
|
||||
};
|
||||
|
||||
struct ValidateLink
|
||||
{
|
||||
int mLinkGroupID;
|
||||
std::string mParentCategory;
|
||||
std::vector<std::string> mParentKeys;
|
||||
std::string mChildCategory;
|
||||
std::vector<std::string> mChildKeys;
|
||||
std::string mLinkGroupLabel;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class Validator
|
||||
{
|
||||
public:
|
||||
friend class DictParser;
|
||||
|
||||
Validator();
|
||||
~Validator();
|
||||
|
||||
Validator(const Validator& rhs) = delete;
|
||||
Validator& operator=(const Validator& rhs) = delete;
|
||||
|
||||
Validator(Validator&& rhs);
|
||||
Validator& operator=(Validator&& rhs);
|
||||
|
||||
void addTypeValidator(ValidateType&& v);
|
||||
const ValidateType* getValidatorForType(std::string typeCode) const;
|
||||
|
||||
void addCategoryValidator(ValidateCategory&& v);
|
||||
const ValidateCategory* getValidatorForCategory(std::string category) const;
|
||||
|
||||
void addLinkValidator(ValidateLink&& v);
|
||||
std::vector<const ValidateLink*> getLinksForParent(const std::string& category) const;
|
||||
std::vector<const ValidateLink*> getLinksForChild(const std::string& category) const;
|
||||
|
||||
void reportError(const std::string& msg, bool fatal);
|
||||
|
||||
std::string dictName() const { return mName; }
|
||||
void dictName(const std::string& name) { mName = name; }
|
||||
|
||||
std::string dictVersion() const { return mVersion; }
|
||||
void dictVersion(const std::string& version) { mVersion = version; }
|
||||
|
||||
private:
|
||||
|
||||
// name is fully qualified here:
|
||||
ValidateItem* getValidatorForItem(std::string name) const;
|
||||
|
||||
std::string mName;
|
||||
std::string mVersion;
|
||||
bool mStrict = false;
|
||||
// std::set<uint32_t> mSubCategories;
|
||||
std::set<ValidateType> mTypeValidators;
|
||||
std::set<ValidateCategory> mCategoryValidators;
|
||||
std::vector<ValidateLink> mLinkValidators;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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 <set>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "cif++/AtomType.hpp"
|
||||
#include "cif++/Cif++.hpp"
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// The chemical composition of the structure in an mmCIF file is
|
||||
// defined in the class composition. A compositon consists of
|
||||
// entities. Each Entity can be either a polymer, a non-polymer
|
||||
// a macrolide or a water molecule.
|
||||
// Entities themselves are made up of compounds. And compounds
|
||||
// contain CompoundAtom records for each atom.
|
||||
|
||||
class Compound;
|
||||
class Link;
|
||||
struct CompoundAtom;
|
||||
|
||||
enum BondType { singleBond, doubleBond, tripleBond, delocalizedBond };
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about an atom in a chemical compound
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct CompoundAtom
|
||||
{
|
||||
std::string id;
|
||||
AtomType typeSymbol;
|
||||
std::string typeEnergy;
|
||||
float partialCharge;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bonds
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct CompoundBond
|
||||
{
|
||||
std::string atomID[2];
|
||||
BondType type;
|
||||
float distance;
|
||||
float esd;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bond-angles
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct CompoundAngle
|
||||
{
|
||||
std::string atomID[3];
|
||||
float angle;
|
||||
float esd;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bond-angles
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct CompoundTorsion
|
||||
{
|
||||
std::string atomID[4];
|
||||
float angle;
|
||||
float esd;
|
||||
int period;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bond-angles
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct CompoundPlane
|
||||
{
|
||||
std::string id;
|
||||
std::vector<std::string> atomID;
|
||||
float esd;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about a chiral centre
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
enum ChiralVolumeSign { negativ, positiv, both };
|
||||
|
||||
struct CompoundChiralCentre
|
||||
{
|
||||
std::string id;
|
||||
std::string atomIDCentre;
|
||||
std::string atomID[3];
|
||||
ChiralVolumeSign volumeSign;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// a class that contains information about a chemical compound.
|
||||
// This information is derived from the ccp4 monomer library by default.
|
||||
// To create compounds, you'd best use the factory method.
|
||||
|
||||
class Compound
|
||||
{
|
||||
public:
|
||||
|
||||
Compound(const std::string& file, const std::string& id, const std::string& name,
|
||||
const std::string& group);
|
||||
|
||||
// factory method, create a Compound based on the three letter code
|
||||
// (for amino acids) or the one-letter code (for bases) or the
|
||||
// code as it is known in the CCP4 monomer library.
|
||||
|
||||
static const Compound* create(const std::string& id);
|
||||
|
||||
// this second factory method can create a Compound even if it is not
|
||||
// recorded in the library. It will take the values from the CCP4 lib
|
||||
// unless the value passed to this function is not empty.
|
||||
static const Compound* create(const std::string& id, const std::string& name,
|
||||
const std::string& type, const std::string& formula);
|
||||
|
||||
// add an additional path to the monomer library.
|
||||
static void addMonomerLibraryPath(const std::string& dir);
|
||||
|
||||
// accessors
|
||||
std::string id() const { return mID; }
|
||||
std::string name() const { return mName; }
|
||||
std::string type() const;
|
||||
std::string group() const { return mGroup; }
|
||||
std::vector<CompoundAtom> atoms() const { return mAtoms; }
|
||||
std::vector<CompoundBond> bonds() const { return mBonds; }
|
||||
std::vector<CompoundAngle> angles() const { return mAngles; }
|
||||
std::vector<CompoundChiralCentre> chiralCentres() const
|
||||
{ return mChiralCentres; }
|
||||
std::vector<CompoundPlane> planes() const { return mPlanes; }
|
||||
std::vector<CompoundTorsion> torsions() const { return mTorsions; }
|
||||
|
||||
CompoundAtom getAtomByID(const std::string& atomID) const;
|
||||
|
||||
bool atomsBonded(const std::string& atomId_1, const std::string& atomId_2) const;
|
||||
float atomBondValue(const std::string& atomId_1, const std::string& atomId_2) const;
|
||||
float bondAngle(const std::string& atomId_1, const std::string& atomId_2, const std::string& atomId_3) const;
|
||||
float chiralVolume(const std::string& centreID) const;
|
||||
|
||||
std::string formula() const;
|
||||
float formulaWeight() const;
|
||||
int charge() const;
|
||||
bool isWater() const;
|
||||
bool isSugar() const;
|
||||
|
||||
std::vector<std::string> isomers() const;
|
||||
bool isIsomerOf(const Compound& c) const;
|
||||
std::vector<std::tuple<std::string,std::string>> mapToIsomer(const Compound& c) const;
|
||||
|
||||
private:
|
||||
|
||||
~Compound();
|
||||
|
||||
cif::File mCF;
|
||||
|
||||
std::string mID;
|
||||
std::string mName;
|
||||
std::string mGroup;
|
||||
std::vector<CompoundAtom> mAtoms;
|
||||
std::vector<CompoundBond> mBonds;
|
||||
std::vector<CompoundAngle> mAngles;
|
||||
std::vector<CompoundTorsion>mTorsions;
|
||||
std::vector<CompoundChiralCentre>
|
||||
mChiralCentres;
|
||||
std::vector<CompoundPlane> mPlanes;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bonds
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct LinkAtom
|
||||
{
|
||||
int compID;
|
||||
std::string atomID;
|
||||
|
||||
bool operator==(const LinkAtom& rhs) const { return compID == rhs.compID and atomID == rhs.atomID; }
|
||||
};
|
||||
|
||||
struct LinkBond
|
||||
{
|
||||
LinkAtom atom[2];
|
||||
BondType type;
|
||||
float distance;
|
||||
float esd;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bond-angles
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct LinkAngle
|
||||
{
|
||||
LinkAtom atom[3];
|
||||
float angle;
|
||||
float esd;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bond-torsions
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct LinkTorsion
|
||||
{
|
||||
LinkAtom atom[4];
|
||||
float angle;
|
||||
float esd;
|
||||
int period;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about the bond-angles
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct LinkPlane
|
||||
{
|
||||
std::string id;
|
||||
std::vector<LinkAtom> atoms;
|
||||
float esd;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// struct containing information about a chiral centre
|
||||
// This information comes from the CCP4 monomer library.
|
||||
|
||||
struct LinkChiralCentre
|
||||
{
|
||||
std::string id;
|
||||
LinkAtom atomCentre;
|
||||
LinkAtom atom[3];
|
||||
ChiralVolumeSign volumeSign;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// a class that contains information about a chemical link between compounds.
|
||||
// This information is derived from the ccp4 monomer library by default.
|
||||
|
||||
class Link
|
||||
{
|
||||
public:
|
||||
|
||||
Link(cif::Datablock& db);
|
||||
|
||||
// Factory method.
|
||||
static const Link& create(const std::string& id);
|
||||
|
||||
// accessors
|
||||
std::string id() const { return mID; }
|
||||
std::vector<LinkBond> bonds() const { return mBonds; }
|
||||
std::vector<LinkAngle> angles() const { return mAngles; }
|
||||
std::vector<LinkChiralCentre> chiralCentres() const { return mChiralCentres; }
|
||||
std::vector<LinkPlane> planes() const { return mPlanes; }
|
||||
std::vector<LinkTorsion> torsions() const { return mTorsions; }
|
||||
|
||||
float atomBondValue(const LinkAtom& atomId_1, const LinkAtom& atomId_2) const;
|
||||
float bondAngle(const LinkAtom& atomId_1, const LinkAtom& atomId_2, const LinkAtom& atomId_3) const;
|
||||
float chiralVolume(const std::string& id) const;
|
||||
|
||||
private:
|
||||
|
||||
~Link();
|
||||
|
||||
std::string mID;
|
||||
std::vector<LinkBond> mBonds;
|
||||
std::vector<LinkAngle> mAngles;
|
||||
std::vector<LinkTorsion> mTorsions;
|
||||
std::vector<LinkChiralCentre> mChiralCentres;
|
||||
std::vector<LinkPlane> mPlanes;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Factory class for Compound and Link objects
|
||||
|
||||
extern const std::map<std::string,char> kAAMap, kBaseMap;
|
||||
|
||||
class CompoundFactory
|
||||
{
|
||||
public:
|
||||
|
||||
static CompoundFactory& instance();
|
||||
|
||||
void pushDictionary(const std::string& inDictFile);
|
||||
void popDictionary();
|
||||
|
||||
bool isKnownPeptide(const std::string& res_name) const;
|
||||
bool isKnownBase(const std::string& res_name) const;
|
||||
|
||||
std::string unalias(const std::string& res_name) const;
|
||||
|
||||
const Compound* get(std::string id);
|
||||
const Compound* create(std::string id);
|
||||
|
||||
const Link* getLink(std::string id);
|
||||
const Link* createLink(std::string id);
|
||||
|
||||
private:
|
||||
|
||||
CompoundFactory();
|
||||
~CompoundFactory();
|
||||
|
||||
CompoundFactory(const CompoundFactory&) = delete;
|
||||
CompoundFactory& operator=(const CompoundFactory&) = delete;
|
||||
|
||||
static CompoundFactory* sInstance;
|
||||
|
||||
class CompoundFactoryImpl* mImpl;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/* include/cif++/Config.hpp.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* define if the Boost library is available */
|
||||
#undef HAVE_BOOST
|
||||
|
||||
/* define if the Boost::Regex library is available */
|
||||
#undef HAVE_BOOST_REGEX
|
||||
|
||||
/* define if the compiler supports basic C++17 syntax */
|
||||
#undef HAVE_CXX17
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `floor' function. */
|
||||
#undef HAVE_FLOOR
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if LIBBZ2 is found */
|
||||
#undef HAVE_LIBBZ2
|
||||
|
||||
/* Define to 1 if LIBZ is found */
|
||||
#undef HAVE_LIBZ
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `pow' function. */
|
||||
#undef HAVE_POW
|
||||
|
||||
/* Define to 1 if the system has the type `ptrdiff_t'. */
|
||||
#undef HAVE_PTRDIFF_T
|
||||
|
||||
/* Define to 1 if you have the `rint' function. */
|
||||
#undef HAVE_RINT
|
||||
|
||||
/* Define to 1 if you have the `sqrt' function. */
|
||||
#undef HAVE_SQRT
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#undef HAVE_TERMIOS_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
@@ -1,412 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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 <functional>
|
||||
|
||||
#include "cif++/Config.hpp"
|
||||
|
||||
#include <boost/math/quaternion.hpp>
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
typedef boost::math::quaternion<float> quaternion;
|
||||
|
||||
const long double
|
||||
kPI = 3.141592653589793238462643383279502884L;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// 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();
|
||||
|
||||
template<typename F>
|
||||
struct PointF
|
||||
{
|
||||
typedef F FType;
|
||||
|
||||
FType mX, mY, mZ;
|
||||
|
||||
PointF() : mX(0), mY(0), mZ(0) {}
|
||||
PointF(FType x, FType y, FType z) : mX(x), mY(y), mZ(z) {}
|
||||
// PointF(const clipper::Coord_orth& pt): mX(pt[0]), mY(pt[1]), mZ(pt[2]) {}
|
||||
|
||||
template<typename PF>
|
||||
PointF(const PointF<PF>& pt)
|
||||
: mX(static_cast<F>(pt.mX))
|
||||
, mY(static_cast<F>(pt.mY))
|
||||
, mZ(static_cast<F>(pt.mZ)) {}
|
||||
|
||||
// PointF& operator=(const clipper::Coord_orth& rhs)
|
||||
// {
|
||||
// mX = rhs[0];
|
||||
// mY = rhs[1];
|
||||
// mZ = rhs[2];
|
||||
// return *this;
|
||||
// }
|
||||
|
||||
template<typename PF>
|
||||
PointF& operator=(const PointF<PF>& rhs)
|
||||
{
|
||||
mX = static_cast<F>(rhs.mX);
|
||||
mY = static_cast<F>(rhs.mY);
|
||||
mZ = static_cast<F>(rhs.mZ);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FType& getX() { return mX; }
|
||||
FType getX() const { return mX; }
|
||||
void setX(FType x) { mX = x; }
|
||||
|
||||
FType& getY() { return mY; }
|
||||
FType getY() const { return mY; }
|
||||
void setY(FType y) { mY = y; }
|
||||
|
||||
FType& getZ() { return mZ; }
|
||||
FType getZ() const { return mZ; }
|
||||
void setZ(FType z) { mZ = z; }
|
||||
|
||||
PointF& operator+=(const PointF& rhs)
|
||||
{
|
||||
mX += rhs.mX;
|
||||
mY += rhs.mY;
|
||||
mZ += rhs.mZ;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator+=(FType d)
|
||||
{
|
||||
mX += d;
|
||||
mY += d;
|
||||
mZ += d;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator-=(const PointF& rhs)
|
||||
{
|
||||
mX -= rhs.mX;
|
||||
mY -= rhs.mY;
|
||||
mZ -= rhs.mZ;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator-=(FType d)
|
||||
{
|
||||
mX -= d;
|
||||
mY -= d;
|
||||
mZ -= d;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator*=(FType rhs)
|
||||
{
|
||||
mX *= rhs;
|
||||
mY *= rhs;
|
||||
mZ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PointF& operator/=(FType rhs)
|
||||
{
|
||||
mX /= rhs;
|
||||
mY /= rhs;
|
||||
mZ /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FType normalize()
|
||||
{
|
||||
auto length = mX * mX + mY * mY + mZ * mZ;
|
||||
if (length > 0)
|
||||
{
|
||||
length = std::sqrt(length);
|
||||
operator/=(length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void rotate(const boost::math::quaternion<FType>& q)
|
||||
{
|
||||
boost::math::quaternion<FType> p(0, mX, mY, mZ);
|
||||
|
||||
p = q * p * boost::math::conj(q);
|
||||
|
||||
mX = p.R_component_2();
|
||||
mY = p.R_component_3();
|
||||
mZ = p.R_component_4();
|
||||
}
|
||||
|
||||
// operator clipper::Coord_orth() const
|
||||
// {
|
||||
// return clipper::Coord_orth(mX, mY, mZ);
|
||||
// }
|
||||
|
||||
operator std::tuple<const FType&, const FType&, const FType&>() const
|
||||
{
|
||||
return std::make_tuple(std::ref(mX), std::ref(mY), std::ref(mZ));
|
||||
}
|
||||
|
||||
operator std::tuple<FType&,FType&,FType&>()
|
||||
{
|
||||
return std::make_tuple(std::ref(mX), std::ref(mY), std::ref(mZ));
|
||||
}
|
||||
|
||||
bool operator==(const PointF& rhs) const
|
||||
{
|
||||
return mX == rhs.mX and mY == rhs.mY and mZ == rhs.mZ;
|
||||
}
|
||||
|
||||
// consider point as a vector... perhaps I should rename Point?
|
||||
FType lengthsq() const
|
||||
{
|
||||
return mX * mX + mY * mY + mZ * mZ;
|
||||
}
|
||||
|
||||
FType length() const
|
||||
{
|
||||
return sqrt(mX * mX + mY * mY + mZ * mZ);
|
||||
}
|
||||
};
|
||||
|
||||
typedef PointF<float> Point;
|
||||
typedef PointF<double> DPoint;
|
||||
|
||||
template<typename F>
|
||||
inline std::ostream& operator<<(std::ostream& os, const PointF<F>& pt)
|
||||
{
|
||||
os << '(' << pt.mX << ',' << pt.mY << ',' << pt.mZ << ')';
|
||||
return os;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator+(const PointF<F>& lhs, const PointF<F>& rhs)
|
||||
{
|
||||
return PointF<F>(lhs.mX + rhs.mX, lhs.mY + rhs.mY, lhs.mZ + rhs.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator-(const PointF<F>& lhs, const PointF<F>& rhs)
|
||||
{
|
||||
return PointF<F>(lhs.mX - rhs.mX, lhs.mY - rhs.mY, lhs.mZ - rhs.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator-(const PointF<F>& pt)
|
||||
{
|
||||
return PointF<F>(-pt.mX, -pt.mY, -pt.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator*(const PointF<F>& pt, F f)
|
||||
{
|
||||
return PointF<F>(pt.mX * f, pt.mY * f, pt.mZ * f);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator*(F f, const PointF<F>& pt)
|
||||
{
|
||||
return PointF<F>(pt.mX * f, pt.mY * f, pt.mZ * f);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> operator/(const PointF<F>& pt, F f)
|
||||
{
|
||||
return PointF<F>(pt.mX / f, pt.mY / f, pt.mZ / f);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// several standard 3d operations
|
||||
|
||||
template<typename F>
|
||||
inline double DistanceSquared(const PointF<F>& a, const PointF<F>& b)
|
||||
{
|
||||
return
|
||||
(a.mX - b.mX) * (a.mX - b.mX) +
|
||||
(a.mY - b.mY) * (a.mY - b.mY) +
|
||||
(a.mZ - b.mZ) * (a.mZ - b.mZ);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline double Distance(const PointF<F>& a, const PointF<F>& b)
|
||||
{
|
||||
return sqrt(
|
||||
(a.mX - b.mX) * (a.mX - b.mX) +
|
||||
(a.mY - b.mY) * (a.mY - b.mY) +
|
||||
(a.mZ - b.mZ) * (a.mZ - b.mZ));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline F DotProduct(const PointF<F>& a, const PointF<F>& b)
|
||||
{
|
||||
return a.mX * b.mX + a.mY * b.mY + a.mZ * b.mZ;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline PointF<F> CrossProduct(const PointF<F>& a, const PointF<F>& b)
|
||||
{
|
||||
return PointF<F>(a.mY * b.mZ - b.mY * a.mZ,
|
||||
a.mZ * b.mX - b.mZ * a.mX,
|
||||
a.mX * b.mY - b.mX * a.mY);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
double Angle(const PointF<F>& p1, const PointF<F>& p2, const PointF<F>& p3)
|
||||
{
|
||||
PointF<F> v1 = p1 - p2;
|
||||
PointF<F> v2 = p3 - p2;
|
||||
|
||||
return std::acos(DotProduct(v1, v2) / (v1.length() * v2.length())) * 180 / kPI;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
double DihedralAngle(const PointF<F>& p1, const PointF<F>& p2, const PointF<F>& p3, const PointF<F>& p4)
|
||||
{
|
||||
PointF<F> v12 = p1 - p2; // vector from p2 to p1
|
||||
PointF<F> v43 = p4 - p3; // vector from p3 to p4
|
||||
|
||||
PointF<F> z = p2 - p3; // vector from p3 to p2
|
||||
|
||||
PointF<F> p = CrossProduct(z, v12);
|
||||
PointF<F> x = CrossProduct(z, v43);
|
||||
PointF<F> y = CrossProduct(z, x);
|
||||
|
||||
double u = DotProduct(x, x);
|
||||
double v = DotProduct(y, y);
|
||||
|
||||
double result = 360;
|
||||
if (u > 0 and v > 0)
|
||||
{
|
||||
u = DotProduct(p, x) / sqrt(u);
|
||||
v = DotProduct(p, y) / sqrt(v);
|
||||
if (u != 0 or v != 0)
|
||||
result = atan2(v, u) * 180 / kPI;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
double CosinusAngle(const PointF<F>& p1, const PointF<F>& p2, const PointF<F>& p3, const PointF<F>& p4)
|
||||
{
|
||||
PointF<F> v12 = p1 - p2;
|
||||
PointF<F> v34 = p3 - p4;
|
||||
|
||||
double result = 0;
|
||||
|
||||
double x = DotProduct(v12, v12) * DotProduct(v34, v34);
|
||||
if (x > 0)
|
||||
result = DotProduct(v12, v34) / sqrt(x);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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.
|
||||
|
||||
template<typename F>
|
||||
PointF<F> Nudge(PointF<F> p, F offset);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// We use quaternions to do rotations in 3d space
|
||||
|
||||
quaternion Normalize(quaternion q);
|
||||
|
||||
//std::tuple<double,Point> QuaternionToAngleAxis(quaternion q);
|
||||
Point Centroid(std::vector<Point>& Points);
|
||||
Point CenterPoints(std::vector<Point>& Points);
|
||||
quaternion AlignPoints(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
|
||||
|
||||
template<int N>
|
||||
class SphericalDots
|
||||
{
|
||||
public:
|
||||
enum { P = 2 * N + 1 };
|
||||
typedef typename std::array<Point,P> array_type;
|
||||
typedef typename array_type::const_iterator iterator;
|
||||
|
||||
static SphericalDots& instance()
|
||||
{
|
||||
static SphericalDots sInstance;
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
size_t size() const { return mPoints.size(); }
|
||||
const Point operator[](uint32_t inIx) const { return mPoints[inIx]; }
|
||||
iterator begin() const { return mPoints.begin(); }
|
||||
iterator end() const { return mPoints.end(); }
|
||||
|
||||
double weight() const { return mWeight; }
|
||||
|
||||
SphericalDots()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
const double
|
||||
kGoldenRatio = (1 + std::sqrt(5.0)) / 2;
|
||||
|
||||
mWeight = (4 * kPI) / P;
|
||||
|
||||
auto p = mPoints.begin();
|
||||
|
||||
for (int32_t i = -N; i <= N; ++i)
|
||||
{
|
||||
double lat = std::asin((2.0 * i) / P);
|
||||
double lon = std::fmod(i, kGoldenRatio) * 2 * kPI / kGoldenRatio;
|
||||
|
||||
p->mX = sin(lon) * cos(lat);
|
||||
p->mY = cos(lon) * cos(lat);
|
||||
p->mZ = sin(lat);
|
||||
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
array_type mPoints;
|
||||
double mWeight;
|
||||
};
|
||||
|
||||
typedef SphericalDots<50> SphericalDots_50;
|
||||
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Calculate DSSP-like secondary structure information
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
class Structure;
|
||||
class Monomer;
|
||||
|
||||
struct Res;
|
||||
|
||||
extern const float
|
||||
kCouplingConstant, kMinHBondEnergy, kMaxHBondEnergy;
|
||||
|
||||
enum SecondaryStructureType : char
|
||||
{
|
||||
ssLoop = ' ',
|
||||
ssAlphahelix = 'H',
|
||||
ssBetabridge = 'B',
|
||||
ssStrand = 'E',
|
||||
ssHelix_3 = 'G',
|
||||
ssHelix_5 = 'I',
|
||||
ssHelix_PPII = 'P',
|
||||
ssTurn = 'T',
|
||||
ssBend = 'S'
|
||||
};
|
||||
|
||||
enum class HelixType
|
||||
{
|
||||
rh_3_10, rh_alpha, rh_pi, rh_pp
|
||||
};
|
||||
|
||||
enum class Helix
|
||||
{
|
||||
None, Start, End, StartAndEnd, Middle
|
||||
};
|
||||
|
||||
//struct HBond
|
||||
//{
|
||||
// std::string labelAsymID;
|
||||
// int labelSeqID;
|
||||
// double energy;
|
||||
//};
|
||||
//
|
||||
//struct BridgePartner
|
||||
//{
|
||||
// std::string labelAsymID;
|
||||
// int labelSeqID;
|
||||
// int ladder;
|
||||
// bool parallel;
|
||||
//};
|
||||
|
||||
struct SecondaryStructure
|
||||
{
|
||||
SecondaryStructureType type;
|
||||
// HBond donor[2], acceptor[2];
|
||||
// BridgePartner beta[2];
|
||||
// int sheet;
|
||||
// bool bend;
|
||||
};
|
||||
|
||||
//void CalculateSecondaryStructure(Structure& s);
|
||||
|
||||
const size_t
|
||||
kHistogramSize = 30;
|
||||
|
||||
struct DSSP_Statistics
|
||||
{
|
||||
uint32_t nrOfResidues, nrOfChains, nrOfSSBridges, nrOfIntraChainSSBridges, nrOfHBonds;
|
||||
uint32_t nrOfHBondsInAntiparallelBridges, nrOfHBondsInParallelBridges;
|
||||
uint32_t nrOfHBondsPerDistance[11] = {};
|
||||
double accessibleSurface = 0;
|
||||
|
||||
uint32_t residuesPerAlphaHelixHistogram[kHistogramSize] = {};
|
||||
uint32_t parallelBridgesPerLadderHistogram[kHistogramSize] = {};
|
||||
uint32_t antiparallelBridgesPerLadderHistogram[kHistogramSize] = {};
|
||||
uint32_t laddersPerSheetHistogram[kHistogramSize] = {};
|
||||
};
|
||||
|
||||
enum class ChainBreak
|
||||
{
|
||||
None, NewChain, Gap
|
||||
};
|
||||
|
||||
class DSSP
|
||||
{
|
||||
public:
|
||||
DSSP(const Structure& s, int min_poly_proline_stretch_length, bool calculateSurfaceAccessibility);
|
||||
~DSSP();
|
||||
|
||||
DSSP(const DSSP&) = delete;
|
||||
DSSP& operator=(const DSSP&) = delete;
|
||||
|
||||
SecondaryStructureType operator()(const std::string& inAsymID, int inSeqID) const;
|
||||
SecondaryStructureType operator()(const Monomer& m) const;
|
||||
|
||||
double accessibility(const std::string& inAsymID, int inSeqID) const;
|
||||
double accessibility(const Monomer& m) const;
|
||||
|
||||
bool isAlphaHelixEndBeforeStart(const Monomer& m) const;
|
||||
bool isAlphaHelixEndBeforeStart(const std::string& inAsymID, int inSeqID) const;
|
||||
|
||||
DSSP_Statistics GetStatistics() const;
|
||||
|
||||
class iterator;
|
||||
using res_iter = typename std::vector<Res>::iterator;
|
||||
|
||||
class ResidueInfo
|
||||
{
|
||||
public:
|
||||
friend class iterator;
|
||||
|
||||
explicit operator bool() const { return not empty(); }
|
||||
bool empty() const { return mImpl == nullptr; }
|
||||
|
||||
const Monomer& residue() const;
|
||||
std::string alt_id() const;
|
||||
|
||||
/// \brief return 0 if not a break, ' ' in case of a new chain and '*' in case of a broken chain
|
||||
ChainBreak chainBreak() const;
|
||||
|
||||
/// \brief the internal number in DSSP
|
||||
int nr() const;
|
||||
|
||||
SecondaryStructureType ss() const;
|
||||
|
||||
int ssBridgeNr() const;
|
||||
|
||||
Helix helix(HelixType helixType) const;
|
||||
|
||||
bool bend() const;
|
||||
|
||||
double accessibility() const;
|
||||
|
||||
/// \brief returns resinfo, ladder and parallel
|
||||
std::tuple<ResidueInfo,int,bool> bridgePartner(int i) const;
|
||||
|
||||
int sheet() const;
|
||||
|
||||
/// \brief return resinfo and the energy of the bond
|
||||
std::tuple<ResidueInfo,double> acceptor(int i) const;
|
||||
std::tuple<ResidueInfo,double> donor(int i) const;
|
||||
|
||||
private:
|
||||
ResidueInfo(Res* res);
|
||||
|
||||
Res* mImpl;
|
||||
};
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = ResidueInfo;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
iterator(const iterator& i);
|
||||
iterator(res_iter cur);
|
||||
iterator& operator=(const iterator& i);
|
||||
|
||||
reference operator*() { return mCurrent; }
|
||||
pointer operator->() { return &mCurrent; }
|
||||
|
||||
iterator& operator++();
|
||||
iterator operator++(int)
|
||||
{
|
||||
auto tmp(*this);
|
||||
this->operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const iterator& rhs) const { return mCurrent.mImpl == rhs.mCurrent.mImpl; }
|
||||
bool operator!=(const iterator& rhs) const { return mCurrent.mImpl != rhs.mCurrent.mImpl; }
|
||||
|
||||
private:
|
||||
ResidueInfo mCurrent;
|
||||
};
|
||||
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
|
||||
bool empty() const { return begin() == end(); }
|
||||
|
||||
private:
|
||||
struct DSSPImpl* mImpl;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -1,539 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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 <numeric>
|
||||
|
||||
#include "cif++/AtomType.hpp"
|
||||
#include "cif++/Point.hpp"
|
||||
#include "cif++/Compound.hpp"
|
||||
#include "cif++/Cif++.hpp"
|
||||
|
||||
/*
|
||||
To modify a structure, you will have to use actions.
|
||||
|
||||
The currently supported actions are:
|
||||
|
||||
// - Move atom to new location
|
||||
- Remove atom
|
||||
// - Add new atom that was formerly missing
|
||||
// - Add alternate Residue
|
||||
-
|
||||
|
||||
*/
|
||||
|
||||
namespace mmcif
|
||||
{
|
||||
|
||||
class Atom;
|
||||
class Residue;
|
||||
class Monomer;
|
||||
class Polymer;
|
||||
class Structure;
|
||||
class File;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class Atom
|
||||
{
|
||||
public:
|
||||
// Atom(const structure& s, const std::string& id);
|
||||
Atom();
|
||||
Atom(struct AtomImpl* impl);
|
||||
Atom(const Atom& rhs);
|
||||
|
||||
~Atom();
|
||||
|
||||
explicit operator bool() const { return mImpl_ != nullptr; }
|
||||
|
||||
// return a copy of this atom, with data copied instead of referenced
|
||||
Atom clone() const;
|
||||
|
||||
Atom& operator=(const Atom& rhs);
|
||||
|
||||
const std::string& id() const;
|
||||
AtomType type() const;
|
||||
|
||||
Point location() const;
|
||||
void location(Point p);
|
||||
|
||||
// Atom symmetryCopy(const Point& d, const clipper::RTop_orth& rt);
|
||||
// bool isSymmetryCopy() const;
|
||||
// std::string symmetry() const;
|
||||
// const clipper::RTop_orth& symop() const;
|
||||
|
||||
const Compound& comp() const;
|
||||
bool isWater() const;
|
||||
int charge() const;
|
||||
|
||||
float uIso() const;
|
||||
bool getAnisoU(float anisou[6]) const;
|
||||
float occupancy() const;
|
||||
|
||||
template<typename T>
|
||||
T property(const std::string& name) const;
|
||||
|
||||
template<typename T>
|
||||
void property(const std::string& name, const T& value);
|
||||
|
||||
// specifications
|
||||
std::string labelAtomID() const;
|
||||
std::string labelCompID() const;
|
||||
std::string labelAsymID() const;
|
||||
int labelSeqID() const;
|
||||
std::string labelAltID() const;
|
||||
bool isAlternate() const;
|
||||
|
||||
std::string authAtomID() const;
|
||||
std::string authCompID() const;
|
||||
std::string authAsymID() const;
|
||||
std::string authSeqID() const;
|
||||
std::string pdbxAuthInsCode() const;
|
||||
std::string pdbxAuthAltID() const;
|
||||
|
||||
std::string labelID() const;// label_comp_id + '_' + label_asym_id + '_' + label_seq_id
|
||||
std::string pdbID() const; // auth_comp_id + '_' + auth_asym_id + '_' + auth_seq_id + pdbx_PDB_ins_code
|
||||
|
||||
bool operator==(const Atom& rhs) const;
|
||||
|
||||
// // get clipper format Atom
|
||||
// clipper::Atom toClipper() const;
|
||||
|
||||
// Radius calculation based on integrating the density until perc of electrons is found
|
||||
void calculateRadius(float resHigh, float resLow, float perc);
|
||||
float radius() const;
|
||||
|
||||
// access data in compound for this atom
|
||||
|
||||
// the energy-type field
|
||||
std::string energyType() const;
|
||||
|
||||
// convenience routine
|
||||
bool isBackBone() const
|
||||
{
|
||||
auto atomID = labelAtomID();
|
||||
return atomID == "N" or atomID == "O" or atomID == "C" or atomID == "CA";
|
||||
}
|
||||
|
||||
void swap(Atom& b)
|
||||
{
|
||||
std::swap(mImpl_, b.mImpl_);
|
||||
}
|
||||
|
||||
int compare(const Atom& b) const;
|
||||
|
||||
bool operator<(const Atom& rhs) const
|
||||
{
|
||||
return compare(rhs) < 0;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Atom& atom);
|
||||
|
||||
private:
|
||||
friend class Structure;
|
||||
void setID(int id);
|
||||
|
||||
AtomImpl* impl();
|
||||
const AtomImpl* impl() const;
|
||||
|
||||
struct AtomImpl* mImpl_;
|
||||
};
|
||||
|
||||
inline void swap(mmcif::Atom& a, mmcif::Atom& b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
inline double Distance(const Atom& a, const Atom& b)
|
||||
{
|
||||
return Distance(a.location(), b.location());
|
||||
}
|
||||
|
||||
inline double DistanceSquared(const Atom& a, const Atom& b)
|
||||
{
|
||||
return DistanceSquared(a.location(), b.location());
|
||||
}
|
||||
|
||||
typedef std::vector<Atom> AtomView;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class Residue
|
||||
{
|
||||
public:
|
||||
// constructors should be private, but that's not possible for now (needed in emplace)
|
||||
// constructor for waters
|
||||
Residue(const Structure& structure, const std::string& compoundID,
|
||||
const std::string& asymID, const std::string& authSeqID);
|
||||
|
||||
Residue(const Structure& structure, const std::string& compoundID,
|
||||
const std::string& asymID, int seqID = 0);
|
||||
|
||||
Residue(const Residue& rhs) = delete;
|
||||
Residue& operator=(const Residue& rhs) = delete;
|
||||
|
||||
Residue(Residue&& rhs);
|
||||
Residue& operator=(Residue&& rhs);
|
||||
|
||||
virtual ~Residue();
|
||||
|
||||
const Compound& compound() const;
|
||||
const AtomView& atoms() const;
|
||||
|
||||
/// \brief Unique atoms returns only the atoms without alternates and the first of each alternate atom id.
|
||||
AtomView unique_atoms() const;
|
||||
|
||||
/// \brief The alt ID used for the unique atoms
|
||||
std::string unique_alt_id() const;
|
||||
|
||||
Atom atomByID(const std::string& atomID) const;
|
||||
|
||||
const std::string& compoundID() const { return mCompoundID; }
|
||||
const std::string& asymID() const { return mAsymID; }
|
||||
int seqID() const { return mSeqID; }
|
||||
|
||||
std::string authAsymID() const;
|
||||
std::string authSeqID() const;
|
||||
std::string authInsCode() const;
|
||||
|
||||
// return a human readable PDB-like auth id (chain+seqnr+iCode)
|
||||
std::string authID() const;
|
||||
|
||||
// similar for mmCIF space
|
||||
std::string labelID() const;
|
||||
|
||||
// Is this residue a single entity?
|
||||
bool isEntity() const;
|
||||
|
||||
bool isWater() const { return mCompoundID == "HOH"; }
|
||||
|
||||
const Structure& structure() const { return *mStructure; }
|
||||
|
||||
bool empty() const { return mStructure == nullptr; }
|
||||
|
||||
bool hasAlternateAtoms() const;
|
||||
|
||||
// some routines for 3d work
|
||||
std::tuple<Point,float> centerAndRadius() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Residue& res);
|
||||
|
||||
protected:
|
||||
|
||||
Residue() {}
|
||||
|
||||
friend class Polymer;
|
||||
|
||||
const Structure* mStructure = nullptr;
|
||||
std::string mCompoundID, mAsymID;
|
||||
int mSeqID = 0;
|
||||
std::string mAuthSeqID;
|
||||
AtomView mAtoms;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// a monomer models a single Residue in a protein chain
|
||||
|
||||
class Monomer : public Residue
|
||||
{
|
||||
public:
|
||||
// Monomer();
|
||||
Monomer(const Monomer& rhs) = delete;
|
||||
Monomer& operator=(const Monomer& rhs) = delete;
|
||||
|
||||
Monomer(Monomer&& rhs);
|
||||
Monomer& operator=(Monomer&& rhs);
|
||||
|
||||
// Monomer(const Polymer& polymer, uint32_t index);
|
||||
Monomer(const Polymer& polymer, uint32_t index, int seqID,
|
||||
const std::string& compoundID);
|
||||
|
||||
bool is_first_in_chain() const;
|
||||
bool is_last_in_chain() const;
|
||||
|
||||
// convenience
|
||||
bool has_alpha() const;
|
||||
bool has_kappa() const;
|
||||
|
||||
// Assuming this is really an amino acid...
|
||||
|
||||
float phi() const;
|
||||
float psi() const;
|
||||
float alpha() const;
|
||||
float kappa() const;
|
||||
float tco() const;
|
||||
float omega() const;
|
||||
|
||||
// torsion angles
|
||||
size_t nrOfChis() const;
|
||||
float chi(size_t i) const;
|
||||
|
||||
bool isCis() const;
|
||||
|
||||
/// \brief Returns true if the four atoms C, CA, N and O are present
|
||||
bool isComplete() const;
|
||||
|
||||
/// \brief Returns true if any of the backbone atoms has an alternate
|
||||
bool hasAlternateBackboneAtoms() const;
|
||||
|
||||
Atom CAlpha() const { return atomByID("CA"); }
|
||||
Atom C() const { return atomByID("C"); }
|
||||
Atom N() const { return atomByID("N"); }
|
||||
Atom O() const { return atomByID("O"); }
|
||||
Atom H() const { return atomByID("H"); }
|
||||
|
||||
bool isBondedTo(const Monomer& rhs) const
|
||||
{
|
||||
return this != &rhs and areBonded(*this, rhs);
|
||||
}
|
||||
|
||||
static bool areBonded(const Monomer& a, const Monomer& b, float errorMargin = 0.5f);
|
||||
static bool isCis(const Monomer& a, const Monomer& b);
|
||||
static float omega(const Monomer& a, const Monomer& b);
|
||||
|
||||
// for LEU and VAL
|
||||
float chiralVolume() const;
|
||||
|
||||
private:
|
||||
const Polymer* mPolymer;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class Polymer : public std::vector<Monomer>
|
||||
{
|
||||
public:
|
||||
Polymer(const Structure& s, const std::string& entityID, const std::string& asymID);
|
||||
|
||||
Polymer(const Polymer&) = delete;
|
||||
Polymer& operator=(const Polymer&) = delete;
|
||||
|
||||
// Polymer(Polymer&& rhs) = delete;
|
||||
// Polymer& operator=(Polymer&& rhs) = de;
|
||||
|
||||
Monomer& getBySeqID(int seqID);
|
||||
const Monomer& getBySeqID(int seqID) const;
|
||||
|
||||
Structure* structure() const { return mStructure; }
|
||||
|
||||
std::string asymID() const { return mAsymID; }
|
||||
std::string entityID() const { return mEntityID; }
|
||||
|
||||
std::string chainID() const;
|
||||
|
||||
int Distance(const Monomer& a, const Monomer& b) const;
|
||||
|
||||
private:
|
||||
|
||||
Structure* mStructure;
|
||||
std::string mEntityID;
|
||||
std::string mAsymID;
|
||||
cif::RowSet mPolySeq;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// file is a reference to the data stored in e.g. the cif file.
|
||||
// This object is not copyable.
|
||||
|
||||
class File : public std::enable_shared_from_this<File>
|
||||
{
|
||||
public:
|
||||
File();
|
||||
File(const std::string& path);
|
||||
~File();
|
||||
|
||||
File(const File&) = delete;
|
||||
File& operator=(const File&) = delete;
|
||||
|
||||
void load(const std::string& path);
|
||||
void save(const std::string& path);
|
||||
|
||||
Structure* model(size_t nr = 1);
|
||||
|
||||
struct FileImpl& impl() const { return *mImpl; }
|
||||
|
||||
cif::Datablock& data();
|
||||
cif::File& file();
|
||||
|
||||
private:
|
||||
|
||||
struct FileImpl* mImpl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
enum class StructureOpenOptions
|
||||
{
|
||||
SkipHydrogen = 1 << 0
|
||||
};
|
||||
|
||||
inline bool operator&(StructureOpenOptions a, StructureOpenOptions b)
|
||||
{
|
||||
return static_cast<int>(a) bitand static_cast<int>(b);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class Structure
|
||||
{
|
||||
public:
|
||||
Structure(File& p, uint32_t modelNr = 1, StructureOpenOptions options = {});
|
||||
Structure& operator=(const Structure&) = delete;
|
||||
~Structure();
|
||||
|
||||
// Create a read-only clone of the current structure (for multithreaded calculations that move atoms)
|
||||
Structure(const Structure&);
|
||||
|
||||
File& getFile() const;
|
||||
|
||||
const AtomView& atoms() const { return mAtoms; }
|
||||
AtomView waters() const;
|
||||
|
||||
const std::list<Polymer>& polymers() const { return mPolymers; }
|
||||
std::list<Polymer>& polymers() { return mPolymers; }
|
||||
|
||||
const std::vector<Residue>& nonPolymers() const { return mNonPolymers; }
|
||||
|
||||
Atom getAtomByID(std::string id) const;
|
||||
// Atom getAtomByLocation(Point pt, float maxDistance) const;
|
||||
|
||||
Atom getAtomByLabel(const std::string& atomID, const std::string& asymID,
|
||||
const std::string& compID, int seqID, const std::string& altID = "");
|
||||
|
||||
// Atom getAtomByAuth(const std::string& atomID, const std::string& asymID,
|
||||
// const std::string& compID, int seqID, const std::string& altID = "",
|
||||
// const std::string& pdbxAuthInsCode = "");
|
||||
|
||||
// map between auth and label locations
|
||||
|
||||
std::tuple<std::string,int,std::string> MapAuthToLabel(const std::string& asymID,
|
||||
const std::string& seqID, const std::string& compID, const std::string& insCode = "");
|
||||
|
||||
std::tuple<std::string,std::string,std::string,std::string> MapLabelToAuth(
|
||||
const std::string& asymID, int seqID, const std::string& compID);
|
||||
|
||||
// returns chain, seqnr, icode
|
||||
std::tuple<char,int,char> MapLabelToAuth(
|
||||
const std::string& asymID, int seqID) const;
|
||||
|
||||
// returns chain,seqnr,comp,iCode
|
||||
std::tuple<std::string,int,std::string,std::string> MapLabelToPDB(
|
||||
const std::string& asymID, int seqID, const std::string& compID,
|
||||
const std::string& authSeqID) const;
|
||||
|
||||
std::tuple<std::string,int,std::string> MapPDBToLabel(
|
||||
const std::string& asymID, int seqID, const std::string& compID, const std::string& iCode) const;
|
||||
|
||||
// Actions
|
||||
void removeAtom(Atom& a);
|
||||
void swapAtoms(Atom& a1, Atom& a2); // swap the labels for these atoms
|
||||
void moveAtom(Atom& a, Point p); // move atom to a new location
|
||||
void changeResidue(const Residue& res, const std::string& newCompound,
|
||||
const std::vector<std::tuple<std::string,std::string>>& remappedAtoms);
|
||||
|
||||
/// To sort the atoms in order of model > asym-id > res-id > atom-id
|
||||
/// Will asssign new atom_id's to all atoms. Be carefull
|
||||
void sortAtoms();
|
||||
|
||||
// iterator for all residues
|
||||
|
||||
class residue_iterator : public std::iterator<std::forward_iterator_tag, const Residue>
|
||||
{
|
||||
public:
|
||||
typedef std::iterator<std::forward_iterator_tag, const Residue> baseType;
|
||||
typedef typename baseType::pointer pointer;
|
||||
typedef typename baseType::reference reference;
|
||||
|
||||
typedef std::list<Polymer>::const_iterator poly_iterator;
|
||||
|
||||
residue_iterator(const Structure* s, poly_iterator polyIter, size_t polyResIndex, size_t nonPolyIndex);
|
||||
|
||||
reference operator*();
|
||||
pointer operator->();
|
||||
|
||||
residue_iterator& operator++();
|
||||
residue_iterator operator++(int);
|
||||
|
||||
bool operator==(const residue_iterator& rhs) const;
|
||||
bool operator!=(const residue_iterator& rhs) const;
|
||||
|
||||
private:
|
||||
const Structure& mStructure;
|
||||
poly_iterator mPolyIter;
|
||||
size_t mPolyResIndex;
|
||||
size_t mNonPolyIndex;
|
||||
};
|
||||
|
||||
class residue_view
|
||||
{
|
||||
public:
|
||||
residue_view(const Structure* s) : mStructure(s) {}
|
||||
residue_view(const residue_view& rhs) : mStructure(rhs.mStructure) {}
|
||||
residue_view& operator=(residue_view& rhs)
|
||||
{
|
||||
mStructure = rhs.mStructure;
|
||||
return *this;
|
||||
}
|
||||
|
||||
residue_iterator begin() const { return residue_iterator(mStructure, mStructure->mPolymers.begin(), 0, 0); }
|
||||
residue_iterator end() const { return residue_iterator(mStructure, mStructure->mPolymers.end(), 0, mStructure->mNonPolymers.size()); }
|
||||
size_t size() const
|
||||
{
|
||||
size_t ps = std::accumulate(mStructure->mPolymers.begin(), mStructure->mPolymers.end(), 0UL, [](size_t s, auto& p) { return s + p.size(); });
|
||||
return ps + mStructure->mNonPolymers.size();
|
||||
}
|
||||
|
||||
private:
|
||||
const Structure* mStructure;
|
||||
};
|
||||
|
||||
residue_view residues() const { return residue_view(this); }
|
||||
|
||||
private:
|
||||
friend Polymer;
|
||||
friend Residue;
|
||||
friend residue_view;
|
||||
friend residue_iterator;
|
||||
|
||||
cif::Category& category(const char* name) const;
|
||||
cif::Datablock& datablock() const;
|
||||
|
||||
void insertCompound(const std::string& compoundID, bool isEntity);
|
||||
|
||||
void loadData();
|
||||
void updateAtomIndex();
|
||||
|
||||
File& mFile;
|
||||
uint32_t mModelNr;
|
||||
AtomView mAtoms;
|
||||
std::vector<size_t> mAtomIndex;
|
||||
std::list<Polymer> mPolymers;
|
||||
std::vector<Residue> mNonPolymers;
|
||||
};
|
||||
|
||||
}
|
||||
340
include/cif++/atom_type.hpp
Normal file
340
include/cif++/atom_type.hpp
Normal file
@@ -0,0 +1,340 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** \file atom_type.hpp
|
||||
*
|
||||
* This file contains information about all known elements
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <array>
|
||||
#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
|
||||
|
||||
H = 1, ///< Hydrogen
|
||||
He = 2, ///< Helium
|
||||
|
||||
Li = 3, ///< Lithium
|
||||
Be = 4, ///< Beryllium
|
||||
B = 5, ///< Boron
|
||||
C = 6, ///< Carbon
|
||||
N = 7, ///< Nitrogen
|
||||
O = 8, ///< Oxygen
|
||||
F = 9, ///< Fluorine
|
||||
Ne = 10, ///< Neon
|
||||
|
||||
Na = 11, ///< Sodium
|
||||
Mg = 12, ///< Magnesium
|
||||
Al = 13, ///< Aluminium
|
||||
Si = 14, ///< Silicon
|
||||
P = 15, ///< Phosphorus
|
||||
S = 16, ///< Sulfur
|
||||
Cl = 17, ///< Chlorine
|
||||
Ar = 18, ///< Argon
|
||||
|
||||
K = 19, ///< Potassium
|
||||
Ca = 20, ///< Calcium
|
||||
Sc = 21, ///< Scandium
|
||||
Ti = 22, ///< Titanium
|
||||
V = 23, ///< Vanadium
|
||||
Cr = 24, ///< Chromium
|
||||
Mn = 25, ///< Manganese
|
||||
Fe = 26, ///< Iron
|
||||
Co = 27, ///< Cobalt
|
||||
Ni = 28, ///< Nickel
|
||||
Cu = 29, ///< Copper
|
||||
Zn = 30, ///< Zinc
|
||||
Ga = 31, ///< Gallium
|
||||
Ge = 32, ///< Germanium
|
||||
As = 33, ///< Arsenic
|
||||
Se = 34, ///< Selenium
|
||||
Br = 35, ///< Bromine
|
||||
Kr = 36, ///< Krypton
|
||||
|
||||
Rb = 37, ///< Rubidium
|
||||
Sr = 38, ///< Strontium
|
||||
Y = 39, ///< Yttrium
|
||||
Zr = 40, ///< Zirconium
|
||||
Nb = 41, ///< Niobium
|
||||
Mo = 42, ///< Molybdenum
|
||||
Tc = 43, ///< Technetium
|
||||
Ru = 44, ///< Ruthenium
|
||||
Rh = 45, ///< Rhodium
|
||||
Pd = 46, ///< Palladium
|
||||
Ag = 47, ///< Silver
|
||||
Cd = 48, ///< Cadmium
|
||||
In = 49, ///< Indium
|
||||
Sn = 50, ///< Tin
|
||||
Sb = 51, ///< Antimony
|
||||
Te = 52, ///< Tellurium
|
||||
I = 53, ///< Iodine
|
||||
Xe = 54, ///< Xenon
|
||||
Cs = 55, ///< Caesium
|
||||
Ba = 56, ///< Barium
|
||||
La = 57, ///< Lanthanum
|
||||
|
||||
Hf = 72, ///< Hafnium
|
||||
Ta = 73, ///< Tantalum
|
||||
W = 74, ///< Tungsten
|
||||
Re = 75, ///< Rhenium
|
||||
Os = 76, ///< Osmium
|
||||
Ir = 77, ///< Iridium
|
||||
Pt = 78, ///< Platinum
|
||||
Au = 79, ///< Gold
|
||||
Hg = 80, ///< Mercury
|
||||
Tl = 81, ///< Thallium
|
||||
Pb = 82, ///< Lead
|
||||
Bi = 83, ///< Bismuth
|
||||
Po = 84, ///< Polonium
|
||||
At = 85, ///< Astatine
|
||||
Rn = 86, ///< Radon
|
||||
Fr = 87, ///< Francium
|
||||
Ra = 88, ///< Radium
|
||||
Ac = 89, ///< Actinium
|
||||
|
||||
Rf = 104, ///< Rutherfordium
|
||||
Db = 105, ///< Dubnium
|
||||
Sg = 106, ///< Seaborgium
|
||||
Bh = 107, ///< Bohrium
|
||||
Hs = 108, ///< Hassium
|
||||
Mt = 109, ///< Meitnerium
|
||||
Ds = 110, ///< Darmstadtium
|
||||
Rg = 111, ///< Roentgenium
|
||||
Cn = 112, ///< Copernicium
|
||||
Nh = 113, ///< Nihonium
|
||||
Fl = 114, ///< Flerovium
|
||||
Mc = 115, ///< Moscovium
|
||||
Lv = 116, ///< Livermorium
|
||||
Ts = 117, ///< Tennessine
|
||||
Og = 118, ///< Oganesson
|
||||
|
||||
Ce = 58, ///< Cerium
|
||||
Pr = 59, ///< Praseodymium
|
||||
Nd = 60, ///< Neodymium
|
||||
Pm = 61, ///< Promethium
|
||||
Sm = 62, ///< Samarium
|
||||
Eu = 63, ///< Europium
|
||||
Gd = 64, ///< Gadolinium
|
||||
Tb = 65, ///< Terbium
|
||||
Dy = 66, ///< Dysprosium
|
||||
Ho = 67, ///< Holmium
|
||||
Er = 68, ///< Erbium
|
||||
Tm = 69, ///< Thulium
|
||||
Yb = 70, ///< Ytterbium
|
||||
Lu = 71, ///< Lutetium
|
||||
|
||||
Th = 90, ///< Thorium
|
||||
Pa = 91, ///< Protactinium
|
||||
U = 92, ///< Uranium
|
||||
Np = 93, ///< Neptunium
|
||||
Pu = 94, ///< Plutonium
|
||||
Am = 95, ///< Americium
|
||||
Cm = 96, ///< Curium
|
||||
Bk = 97, ///< Berkelium
|
||||
Cf = 98, ///< Californium
|
||||
Es = 99, ///< Einsteinium
|
||||
Fm = 100, ///< Fermium
|
||||
Md = 101, ///< Mendelevium
|
||||
No = 102, ///< Nobelium
|
||||
Lr = 103, ///< Lawrencium
|
||||
|
||||
D = 119, ///< Deuterium
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// 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, ///< 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, ///< 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, ///< Radius of an imaginary hard sphere representing the distance of closest approach for another atom
|
||||
|
||||
type_count ///< Number of radii
|
||||
};
|
||||
|
||||
/// @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, ///< 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
|
||||
std::array<float, kRadiusTypeCount> radii;
|
||||
};
|
||||
|
||||
/// 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);
|
||||
|
||||
[[nodiscard]] atom_type type() const { return m_info->type; } ///< Returns the atom_type
|
||||
[[nodiscard]] std::string name() const { return m_info->name; } ///< Returns the name of the element
|
||||
[[nodiscard]] std::string symbol() const { return m_info->symbol; } ///< Returns the symbol of the element
|
||||
[[nodiscard]] float weight() const { return m_info->weight; } ///< Returns the average weight of the element
|
||||
|
||||
[[nodiscard]] 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)
|
||||
[[nodiscard]] 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<std::size_t>(type)] / 100.f;
|
||||
}
|
||||
|
||||
/// \brief Return the radius for a charged version of this atom in a solid crystal
|
||||
///
|
||||
/// \param charge The charge of the ion
|
||||
/// \return The radius of the ion
|
||||
[[nodiscard]] float crystal_ionic_radius(int charge) const;
|
||||
|
||||
/// \brief Return the radius for a charged version of this atom in a non-solid environment
|
||||
///
|
||||
/// \param charge The charge of the ion
|
||||
/// \return The radius of the ion
|
||||
[[nodiscard]] float effective_ionic_radius(int charge) const;
|
||||
|
||||
/// \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
|
||||
[[nodiscard]] 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief data type encapsulating the scattering factors
|
||||
* in a simplified form (only a and b).
|
||||
*/
|
||||
struct SFData
|
||||
{
|
||||
/** @cond */
|
||||
double a[6], b[6];
|
||||
/** @endcond */
|
||||
};
|
||||
|
||||
/// @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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] bool has_sf(int charge) const;
|
||||
|
||||
private:
|
||||
const struct atom_type_info *m_info;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
1340
include/cif++/category.hpp
Normal file
1340
include/cif++/category.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -26,32 +26,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "cif++/Cif++.hpp"
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
extern const int
|
||||
kResidueNrWildcard,
|
||||
kNoSeqNum;
|
||||
|
||||
struct TLSSelection;
|
||||
typedef std::unique_ptr<TLSSelection> TLSSelectionPtr;
|
||||
|
||||
struct TLSResidue;
|
||||
|
||||
struct TLSSelection
|
||||
{
|
||||
virtual ~TLSSelection() {}
|
||||
virtual void CollectResidues(cif::Datablock& db, std::vector<TLSResidue>& residues, int indentLevel = 0) const = 0;
|
||||
std::vector<std::tuple<std::string,int,int>> GetRanges(cif::Datablock& db, bool pdbNamespace) const;
|
||||
};
|
||||
|
||||
// Low level: get the selections
|
||||
TLSSelectionPtr ParseSelectionDetails(const std::string& program, const std::string& selection);
|
||||
|
||||
}
|
||||
// IWYU pragma: begin_exports
|
||||
#include "cif++/atom_type.hpp"
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/compound.hpp"
|
||||
#include "cif++/condition.hpp"
|
||||
#include "cif++/cql.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/dictionary_parser.hpp"
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/file.hpp"
|
||||
#include "cif++/format.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.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"
|
||||
// IWYU pragma: end_exports
|
||||
360
include/cif++/compound.hpp
Normal file
360
include/cif++/compound.hpp
Normal file
@@ -0,0 +1,360 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020-2022 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++/datablock.hpp"
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#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
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class compound_factory_impl;
|
||||
class datablock;
|
||||
class file;
|
||||
enum atom_type : uint8_t;
|
||||
|
||||
/// \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
|
||||
};
|
||||
|
||||
/// @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.
|
||||
/// This is a subset of the available information. Contact the author if you need more fields.
|
||||
|
||||
struct compound_atom
|
||||
{
|
||||
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
|
||||
[[nodiscard]] point get_location() const
|
||||
{
|
||||
return { x, y, z };
|
||||
}
|
||||
};
|
||||
|
||||
/// --------------------------------------------------------------------
|
||||
/// \brief struct containing information about the bonds
|
||||
|
||||
struct compound_bond
|
||||
{
|
||||
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.
|
||||
};
|
||||
|
||||
/// --------------------------------------------------------------------
|
||||
/// \brief a class that contains information about a chemical compound.
|
||||
/// 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 push_dictionary function and
|
||||
/// pass it a valid CCD formatted file.
|
||||
|
||||
class compound
|
||||
{
|
||||
public:
|
||||
// accessors
|
||||
|
||||
[[nodiscard]] std::string id() const { return m_id; } ///< Return the alphanumeric code for the chemical component.
|
||||
[[nodiscard]] std::string name() const { return m_name; } ///< Return the name of the chemical component.
|
||||
[[nodiscard]] std::string type() const { return m_type; } ///< Return the type of monomer.
|
||||
[[nodiscard]] std::string formula() const { return m_formula; } ///< Return the chemical formula of the chemical component.
|
||||
[[nodiscard]] float formula_weight() const { return m_formula_weight; } ///< Return the formula mass of the chemical component in Daltons.
|
||||
[[nodiscard]] int formal_charge() const { return m_formal_charge; } ///< Return the formal charge on the chemical component.
|
||||
|
||||
[[nodiscard]] const std::vector<compound_atom> &atoms() const { return m_atoms; } ///< Return the list of atoms for this compound
|
||||
[[nodiscard]] const std::vector<compound_bond> &bonds() const { return m_bonds; } ///< Return the list of bonds for this compound
|
||||
|
||||
[[nodiscard]] compound_atom get_atom_by_atom_id(const std::string &atom_id) const; ///< Return the atom with id @a atom_id
|
||||
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] 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
|
||||
|
||||
[[nodiscard]] 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' */
|
||||
[[nodiscard]] bool is_peptide() const;
|
||||
|
||||
/** \brief Return whether this compound has a type of either 'DNA linking' or 'RNA linking' */
|
||||
[[nodiscard]] bool is_base() const;
|
||||
|
||||
/// Return the one letter code to use in a canonical sequence. If unknown the value '\0' is returned
|
||||
[[nodiscard]] char one_letter_code() const { return m_one_letter_code; };
|
||||
|
||||
/// Return the parent id code in case a parent is specified (e.g. MET for MSE)
|
||||
[[nodiscard]] std::string parent_id() const { return m_parent_id; };
|
||||
|
||||
private:
|
||||
friend class compound_factory_impl;
|
||||
friend class local_compound_factory_impl;
|
||||
|
||||
compound(datablock &db);
|
||||
|
||||
std::string m_id;
|
||||
std::string m_name;
|
||||
std::string m_type;
|
||||
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;
|
||||
std::vector<compound_bond> m_bonds;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Factory class for compound and Link objects
|
||||
|
||||
/// Use the compound_factory singleton instance to create compound objects
|
||||
|
||||
class compound_factory
|
||||
{
|
||||
public:
|
||||
compound_factory(const compound_factory &) = delete;
|
||||
compound_factory &operator=(const compound_factory &) = delete;
|
||||
|
||||
/// \brief Initialise a singleton instance.
|
||||
///
|
||||
/// If you have a multithreaded application and want to have different
|
||||
/// compounds in each thread (e.g. a web service processing user requests
|
||||
/// with different sets of compounds) you can set the \a useThreadLocalInstanceOnly
|
||||
/// 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)")]]
|
||||
[[nodiscard]] 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)")]]
|
||||
[[nodiscard]] bool
|
||||
is_known_base(const std::string &res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a peptide
|
||||
[[nodiscard]] bool is_peptide(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a base
|
||||
[[nodiscard]] bool is_base(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard peptides
|
||||
[[nodiscard]] bool is_std_peptide(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard bases
|
||||
[[nodiscard]] bool is_std_base(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is a monomer (either base or peptide)
|
||||
[[nodiscard]] bool is_monomer(std::string_view res_name) const;
|
||||
|
||||
/// Return whether @a res_name is one of the standard bases or peptides
|
||||
[[nodiscard]] bool is_std_monomer(std::string_view res_name) const
|
||||
{
|
||||
return is_std_base(res_name) or is_std_peptide(res_name);
|
||||
}
|
||||
|
||||
/// Return whether @a res_name is water
|
||||
[[nodiscard]] bool is_water(std::string_view res_name) const
|
||||
{
|
||||
return res_name == "HOH" or res_name == "H2O" or res_name == "WAT";
|
||||
}
|
||||
|
||||
/// Return whether @a res_name already exists, without creating it.
|
||||
[[nodiscard]] bool exists(std::string_view res_name) const;
|
||||
|
||||
/// \brief Create the compound object for \a id
|
||||
///
|
||||
/// This will create the compound instance for \a id if it doesn't exist already.
|
||||
/// The result is owned by this factory and should not be deleted by the user.
|
||||
/// \param id The compound ID, a three letter code usually
|
||||
/// \result The compound, or nullptr if it could not be created (missing info)
|
||||
const compound *create(std::string_view id);
|
||||
|
||||
~compound_factory() = default;
|
||||
|
||||
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
|
||||
|
||||
/// Print out a message for a missing compound
|
||||
void report_missing_compound(std::string_view compound_id);
|
||||
|
||||
/// Return a flag indicating if we need to print out a report
|
||||
[[nodiscard]] bool get_report_missing() const { return m_report_missing; }
|
||||
|
||||
/// Set a flag indicating if we need to print out a report
|
||||
void set_report_missing(bool report)
|
||||
{
|
||||
m_report_missing = report;
|
||||
}
|
||||
|
||||
private:
|
||||
compound_factory();
|
||||
|
||||
static std::unique_ptr<compound_factory> s_instance;
|
||||
static thread_local std::unique_ptr<compound_factory> tl_instance;
|
||||
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:
|
||||
/// Constructor
|
||||
compound_source(const file &file)
|
||||
{
|
||||
compound_factory::instance().push_dictionary(file);
|
||||
}
|
||||
|
||||
~compound_source()
|
||||
{
|
||||
compound_factory::instance().pop_dictionary();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
1208
include/cif++/condition.hpp
Normal file
1208
include/cif++/condition.hpp
Normal file
File diff suppressed because it is too large
Load Diff
507
include/cif++/cql.hpp
Normal file
507
include/cif++/cql.hpp
Normal file
@@ -0,0 +1,507 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file cql.hpp
|
||||
*
|
||||
* This file contains code to access stored data as if it were
|
||||
* a relation database. The underlying code uses SQLite as engine.
|
||||
* categories are exposed as virtual tables.
|
||||
*/
|
||||
|
||||
#include "cif++/category.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/iterator.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
namespace cif::cql
|
||||
{
|
||||
|
||||
class connection;
|
||||
struct result_impl;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Reference to a field in the result set
|
||||
class field_ref final
|
||||
{
|
||||
public:
|
||||
/// The name of the field
|
||||
[[nodiscard]] std::string_view name() const &
|
||||
{
|
||||
return m_row.get_category().get_item_name(m_index);
|
||||
}
|
||||
|
||||
/// The index number of the field
|
||||
[[nodiscard]] constexpr size_t num() const noexcept
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
/** Return the contents of this item as type @tparam T */
|
||||
template <typename T = std::string>
|
||||
[[nodiscard]] auto get() const -> T
|
||||
{
|
||||
return m_row[m_index].get<T>();
|
||||
}
|
||||
|
||||
/// Returns true if the field contains NULL
|
||||
[[nodiscard]] bool is_null() const
|
||||
{
|
||||
return m_row[m_index].is_null();
|
||||
}
|
||||
|
||||
/** 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 m_row[m_index].value_or(dv);
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
field_ref(const_row_handle rh, uint16_t col, std::shared_ptr<result_impl> result_impl)
|
||||
: m_row(std::move(rh))
|
||||
, m_index(col)
|
||||
, m_result_impl(std::move(result_impl))
|
||||
{
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
field_ref(const field_ref &) = default;
|
||||
/// Move constructor
|
||||
field_ref(field_ref &&) = default;
|
||||
|
||||
/// Copy assignment
|
||||
field_ref &operator=(const field_ref &) = default;
|
||||
/// Move assignment
|
||||
field_ref &operator=(field_ref &&) = default;
|
||||
|
||||
private:
|
||||
const_row_handle m_row;
|
||||
uint16_t m_index;
|
||||
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A reference to a row in the result set
|
||||
class row_ref final
|
||||
{
|
||||
public:
|
||||
/// Iterator for the items in this row
|
||||
class const_field_iterator
|
||||
{
|
||||
public:
|
||||
friend class result;
|
||||
|
||||
/// @cond
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = const field_ref;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
const_field_iterator(const const_field_iterator &) = default;
|
||||
const_field_iterator(const_field_iterator &&) = default;
|
||||
|
||||
const_field_iterator &operator=(const const_field_iterator &) = default;
|
||||
const_field_iterator &operator=(const_field_iterator &&) = default;
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
const_field_iterator &operator++()
|
||||
{
|
||||
if (m_row)
|
||||
{
|
||||
++m_col;
|
||||
m_current = field_ref(m_row, m_col, m_result_impl);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_field_iterator operator++(int)
|
||||
{
|
||||
const_field_iterator result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const const_field_iterator &rhs) const
|
||||
{
|
||||
return m_row == rhs.m_row and m_col == rhs.m_col;
|
||||
}
|
||||
|
||||
bool operator!=(const const_field_iterator &rhs) const
|
||||
{
|
||||
return m_row != rhs.m_row or m_col != rhs.m_col;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class row_ref;
|
||||
|
||||
const_field_iterator(const_row_handle row, uint16_t column, std::shared_ptr<result_impl> result_impl)
|
||||
: m_row(std::move(row))
|
||||
, m_col(column)
|
||||
, m_current(m_row, m_col, result_impl)
|
||||
, m_result_impl(result_impl)
|
||||
{
|
||||
}
|
||||
|
||||
const_row_handle m_row;
|
||||
uint16_t m_col;
|
||||
field_ref m_current;
|
||||
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
row_ref() = default;
|
||||
|
||||
/// Constructor
|
||||
row_ref(const_row_handle rh, std::shared_ptr<result_impl> result_impl)
|
||||
: m_row(std::move(rh))
|
||||
, m_result_impl(std::move(result_impl))
|
||||
{
|
||||
}
|
||||
|
||||
/// @cond
|
||||
row_ref(const row_ref &) = default;
|
||||
row_ref &operator=(const row_ref &) = default;
|
||||
/// @endcond
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] const_field_iterator begin() const noexcept { return { m_row, 0, m_result_impl }; } ///< Return begin field iterator
|
||||
[[nodiscard]] const_field_iterator cbegin() const noexcept { return { m_row, 0, m_result_impl }; } ///< Return cbegin field iterator
|
||||
[[nodiscard]] const_field_iterator end() const noexcept { return { m_row, static_cast<uint16_t>(size()), m_result_impl }; } ///< Return end field iterator
|
||||
[[nodiscard]] const_field_iterator cend() const noexcept { return { m_row, static_cast<uint16_t>(size()), m_result_impl }; } ///< Return cend field iterator
|
||||
|
||||
[[nodiscard]] field_ref front() const noexcept { return { m_row, 0, m_result_impl }; } ///< return reference to front field
|
||||
[[nodiscard]] field_ref back() const noexcept { return { m_row, static_cast<uint16_t>(size() - 1), m_result_impl }; } ///< return reference to back field
|
||||
|
||||
[[nodiscard]] size_t size() const noexcept; ///< return number of items in the row
|
||||
[[nodiscard]] bool empty() const noexcept { return size() == 0; } ///< return if the row contains no items at all
|
||||
|
||||
[[nodiscard]] field_ref operator[](uint16_t index) const noexcept { return { m_row, index, m_result_impl }; } ///< access field by index
|
||||
[[nodiscard]] field_ref operator[](std::string_view name) const; ///< access field by name
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
bool operator==(const row_ref &rhs) const { return m_row == rhs.m_row; }
|
||||
bool operator!=(const row_ref &rhs) const { return m_row != rhs.m_row; }
|
||||
|
||||
private:
|
||||
const_row_handle m_row;
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// The result set, containing the result of a query
|
||||
class result
|
||||
{
|
||||
public:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// iterator to the rows in the result set
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
friend class view;
|
||||
|
||||
/// @cond
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = const row_ref;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
// const_row_iterator() = default;
|
||||
|
||||
iterator(std::shared_ptr<result_impl> result_impl, category::const_iterator cat_iter)
|
||||
: m_iter(std::move(cat_iter))
|
||||
, m_current(*m_iter, result_impl)
|
||||
, m_result_impl(result_impl)
|
||||
{
|
||||
}
|
||||
|
||||
iterator(const iterator &) = default;
|
||||
iterator(iterator &&) = default;
|
||||
|
||||
// const_row_iterator &operator=(const const_row_iterator &) = default;
|
||||
// const_row_iterator &operator=(const_row_iterator &&) = default;
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
iterator &operator++()
|
||||
{
|
||||
++m_iter;
|
||||
m_current = { *m_iter, m_result_impl };
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator &rhs) const
|
||||
{
|
||||
return m_result_impl == rhs.m_result_impl and m_iter == rhs.m_iter;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &rhs) const
|
||||
{
|
||||
return m_result_impl != rhs.m_result_impl or m_iter != rhs.m_iter;
|
||||
}
|
||||
|
||||
private:
|
||||
category::const_iterator m_iter;
|
||||
row_ref m_current;
|
||||
std::shared_ptr<result_impl> m_result_impl;
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
result() = delete;
|
||||
result(result const &rhs) noexcept = default;
|
||||
result(result &&rhs) noexcept = default;
|
||||
result &operator=(result const &rhs) noexcept = default;
|
||||
result &operator=(result &&rhs) noexcept = default;
|
||||
|
||||
result(category &&data, const std::string &query = "");
|
||||
|
||||
~result() = default;
|
||||
/// @endcond
|
||||
|
||||
/// Return the row if and only if the result set contains exactly one row, throws otherwise
|
||||
[[nodiscard]] row_ref one_row() const
|
||||
{
|
||||
if (size() != 1)
|
||||
throw std::runtime_error("Expected one row");
|
||||
return front();
|
||||
}
|
||||
|
||||
/// Return the row if and only if the result set contains exactly one row,
|
||||
/// and this row also contains only one field, throws otherwise
|
||||
[[nodiscard]] field_ref one_field() const
|
||||
{
|
||||
expect_columns(1);
|
||||
|
||||
if (size() != 1)
|
||||
throw std::runtime_error("Expected one row");
|
||||
|
||||
return one_row().front();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
[[nodiscard]] iterator begin() const noexcept;
|
||||
[[nodiscard]] iterator cbegin() const noexcept;
|
||||
|
||||
[[nodiscard]] iterator end() const noexcept;
|
||||
[[nodiscard]] iterator cend() const noexcept;
|
||||
|
||||
[[nodiscard]] row_ref front() const;
|
||||
[[nodiscard]] row_ref back() const;
|
||||
|
||||
[[nodiscard]] size_t size() const noexcept;
|
||||
[[nodiscard]] bool empty() const noexcept { return size() == 0; }
|
||||
/// @endcond
|
||||
|
||||
/// Return the number of colums/fields in each row
|
||||
[[nodiscard]] size_t column_count() const;
|
||||
|
||||
/// Return the result set as a cif::category
|
||||
[[nodiscard]] category &get_category() const;
|
||||
|
||||
/// Test to see if the result set contains at least the number of fields/columns
|
||||
/// but only when not empty
|
||||
void expect_columns(size_t cols) const
|
||||
{
|
||||
if (auto actual = column_count(); size() > 0 and cols != actual)
|
||||
throw std::runtime_error("Unexpected number of columns");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Print out the result set, for debugging mostly
|
||||
friend std::ostream &operator<<(std::ostream &os, const result &r)
|
||||
{
|
||||
os << r.get_category();
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class transaction;
|
||||
friend class SelectStatement;
|
||||
|
||||
std::shared_ptr<result_impl> m_impl;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Helper class to allow access to the data as a stream
|
||||
template <typename... Ts>
|
||||
class cql_iterator_proxy : public cif::iterator_proxy<Ts...>
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
cql_iterator_proxy(result &&res)
|
||||
: cif::iterator_proxy<Ts...>(res.get_category())
|
||||
, m_result(std::forward<result>(res))
|
||||
{
|
||||
m_result.expect_columns(cif::iterator_proxy<Ts...>::N);
|
||||
}
|
||||
|
||||
private:
|
||||
result m_result;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Transaction class.
|
||||
/// At construction, this class starts a transaction on the connection
|
||||
/// and at exit an automatic rollback is done, unless commit was called.
|
||||
class transaction final
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
transaction(connection &conn);
|
||||
|
||||
/// @cond
|
||||
~transaction();
|
||||
|
||||
transaction(const transaction &) = delete;
|
||||
transaction &operator=(const transaction &) = delete;
|
||||
/// @endcond
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result
|
||||
result exec(std::string query);
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result.
|
||||
/// Updates @a tail with what remains after the first statement in @a query
|
||||
result exec(std::string query, std::string &tail);
|
||||
|
||||
/// Execute the sql in @a sql and return the result as a stream
|
||||
template <typename... Ts>
|
||||
cql_iterator_proxy<Ts...> stream(const std::string &sql)
|
||||
{
|
||||
return cql_iterator_proxy<Ts...>{ exec(sql) };
|
||||
}
|
||||
|
||||
/// Commit the result of the operations
|
||||
void commit();
|
||||
|
||||
/// Rollback the result of the operations, the underlying data is
|
||||
/// restored to the state before the construction of this transaction.
|
||||
void rollback();
|
||||
|
||||
private:
|
||||
connection &m_conn;
|
||||
bool m_transaction_active = false;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// This connection class creates a SQLite environment with the data in
|
||||
/// the provided datablock as tables.
|
||||
class connection final
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
connection(datablock &db);
|
||||
|
||||
/// Destructor
|
||||
~connection();
|
||||
|
||||
friend class transaction;
|
||||
|
||||
/// \brief Return true if the string @a sql contains a complete statement.
|
||||
[[nodiscard]] bool is_complete_statement(const std::string &sql) const;
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result
|
||||
result exec(std::string query);
|
||||
|
||||
/// \brief Execute the sql in @a query returning an iterable result.
|
||||
/// Updates @a tail with what remains after the first statement in @a query
|
||||
result exec(std::string query, std::string &tail);
|
||||
|
||||
/// \brief Return true if the underlying data was modified by any query.
|
||||
[[nodiscard]] bool is_modified() const;
|
||||
|
||||
private:
|
||||
struct connection_impl *m_impl;
|
||||
};
|
||||
|
||||
} // namespace cif::cql
|
||||
257
include/cif++/datablock.hpp
Normal file
257
include/cif++/datablock.hpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 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++/category.hpp"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/** \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
|
||||
{
|
||||
|
||||
class validator;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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 &&db) noexcept
|
||||
{
|
||||
swap_(*this, db);
|
||||
}
|
||||
|
||||
datablock &operator=(datablock db)
|
||||
{
|
||||
swap_(*this, db);
|
||||
return *this;
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/// Swap two datablocks
|
||||
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
|
||||
*/
|
||||
[[nodiscard]] 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 Attempt to load the dictionary @a dict
|
||||
*
|
||||
*/
|
||||
void load_dictionary(std::string_view dict);
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
[[nodiscard]] 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
|
||||
*/
|
||||
[[nodiscard]] 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
|
||||
*/
|
||||
[[nodiscard]] 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
|
||||
*/
|
||||
[[nodiscard]] const category *get(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* @brief Return true if this datablock contains a non-empty category
|
||||
*/
|
||||
[[nodiscard]] 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);
|
||||
|
||||
/**
|
||||
* @brief Get the preferred order of the categories when writing them
|
||||
*/
|
||||
[[nodiscard]] 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);
|
||||
return os;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Comparison operator to compare two datablock for equal content
|
||||
*/
|
||||
bool operator==(const datablock &rhs) const;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
const validator *m_validator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
@@ -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
|
||||
@@ -26,14 +26,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/Cif++.hpp"
|
||||
#include "cif++/validate.hpp"
|
||||
#include <iosfwd>
|
||||
|
||||
void WritePDBFile(std::ostream& pdbFile, cif::File& cifFile);
|
||||
/**
|
||||
* @file validate.hpp
|
||||
*
|
||||
* Functions to create and manipulate validator objects
|
||||
*/
|
||||
|
||||
/// \brief Just the HEADER, COMPND, SOURCE and AUTHOR lines
|
||||
void WritePDBHeaderLines(std::ostream& os, cif::File& cifFile);
|
||||
namespace cif
|
||||
{
|
||||
|
||||
std::string GetPDBHEADERLine(cif::File& cifFile, std::string::size_type truncate_at = 127);
|
||||
std::string GetPDBCOMPNDLine(cif::File& cifFile, std::string::size_type truncate_at = 127);
|
||||
std::string GetPDBSOURCELine(cif::File& cifFile, std::string::size_type truncate_at = 127);
|
||||
std::string GetPDBAUTHORLine(cif::File& cifFile, std::string::size_type truncate_at = 127);
|
||||
class validator;
|
||||
|
||||
/**
|
||||
* @brief Parse the contents of @a is and place content in validator @a v
|
||||
*/
|
||||
void parse_dictionary(validator &v, std::istream &is);
|
||||
|
||||
} // namespace cif
|
||||
228
include/cif++/file.hpp
Normal file
228
include/cif++/file.hpp
Normal file
@@ -0,0 +1,228 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 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++/datablock.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <istream>
|
||||
#include <list>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
/** \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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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, std::size_t length)
|
||||
{
|
||||
this->setg(text, text, text + length);
|
||||
}
|
||||
} buffer(const_cast<char *>(data), length);
|
||||
|
||||
std::istream is(&buffer);
|
||||
load(is);
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
file(const file &rhs) // NOLINT
|
||||
: std::list<datablock>(rhs)
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
[[nodiscard]] 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
|
||||
*/
|
||||
[[nodiscard]] bool validate_links() const;
|
||||
|
||||
/**
|
||||
* @brief Return true if a datablock with the name @a name is part of this file
|
||||
*/
|
||||
[[nodiscard]] 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
|
||||
*/
|
||||
[[nodiscard]] 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);
|
||||
|
||||
/** 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;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
126
include/cif++/format.hpp
Normal file
126
include/cif++/format.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 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 <ostream>
|
||||
#include <streambuf>
|
||||
|
||||
|
||||
/** \file format.hpp
|
||||
*
|
||||
* Now using std::format instead of a home grown rip off
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// A streambuf that fills out lines with spaces up until a specified width
|
||||
|
||||
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())
|
||||
, m_width(width)
|
||||
{
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
|
||||
~fill_out_streambuf() override
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
||||
int_type overflow(int_type ic = traits_type::eof()) override
|
||||
{
|
||||
char ch = traits_type::to_char_type(ic);
|
||||
|
||||
int_type result = ic;
|
||||
|
||||
if (ch == '\n')
|
||||
{
|
||||
for (int i = m_column_count; result != traits_type::eof() and i < m_width; ++i)
|
||||
result = m_upstream->sputc(' ');
|
||||
}
|
||||
|
||||
if (result != traits_type::eof())
|
||||
result = m_upstream->sputc(ch);
|
||||
|
||||
if (result != traits_type::eof())
|
||||
{
|
||||
if (ch == '\n')
|
||||
{
|
||||
m_column_count = 0;
|
||||
++m_line_count;
|
||||
}
|
||||
else
|
||||
++m_column_count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Return the upstream streambuf */
|
||||
[[nodiscard]] std::streambuf *get_upstream() const { return m_upstream; }
|
||||
|
||||
/** Return how many lines have been written */
|
||||
[[nodiscard]] int get_line_count() const { return m_line_count; }
|
||||
|
||||
private:
|
||||
std::ostream &m_os;
|
||||
std::streambuf *m_upstream;
|
||||
int m_width;
|
||||
int m_line_count = 0;
|
||||
int m_column_count = 0;
|
||||
};
|
||||
|
||||
} // namespace pdbx
|
||||
1116
include/cif++/gzio.hpp
Normal file
1116
include/cif++/gzio.hpp
Normal file
File diff suppressed because it is too large
Load Diff
924
include/cif++/item.hpp
Normal file
924
include/cif++/item.hpp
Normal file
@@ -0,0 +1,924 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 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++/text.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <version>
|
||||
|
||||
/** \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
|
||||
{
|
||||
|
||||
class category;
|
||||
class row;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The primitive types as known in libcifpp.
|
||||
*/
|
||||
enum class item_value_type
|
||||
{
|
||||
/// Integer, stored as int64_t
|
||||
INT,
|
||||
|
||||
/// Floating point, stored as double
|
||||
FLOAT,
|
||||
|
||||
/// Character string
|
||||
TEXT,
|
||||
|
||||
/// A value is not applicable, no data is stored, output is '.'
|
||||
INAPPLICABLE,
|
||||
|
||||
/// A values is now known or missing, no data is stored, output is '?'
|
||||
MISSING
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
template <typename T>
|
||||
concept IntegralType = (std::is_integral_v<std::remove_cvref_t<T>>);
|
||||
|
||||
template <typename T>
|
||||
concept FloatType = std::is_floating_point_v<std::remove_cvref_t<T>>;
|
||||
|
||||
template <typename T>
|
||||
concept StringType = (std::is_assignable_v<std::string, T> and not std::is_integral_v<T> and not std::is_floating_point_v<T>);
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_optional_v = false;
|
||||
template <typename T>
|
||||
inline constexpr bool is_optional_v<std::optional<T>> = true;
|
||||
/// @endcond
|
||||
|
||||
/// The data is stored in this item_value type. It contains one of
|
||||
/// the five types from @ref cif::item_value_type.
|
||||
/// Data is stored internally in the structure, except for strings
|
||||
/// larger than 7 characters. 99% of the character strings in a typical
|
||||
/// mmCIF file are 7 bytes or less, so this saves a lot of memory allocations.
|
||||
|
||||
class item_value
|
||||
{
|
||||
public:
|
||||
/// Construct an item_value containing the @ref INAPPLICABLE value.
|
||||
item_value() noexcept
|
||||
{
|
||||
m_data.m_type = item_value_type::INAPPLICABLE;
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the @ref MISSING value.
|
||||
item_value(std::nullptr_t)
|
||||
{
|
||||
m_data.m_type = item_value_type::MISSING;
|
||||
}
|
||||
|
||||
/// Create an item_value containing the type specified by @a type
|
||||
/// and a default value for this type.
|
||||
item_value(item_value_type type) noexcept
|
||||
: m_data(type)
|
||||
{
|
||||
}
|
||||
|
||||
/// Copy constructor
|
||||
item_value(const item_value &rhs)
|
||||
{
|
||||
m_data.m_type = rhs.m_data.m_type;
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT:
|
||||
m_data.m_value = rhs.m_data.m_value.m_integer;
|
||||
break;
|
||||
case FLOAT:
|
||||
m_data.m_len = rhs.m_data.m_len;
|
||||
m_data.m_value = rhs.m_data.m_value.m_float;
|
||||
break;
|
||||
case TEXT:
|
||||
m_data.m_len = rhs.m_data.m_len;
|
||||
m_data.m_value = rhs.m_data.sv();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the string @a s
|
||||
item_value(std::string_view s)
|
||||
{
|
||||
if (s == ".")
|
||||
m_data.m_type = item_value_type::INAPPLICABLE;
|
||||
else if (s == "?")
|
||||
m_data.m_type = item_value_type::MISSING;
|
||||
else
|
||||
{
|
||||
m_data.m_type = item_value_type::TEXT;
|
||||
m_data.m_len = s.length();
|
||||
m_data.m_value = s;
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the string @a s
|
||||
template <size_t N>
|
||||
item_value(const char(s)[N])
|
||||
: item_value(std::string_view{ s, N })
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the string @a s
|
||||
item_value(const char *s)
|
||||
: item_value(std::string_view{ s })
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the string @a s
|
||||
item_value(const std::string &s)
|
||||
: item_value(std::string_view{ s })
|
||||
{
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the integer @a v
|
||||
template <IntegralType T>
|
||||
item_value(T v)
|
||||
{
|
||||
m_data.m_type = item_value_type::INT;
|
||||
m_data.m_value = static_cast<int64_t>(v);
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the double @a v
|
||||
/// No precission is recorded, so output will be as
|
||||
/// long as required to contain value.
|
||||
template <FloatType T>
|
||||
item_value(T v)
|
||||
{
|
||||
m_data.m_type = item_value_type::FLOAT;
|
||||
m_data.m_value = static_cast<double>(v);
|
||||
m_data.m_len = 0;
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the double @a v
|
||||
/// If precision is not zero, output of this value to a file
|
||||
/// will use this precision. When parsing files, this precision
|
||||
/// is taken from the parsed string which will guarantee that
|
||||
/// the output of the data is the same as the input.
|
||||
template <FloatType T>
|
||||
item_value(T v, int precision)
|
||||
{
|
||||
m_data.m_type = item_value_type::FLOAT;
|
||||
m_data.m_value = static_cast<double>(v);
|
||||
m_data.m_len = precision;
|
||||
}
|
||||
|
||||
/// Construct an item_value containing either the value @a v
|
||||
/// or a MISSING type.
|
||||
template <typename T>
|
||||
item_value(std::optional<T> v)
|
||||
{
|
||||
if (v.has_value())
|
||||
{
|
||||
item_value iv{ *v };
|
||||
swap(*this, iv);
|
||||
}
|
||||
else
|
||||
m_data.m_type = item_value_type::MISSING;
|
||||
}
|
||||
|
||||
/// Construct an item_value containing the double @a v
|
||||
/// If precision is not zero, output of this value to a file
|
||||
/// will use this precision. When parsing files, this precision
|
||||
/// is taken from the parsed string which will guarantee that
|
||||
/// the output of the data is the same as the input.
|
||||
/// If v is emtpy, the proper MISSING value type will be used.
|
||||
template <FloatType T>
|
||||
item_value(std::optional<T> v, int precision)
|
||||
{
|
||||
if (v.has_value())
|
||||
{
|
||||
item_value iv{ *v };
|
||||
swap(*this, iv);
|
||||
}
|
||||
else
|
||||
m_data.m_type = item_value_type::MISSING;
|
||||
m_data.m_len = precision;
|
||||
}
|
||||
|
||||
/// Move constructor
|
||||
item_value(item_value &&rhs) noexcept
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// We're using modern move semantics
|
||||
item_value &operator=(item_value rhs) noexcept
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Test if contained value is of type @ref cif::item_value_type::INAPPLICABLE
|
||||
[[nodiscard]] constexpr bool is_inapplicable() const noexcept { return m_data.m_type == item_value_type::INAPPLICABLE; }
|
||||
|
||||
/// Test if contained value is of type @ref cif::item_value_type::MISSING
|
||||
[[nodiscard]] constexpr bool is_missing() const noexcept { return m_data.m_type == item_value_type::MISSING; }
|
||||
|
||||
/// Test if contained value is null, i.e. of type @ref cif::item_value_type::INAPPLICABLE or @ref cif::item_value_type::MISSING
|
||||
[[nodiscard]] constexpr bool is_null() const noexcept { return is_inapplicable() or is_missing(); }
|
||||
|
||||
/// Test if contained value is a string, i.e. of type @ref cif::item_value_type::TEXT
|
||||
[[nodiscard]] constexpr bool is_string() const noexcept { return m_data.m_type == item_value_type::TEXT; }
|
||||
|
||||
/// Test if contained value is of type @ref cif::item_value_type::INT
|
||||
[[nodiscard]] constexpr bool is_number_int() const noexcept { return m_data.m_type == item_value_type::INT; }
|
||||
|
||||
/// Test if contained value is of type @ref cif::item_value_type::FLOAT
|
||||
[[nodiscard]] constexpr bool is_number_float() const noexcept { return m_data.m_type == item_value_type::FLOAT; }
|
||||
|
||||
/// Test if contained value is a number, i.e. of type @ref cif::item_value_type::INT or @ref cif::item_value_type::FLOAT
|
||||
[[nodiscard]] constexpr bool is_number() const noexcept { return is_number_int() or is_number_float(); }
|
||||
|
||||
/// Return the type of the contained value
|
||||
[[nodiscard]] constexpr item_value_type type() const { return m_data.m_type; }
|
||||
|
||||
/// Return true if the contained value is considered to be 'empty'
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INAPPLICABLE:
|
||||
case MISSING:
|
||||
return true;
|
||||
|
||||
case TEXT:
|
||||
return m_data.sv().empty();
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Return the string representation of the contained value
|
||||
template <StringType T>
|
||||
[[nodiscard]] inline std::string get() const
|
||||
{
|
||||
return str();
|
||||
}
|
||||
|
||||
/// Return the integer representation of the contained value.
|
||||
/// Will throw if the value cannot be cast to an integer
|
||||
template <IntegralType T>
|
||||
[[nodiscard]] std::remove_cvref_t<T> get() const
|
||||
{
|
||||
static_assert(not std::is_same_v<std::remove_cvref_t<T>, bool>, "bool is no longer supported");
|
||||
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT:
|
||||
return m_data.m_value.m_integer;
|
||||
case FLOAT:
|
||||
return m_data.m_value.m_float;
|
||||
case TEXT:
|
||||
{
|
||||
auto sv = m_data.sv();
|
||||
auto sp = sv.data();
|
||||
if (*sp == '+')
|
||||
++sp;
|
||||
int64_t v;
|
||||
auto &&[ptr, ec] = from_chars(sp, sv.data() + sv.length(), v);
|
||||
if (ec != std::errc{})
|
||||
throw std::system_error(std::make_error_code(ec));
|
||||
if (ptr != sv.data() + sv.length())
|
||||
throw std::invalid_argument("String value does not contain only an integer");
|
||||
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
return not empty();
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the floating point representation of the contained value.
|
||||
/// Will throw if the value cannot be cast to the requested type
|
||||
template <FloatType T>
|
||||
[[nodiscard]] std::remove_cvref_t<T> get() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT:
|
||||
return m_data.m_value.m_integer;
|
||||
case FLOAT:
|
||||
return m_data.m_value.m_float;
|
||||
case TEXT:
|
||||
{
|
||||
auto sv = m_data.sv();
|
||||
auto sp = sv.data();
|
||||
if (*sp == '+')
|
||||
++sp;
|
||||
double v;
|
||||
auto &&[ptr, ec] = from_chars(sp, sv.data() + sv.length(), v);
|
||||
if (ec != std::errc{})
|
||||
throw std::system_error(std::make_error_code(ec));
|
||||
if (ptr != sv.data() + sv.length())
|
||||
throw std::invalid_argument("String value does not contain only a floating point number");
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
return not empty();
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the std::optional<> wrapped value.
|
||||
/// The return value will not have a value if the contained
|
||||
/// value is missing or inapplicable.
|
||||
/// Will throw if the value cannot be cast to the requested type
|
||||
template <typename T>
|
||||
requires is_optional_v<T>
|
||||
[[nodiscard]] auto get() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INAPPLICABLE:
|
||||
case MISSING:
|
||||
return T{};
|
||||
|
||||
default:
|
||||
{
|
||||
auto v = get<typename T::value_type>();
|
||||
return T{ v };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the string representation of the contained value.
|
||||
[[nodiscard]] std::string str() const;
|
||||
|
||||
/// Return a std::string_view to the contained value.
|
||||
/// This will of course throw when the type is not @ref cif::item_value_type::TEXT
|
||||
[[nodiscard]] const std::string_view sv() const
|
||||
{
|
||||
assert(m_data.m_type == cif::item_value_type::TEXT);
|
||||
return m_data.sv();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Swap two item_values
|
||||
friend void swap(item_value &a, item_value &b) noexcept
|
||||
{
|
||||
std::swap(a.m_data.m_type, b.m_data.m_type);
|
||||
std::swap(a.m_data.m_len, b.m_data.m_len);
|
||||
std::swap(a.m_data.m_value, b.m_data.m_value);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Three way comparison operator
|
||||
auto operator<=>(const item_value &rhs) const noexcept
|
||||
{
|
||||
std::partial_ordering result = std::partial_ordering::unordered;
|
||||
if (m_data.m_type == rhs.m_data.m_type)
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT: result = m_data.m_value.m_integer <=> rhs.m_data.m_value.m_integer;
|
||||
case FLOAT: result = m_data.m_value.m_float <=> rhs.m_data.m_value.m_float;
|
||||
case TEXT: result = m_data.sv() <=> rhs.m_data.sv();
|
||||
default: result = std::partial_ordering::equivalent;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = m_data.m_type <=> rhs.m_data.m_type;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Three way comparison operator is not always found TODO: find out why
|
||||
bool operator==(const item_value &rhs) const
|
||||
{
|
||||
if (m_data.m_type == rhs.m_data.m_type)
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
using enum item_value_type;
|
||||
|
||||
case INT: return m_data.m_value.m_integer == rhs.m_data.m_value.m_integer;
|
||||
case FLOAT: return m_data.m_value.m_float == rhs.m_data.m_value.m_float;
|
||||
case TEXT: return m_data.sv() == rhs.m_data.sv();
|
||||
case INAPPLICABLE:
|
||||
case MISSING: return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Compare the value of this item_value with b, optionally ignoring case
|
||||
[[nodiscard]] int compare(const item_value &b, bool ignore_case = false) const noexcept;
|
||||
|
||||
/// For debugging, print out a value
|
||||
friend std::ostream &operator<<(std::ostream &os, const item_value &v);
|
||||
|
||||
/// \brief Cast the value to an integer, will throw if not possible
|
||||
void cast_to_int();
|
||||
|
||||
/// \brief Cast the value to a float, will throw if not possible
|
||||
void cast_to_float();
|
||||
|
||||
/// \brief Cast the value to a string, may throw (when value is null)
|
||||
void cast_to_string();
|
||||
|
||||
/// @cond
|
||||
|
||||
private:
|
||||
union value
|
||||
{
|
||||
int64_t m_integer{};
|
||||
double m_float;
|
||||
char m_local_str[8];
|
||||
char *m_str;
|
||||
|
||||
value() = default;
|
||||
|
||||
value(int64_t v)
|
||||
: m_integer(v)
|
||||
{
|
||||
}
|
||||
|
||||
value(double v)
|
||||
: m_float(v)
|
||||
{
|
||||
}
|
||||
|
||||
value(std::string_view s)
|
||||
{
|
||||
if (s.length() >= sizeof(m_local_str))
|
||||
{
|
||||
m_str = new char[s.length() + 1];
|
||||
std::copy(s.data(), s.data() + s.length(), m_str);
|
||||
m_str[s.length()] = 0;
|
||||
}
|
||||
else
|
||||
std::memcpy(m_local_str, s.data(), s.length() + 1);
|
||||
}
|
||||
|
||||
value(item_value_type t)
|
||||
{
|
||||
m_integer = 0;
|
||||
}
|
||||
|
||||
void destroy(item_value_type t, size_t len)
|
||||
{
|
||||
if (t == item_value_type::TEXT and len >= sizeof(m_local_str))
|
||||
delete[] m_str;
|
||||
}
|
||||
};
|
||||
|
||||
struct data
|
||||
{
|
||||
item_value_type m_type = item_value_type::MISSING;
|
||||
uint32_t m_len{};
|
||||
value m_value{};
|
||||
|
||||
data(item_value_type t)
|
||||
: m_type(t)
|
||||
, m_value(t)
|
||||
{
|
||||
}
|
||||
|
||||
data() noexcept = default;
|
||||
data(data &&rhs) noexcept
|
||||
{
|
||||
std::swap(m_type, rhs.m_type);
|
||||
std::swap(m_len, rhs.m_len);
|
||||
std::swap(m_value, rhs.m_value);
|
||||
}
|
||||
|
||||
data(const data &) noexcept = delete;
|
||||
data &operator=(data &&) noexcept = delete;
|
||||
data &operator=(const data &) noexcept = delete;
|
||||
|
||||
~data()
|
||||
{
|
||||
m_value.destroy(m_type, m_len);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view sv() const noexcept
|
||||
{
|
||||
assert(m_type == item_value_type::TEXT);
|
||||
return m_type == item_value_type::TEXT ? std::string_view(m_len >= sizeof(m_value.m_local_str) ? m_value.m_str : m_value.m_local_str, m_len) : std::string_view{};
|
||||
}
|
||||
|
||||
[[nodiscard]] const char *c_str() const noexcept
|
||||
{
|
||||
assert(m_type == item_value_type::TEXT);
|
||||
return m_type == item_value_type::TEXT ? (m_len >= sizeof(m_value.m_local_str) ? m_value.m_str : m_value.m_local_str) : nullptr;
|
||||
}
|
||||
} m_data{};
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
static_assert(sizeof(item_value) == 16, "item_value should be 16 bytes");
|
||||
|
||||
|
||||
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 name)
|
||||
: m_name(std::move(name))
|
||||
, m_value(item_value_type::MISSING)
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructor using @a name and @a value
|
||||
item(std::string name, item_value value)
|
||||
: m_name(std::move(name))
|
||||
, m_value(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
item(const item &rhs) = default;
|
||||
|
||||
item(item &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
item &operator=(item rhs) noexcept
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/// Swap two items
|
||||
friend void swap(item &a, item &b) noexcept
|
||||
{
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_value, b.m_value);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &name() const { return m_name; } ///< Return the name of the item
|
||||
[[nodiscard]] const item_value &value() const & { return m_value; } ///< Return the value of the item
|
||||
item_value &value() & { return m_value; } ///< Return the value of the item
|
||||
|
||||
/// \brief replace the content of the stored value with \a v
|
||||
void value(item_value v) { m_value = std::move(v); }
|
||||
|
||||
/// \brief empty means either null or unknown
|
||||
[[nodiscard]] bool empty() const { return m_value.empty(); }
|
||||
|
||||
/// \brief returns true if the item contains '.' or '?'
|
||||
[[nodiscard]] bool is_null() const { return m_value.is_null(); }
|
||||
|
||||
/// \brief returns true if the item contains '?'
|
||||
[[nodiscard]] bool is_unknown() const { return m_value.is_missing(); }
|
||||
|
||||
// /// \brief the length of the value string
|
||||
// std::size_t length() const { return m_value.length(); }
|
||||
|
||||
/// \brief support for structured binding
|
||||
template <std::size_t N>
|
||||
decltype(auto) get() const
|
||||
{
|
||||
if constexpr (N == 0)
|
||||
return name();
|
||||
else if constexpr (N == 1)
|
||||
return value();
|
||||
}
|
||||
|
||||
// auto operator<=>(const item &rhs) const = default;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
item_value m_value;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief This is item_handle, it is used to access the data stored in
|
||||
/// item_value's in rows
|
||||
|
||||
struct item_handle
|
||||
{
|
||||
public:
|
||||
item_handle() = delete;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
item_handle &operator=(item_value value)
|
||||
{
|
||||
set(std::move(value), true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return the value of the item
|
||||
[[nodiscard]] item_value &value();
|
||||
|
||||
/// Return the const value of the item
|
||||
[[nodiscard]] const item_value &value() const;
|
||||
|
||||
/// Return if value in item is of type INAPPLICABLE
|
||||
[[nodiscard]] bool is_inapplicable() const noexcept
|
||||
{
|
||||
return not empty() and value().type() == item_value_type::INAPPLICABLE;
|
||||
}
|
||||
|
||||
/// Return if value in item is of type MISSING
|
||||
[[nodiscard]] bool is_missing() const noexcept
|
||||
{
|
||||
return empty() or value().type() == item_value_type::MISSING;
|
||||
}
|
||||
|
||||
/// Return if value in item is NULL (MISSING or INAPPLICABLE)
|
||||
[[nodiscard]] bool is_null() const noexcept
|
||||
{
|
||||
return empty() or is_inapplicable() or is_missing();
|
||||
}
|
||||
|
||||
/// Return if value in item is of type TEXT
|
||||
[[nodiscard]] bool is_string() const noexcept
|
||||
{
|
||||
return not empty() and value().type() == item_value_type::TEXT;
|
||||
}
|
||||
|
||||
/// Return if value in item is an integer
|
||||
[[nodiscard]] bool is_number_int() const noexcept
|
||||
{
|
||||
return not empty() and value().type() == item_value_type::INT;
|
||||
}
|
||||
|
||||
/// Return if value in item is a double
|
||||
[[nodiscard]] bool is_number_float() const noexcept
|
||||
{
|
||||
return not empty() and value().type() == item_value_type::FLOAT;
|
||||
}
|
||||
|
||||
/// Return if value in item is a number
|
||||
[[nodiscard]] bool is_number() const noexcept
|
||||
{
|
||||
return not empty() and (is_number_int() or is_number_float());
|
||||
}
|
||||
|
||||
/// Return type of the value
|
||||
[[nodiscard]] auto type() const
|
||||
{
|
||||
return empty() ? item_value_type::MISSING : value().type();
|
||||
}
|
||||
|
||||
/// Return the value casted to the type @tparam T
|
||||
template <typename T>
|
||||
[[nodiscard]] auto get() const
|
||||
{
|
||||
if (empty())
|
||||
return T{};
|
||||
else
|
||||
return value().template get<T>();
|
||||
}
|
||||
|
||||
/// Return the value casted to the type @tparam T, same as get
|
||||
template <typename T>
|
||||
[[deprecated("Use get<T> instead")]] [[nodiscard]] auto as() const
|
||||
{
|
||||
if (empty())
|
||||
return T{};
|
||||
else
|
||||
return value().template get<T>();
|
||||
}
|
||||
|
||||
/// Return the value as a std::string
|
||||
[[nodiscard]] auto str() const
|
||||
{
|
||||
return value().str();
|
||||
}
|
||||
|
||||
/// Return a std::string_view to the character data in the value, throws if the type is not TEXT
|
||||
[[nodiscard]] auto sv() const
|
||||
{
|
||||
return value().sv();
|
||||
}
|
||||
|
||||
/** Swap contents of @a a and @a b */
|
||||
friend void swap(item_handle a, item_handle b) noexcept;
|
||||
|
||||
/** Return the contents of this item as type @tparam T or, if not
|
||||
* set, use @a dv as the default value.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] auto value_or(const T &dv) const
|
||||
{
|
||||
return empty() ? dv : this->get<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
|
||||
*
|
||||
* @param value The value to compare with
|
||||
* @param icase Flag indicating if we should compare character case sensitive
|
||||
* @return -1, 0 or 1
|
||||
*/
|
||||
|
||||
[[nodiscard]] int compare(const item_value &value, bool icase = true) const noexcept
|
||||
{
|
||||
return this->value().compare(value, icase);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare the contents of this item with value of item @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
|
||||
*
|
||||
* @param value The value to compare with
|
||||
* @param icase Flag indicating if we should compare character case sensitive
|
||||
* @return -1, 0 or 1
|
||||
*/
|
||||
|
||||
[[nodiscard]] int compare(const item_handle &value, bool icase = true) const noexcept
|
||||
{
|
||||
if (empty() and value.empty())
|
||||
return 0;
|
||||
else if (empty())
|
||||
return -1;
|
||||
else if (value.empty())
|
||||
return 1;
|
||||
else
|
||||
return compare(value.value(), icase);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare the value contained with the value @a value and
|
||||
* return true if both are equal.
|
||||
*/
|
||||
[[nodiscard]] bool operator==(const item_value &value) const noexcept
|
||||
{
|
||||
// TODO: icase or not icase?
|
||||
return this->value().compare(value) == 0;
|
||||
}
|
||||
|
||||
// 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>
|
||||
[[nodiscard]] bool operator!=(const T &value) const noexcept
|
||||
{
|
||||
return not operator==(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the content string is empty or
|
||||
* only contains '.' meaning null or '?' meaning unknown
|
||||
* in a mmCIF context
|
||||
*/
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
/** Return a std::string_view for the contents */
|
||||
[[nodiscard]] std::string_view text_() const;
|
||||
|
||||
/**
|
||||
* @brief Construct a new item handle object
|
||||
*
|
||||
* @param cat Reference to category containing row
|
||||
* @param row Reference to the row
|
||||
* @param item_ix Item index
|
||||
*/
|
||||
item_handle(category &cat, row &row, uint16_t item_ix)
|
||||
: m_category(cat)
|
||||
, m_row(row)
|
||||
, m_item_ix(item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
item_handle(const category &cat, const row &r, uint16_t item_ix)
|
||||
: m_category(const_cast<category &>(cat))
|
||||
, m_row(const_cast<row &>(r))
|
||||
, m_item_ix(item_ix)
|
||||
, m_is_const(true)
|
||||
{
|
||||
}
|
||||
|
||||
item_handle(const item_handle &) = delete;
|
||||
item_handle &operator=(const item_handle &) = delete;
|
||||
|
||||
/// Print out the item, for debugging
|
||||
friend std::ostream &operator<<(std::ostream &os, const item_handle &h)
|
||||
{
|
||||
if (h.empty())
|
||||
os << "NULL";
|
||||
else
|
||||
os << h.value();
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
category &m_category;
|
||||
row &m_row;
|
||||
uint16_t m_item_ix;
|
||||
bool m_is_const = false;
|
||||
|
||||
friend class parser;
|
||||
|
||||
void set(item_value value, bool updateLinked);
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
/** @cond */
|
||||
|
||||
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>
|
||||
{
|
||||
using type = decltype(std::declval<::cif::item>().value());
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace std
|
||||
830
include/cif++/iterator.hpp
Normal file
830
include/cif++/iterator.hpp
Normal file
@@ -0,0 +1,830 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 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++/condition.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
|
||||
/**
|
||||
* @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
|
||||
{
|
||||
|
||||
class category;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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 <bool Const, typename... Ts>
|
||||
class iterator_impl_base
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
friend class category;
|
||||
/** @endcond */
|
||||
|
||||
/** variable that contains the number of elements in the tuple */
|
||||
static constexpr std::size_t N = sizeof...(Ts);
|
||||
|
||||
/** @cond */
|
||||
using tuple_type = std::tuple<Ts...>;
|
||||
|
||||
using row_handle_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = std::conditional_t<Const, const tuple_type, tuple_type>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl_base() = default;
|
||||
|
||||
iterator_impl_base(const iterator_impl_base &rhs) = default;
|
||||
iterator_impl_base(iterator_impl_base &&rhs) = default;
|
||||
|
||||
template <bool C, typename... T2s>
|
||||
iterator_impl_base(const iterator_impl_base<C, T2s...> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(iterator_impl_base<C, Ts...> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, N> &cix)
|
||||
: m_current(rhs.m_current)
|
||||
, m_item_ix(cix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
iterator_impl_base &operator=(iterator_impl_base 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;
|
||||
}
|
||||
|
||||
virtual ~iterator_impl_base() = default;
|
||||
|
||||
auto operator*()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
operator const_row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle_type()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl_base &operator++()
|
||||
{
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator_impl_base operator++(int)
|
||||
{
|
||||
iterator_impl_base result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator_impl_base &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl_base &rhs) const { return m_current != rhs.m_current; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
{
|
||||
return m_current == rhs.m_current;
|
||||
}
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
{
|
||||
return m_current != rhs.m_current;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
template <std::size_t... Is>
|
||||
[[nodiscard]] tuple_type get(std::index_sequence<Is...>) const
|
||||
{
|
||||
return m_current ? tuple_type{ m_current[m_item_ix[Is]].template get<Ts>()... } : tuple_type{};
|
||||
}
|
||||
|
||||
row_handle_type m_current;
|
||||
tuple_type m_value;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implementation of an iterator that returns
|
||||
* only row_handles
|
||||
*
|
||||
* @tparam Category The category for this iterator
|
||||
*/
|
||||
template <bool Const>
|
||||
class iterator_impl_base<Const>
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
friend class category;
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using row_type = std::conditional_t<Const, const row, row>;
|
||||
using row_handle_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
using value_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl_base() = default;
|
||||
|
||||
iterator_impl_base(const iterator_impl_base &rhs) = default;
|
||||
iterator_impl_base(iterator_impl_base &&rhs) = default;
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl_base(const category_type &cat, const row_type *current)
|
||||
: m_current(const_cast<category &>(cat), const_cast<row_type &>(*current))
|
||||
{
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, 0> &)
|
||||
: m_current(rhs.m_current)
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl_base &operator=(iterator_impl_base i)
|
||||
{
|
||||
std::swap(m_current, i.m_current);
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~iterator_impl_base() = default;
|
||||
|
||||
auto operator*()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
{
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
operator const_row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle_type()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
[[nodiscard]] int64_t row_id() const
|
||||
{
|
||||
return reinterpret_cast<int64_t>(m_current.m_row);
|
||||
}
|
||||
|
||||
iterator_impl_base &operator++()
|
||||
{
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator_impl_base operator++(int)
|
||||
{
|
||||
iterator_impl_base result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator_impl_base &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl_base &rhs) const { return m_current != rhs.m_current; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
{
|
||||
return m_current == rhs.m_current;
|
||||
}
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
{
|
||||
return m_current != rhs.m_current;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
row_handle_type 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 <bool Const, typename T>
|
||||
class iterator_impl_base<Const, T>
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
friend class category;
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using row_handle_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
|
||||
iterator_impl_base() = default;
|
||||
|
||||
iterator_impl_base(const iterator_impl_base &rhs) = default;
|
||||
iterator_impl_base(iterator_impl_base &&rhs) = default;
|
||||
|
||||
template <bool C, typename T2>
|
||||
iterator_impl_base(const iterator_impl_base<C, T2> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(iterator_impl_base<C, T> &rhs)
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, 1> &cix)
|
||||
: m_current(rhs.m_current)
|
||||
, m_item_ix(cix[0])
|
||||
{
|
||||
m_value = get();
|
||||
}
|
||||
|
||||
iterator_impl_base &operator=(iterator_impl_base 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;
|
||||
}
|
||||
|
||||
virtual ~iterator_impl_base() = default;
|
||||
|
||||
auto operator*()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
{
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
operator const_row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator row_handle_type()
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
|
||||
iterator_impl_base &operator++()
|
||||
{
|
||||
if (m_current)
|
||||
m_current.m_row = m_current.m_row->m_next;
|
||||
|
||||
m_value = get();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator_impl_base operator++(int)
|
||||
{
|
||||
iterator_impl_base result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const iterator_impl_base &rhs) const { return m_current == rhs.m_current; }
|
||||
bool operator!=(const iterator_impl_base &rhs) const { return m_current != rhs.m_current; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
{
|
||||
return m_current == rhs.m_current;
|
||||
}
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const
|
||||
{
|
||||
return m_current != rhs.m_current;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
[[nodiscard]] value_type get() const
|
||||
{
|
||||
return m_current ? m_current[m_item_ix].template get<value_type>() : value_type{};
|
||||
}
|
||||
|
||||
row_handle_type m_current;
|
||||
value_type m_value;
|
||||
uint16_t m_item_ix;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A non-const version of iterator_impl
|
||||
template<typename ... Ts>
|
||||
using iterator_impl = iterator_impl_base<false, Ts...>;
|
||||
|
||||
/// A const version of iterator_impl
|
||||
template<typename ... Ts>
|
||||
using const_iterator_impl = iterator_impl_base<true, Ts...>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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 <bool Const, typename... Ts>
|
||||
class iterator_proxy_base
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
|
||||
using iterator = iterator_impl_base<Const, Ts...>;
|
||||
using row_iterator = iterator_impl_base<Const>;
|
||||
|
||||
iterator_proxy_base(category_type &cat, row_iterator pos, char const *const items[N]);
|
||||
iterator_proxy_base(category_type &cat, row_iterator pos, std::initializer_list<char const *> items); // NOLINT(modernize-pass-by-value)
|
||||
|
||||
iterator_proxy_base(iterator_proxy_base &&p);
|
||||
iterator_proxy_base &operator=(iterator_proxy_base &&p);
|
||||
|
||||
iterator_proxy_base(const iterator_proxy_base &) = delete;
|
||||
iterator_proxy_base &operator=(const iterator_proxy_base &) = delete;
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] iterator begin() const { return iterator(m_begin, m_item_ix); } ///< Return the iterator pointing to the first row
|
||||
[[nodiscard]] iterator end() const { return iterator(m_end, m_item_ix); } ///< Return the iterator pointing past the last row
|
||||
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] 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())); }
|
||||
|
||||
[[nodiscard]] category_type &get_category() const { return *m_category; } ///< Return the category the iterator belong to
|
||||
|
||||
/** swap */
|
||||
void swap(iterator_proxy_base &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_item_ix, rhs.m_item_ix);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// @cond
|
||||
iterator_proxy_base(category_type &cat);
|
||||
/// @endcond
|
||||
|
||||
private:
|
||||
category_type *m_category;
|
||||
row_iterator m_begin, m_end;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A non-const version of iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using iterator_proxy = iterator_proxy_base<false, Ts...>;
|
||||
|
||||
/// A const version of iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using const_iterator_proxy = iterator_proxy_base<true, Ts...>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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 category_type The category the iterators belong to
|
||||
* @tparam Ts The types to which the iterators can be dereferenced
|
||||
*/
|
||||
template <bool Const, typename... Ts>
|
||||
class conditional_iterator_proxy_base
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
static constexpr const std::size_t N = sizeof...(Ts);
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using base_iterator = iterator_impl_base<Const, Ts...>;
|
||||
using value_type = typename base_iterator::value_type;
|
||||
using row_iterator = iterator_impl_base<Const>;
|
||||
|
||||
class conditional_iterator_impl
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = conditional_iterator_proxy_base::value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type;
|
||||
|
||||
conditional_iterator_impl() = default;
|
||||
conditional_iterator_impl(category_type &cat, row_iterator pos, const condition &cond, const std::array<uint16_t, N> &cix);
|
||||
conditional_iterator_impl(const conditional_iterator_impl &i) = default;
|
||||
conditional_iterator_impl &operator=(const conditional_iterator_impl &i) = default;
|
||||
|
||||
virtual ~conditional_iterator_impl() = default;
|
||||
|
||||
auto operator*()
|
||||
{
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
auto operator*() const
|
||||
{
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
auto operator->()
|
||||
{
|
||||
m_current = *m_begin;
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
auto operator->() const
|
||||
{
|
||||
m_current = *m_begin;
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
conditional_iterator_impl &operator++()
|
||||
{
|
||||
while (m_begin != m_end)
|
||||
{
|
||||
if (++m_begin == m_end)
|
||||
break;
|
||||
|
||||
if (m_condition->operator()(m_begin))
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
conditional_iterator_impl operator++(int)
|
||||
{
|
||||
conditional_iterator_impl result(*this);
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
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 <bool C, typename... ITs>
|
||||
bool operator==(const iterator_impl_base<C, ITs...> &rhs) const { return m_begin == rhs; }
|
||||
|
||||
template <bool C, typename... ITs>
|
||||
bool operator!=(const iterator_impl_base<C, ITs...> &rhs) const { return m_begin != rhs; }
|
||||
|
||||
private:
|
||||
category_type *m_cat = nullptr;
|
||||
base_iterator m_begin, m_end;
|
||||
std::remove_cv_t<value_type> m_current;
|
||||
const condition *m_condition;
|
||||
};
|
||||
|
||||
using iterator = conditional_iterator_impl;
|
||||
using reference = typename iterator::reference;
|
||||
|
||||
template <typename... Ns>
|
||||
conditional_iterator_proxy_base(category_type &cat, row_iterator pos, condition &&cond, Ns... names); // NOLINT(modernize-pass-by-value)
|
||||
|
||||
conditional_iterator_proxy_base(conditional_iterator_proxy_base &&p)
|
||||
{
|
||||
swap(*this, p);
|
||||
}
|
||||
|
||||
conditional_iterator_proxy_base &operator=(conditional_iterator_proxy_base &&p)
|
||||
{
|
||||
swap(*this, p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
conditional_iterator_proxy_base(const conditional_iterator_proxy_base &) = delete;
|
||||
conditional_iterator_proxy_base &operator=(const conditional_iterator_proxy_base &) = delete;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] iterator begin() const; ///< Return the iterator pointing to the first row
|
||||
[[nodiscard]] iterator end() const; ///< Return the iterator pointing past the last row
|
||||
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] std::size_t size() const { return std::distance(begin(), end()); } ///< Return size of the range
|
||||
|
||||
auto front() { return *begin(); } ///< Return reference to the first row
|
||||
// row_handle back() { return *begin(); }
|
||||
|
||||
[[nodiscard]] category_type &get_category() const { return *m_cat; } ///< Category the iterators belong to
|
||||
|
||||
/** swap */
|
||||
template <bool C2, typename ... T2s>
|
||||
friend void swap(conditional_iterator_proxy_base<C2, T2s...> &lhs, conditional_iterator_proxy_base<C2, T2s...> &rhs);
|
||||
|
||||
private:
|
||||
category_type *m_cat;
|
||||
condition m_condition;
|
||||
row_iterator mCBegin, mCEnd;
|
||||
std::array<uint16_t, N> mCix;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A non-const version of conditional_iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using conditional_iterator_proxy = conditional_iterator_proxy_base<false, Ts...>;
|
||||
|
||||
/// A const version of conditional_iterator_proxy_base
|
||||
template <typename... Ts>
|
||||
using const_conditional_iterator_proxy = conditional_iterator_proxy_base<true, Ts...>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** @cond */
|
||||
template <bool Const, typename... Ts>
|
||||
iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &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_item_ix[i] = m_category->get_item_ix(items[i]);
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &cat, row_iterator pos, std::initializer_list<char const *> items)
|
||||
: m_category(&cat)
|
||||
, m_begin(pos)
|
||||
, m_end(cat.end())
|
||||
{
|
||||
// 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 item : items)
|
||||
m_item_ix[i++] = m_category->get_item_ix(item);
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
iterator_proxy_base<Const, Ts...>::iterator_proxy_base(category_type &cat)
|
||||
: m_category(&cat)
|
||||
, m_begin(cat.begin())
|
||||
, m_end(cat.end())
|
||||
{
|
||||
std::iota(m_item_ix.begin(), m_item_ix.end(), 0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
conditional_iterator_proxy_base<Const, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
|
||||
category_type &cat, row_iterator pos, const condition &cond, const std::array<uint16_t, N> &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;
|
||||
else
|
||||
m_current = *m_begin;
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
template <typename... Ns>
|
||||
conditional_iterator_proxy_base<Const, Ts...>::conditional_iterator_proxy_base(category_type &cat, row_iterator pos, condition &&cond, Ns... names)
|
||||
: m_cat(&cat)
|
||||
, m_condition(std::move(cond))
|
||||
, mCBegin(pos)
|
||||
, mCEnd(cat.end())
|
||||
{
|
||||
static_assert(sizeof...(Ts) == sizeof...(Ns), "Number of item names should be equal to number of requested value types");
|
||||
|
||||
if (m_condition and m_condition.prepare(cat))
|
||||
{
|
||||
while (mCBegin != mCEnd and not m_condition(*mCBegin))
|
||||
++mCBegin;
|
||||
}
|
||||
else
|
||||
mCBegin = mCEnd;
|
||||
|
||||
uint16_t i = 0;
|
||||
((mCix[i++] = m_cat->get_item_ix(names)), ...);
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
auto conditional_iterator_proxy_base<Const, Ts...>::begin() const -> iterator
|
||||
{
|
||||
return iterator{ *m_cat, mCBegin, m_condition, mCix };
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
auto conditional_iterator_proxy_base<Const, Ts...>::end() const -> iterator
|
||||
{
|
||||
return iterator{ *m_cat, mCEnd, m_condition, mCix };
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
bool conditional_iterator_proxy_base<Const, Ts...>::empty() const
|
||||
{
|
||||
return mCBegin == mCEnd;
|
||||
}
|
||||
|
||||
template <bool Const, typename... Ts>
|
||||
void swap(conditional_iterator_proxy_base<Const, Ts...> &lhs, conditional_iterator_proxy_base<Const, Ts...> &rhs)
|
||||
{
|
||||
std::swap(lhs.m_cat, rhs.m_cat);
|
||||
std::swap(lhs.m_condition, rhs.m_condition);
|
||||
std::swap(lhs.mCBegin, rhs.mCBegin);
|
||||
std::swap(lhs.mCEnd, rhs.mCEnd);
|
||||
std::swap(lhs.mCix, rhs.mCix);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// template <bool Const, typename... Ts>
|
||||
|
||||
|
||||
/** @endcond */
|
||||
|
||||
} // namespace cif
|
||||
776
include/cif++/matrix.hpp
Normal file
776
include/cif++/matrix.hpp
Normal file
@@ -0,0 +1,776 @@
|
||||
/*-
|
||||
* 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 <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <ostream>
|
||||
#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 // NOLINT(bugprone-crtp-constructor-accessibility)
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return static_cast<const M &>(*this).dim_m(); } ///< Return the size (dimension) in direction m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return static_cast<const M &>(*this).dim_n(); } ///< Return the size (dimension) in direction n
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const { return dim_m() == 0 or dim_n() == 0; } ///< Convenient way to test for empty matrices
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
return static_cast<M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<const M &>(*this).operator()(i, j);
|
||||
}
|
||||
|
||||
/** Swap the contents of rows @a r1 and @a r2 */
|
||||
void swap_row(std::size_t r1, std::size_t r2)
|
||||
{
|
||||
for (std::size_t c = 0; c < dim_m(); ++c)
|
||||
{
|
||||
auto v = operator()(r1, c);
|
||||
operator()(r1, c) = operator()(r2, c);
|
||||
operator()(r2, c) = v;
|
||||
}
|
||||
}
|
||||
|
||||
/** Swap the contents of columns @a c1 and @a c2 */
|
||||
void swap_col(std::size_t c1, std::size_t c2)
|
||||
{
|
||||
for (std::size_t r = 0; r < dim_n(); ++r)
|
||||
{
|
||||
auto &a = operator()(r, c1);
|
||||
auto &b = operator()(r, c2);
|
||||
std::swap(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** write the matrix @a m to std::ostream @a os */
|
||||
friend std::ostream &operator<<(std::ostream &os, const matrix_expression &m)
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (std::size_t i = 0; i < m.dim_m(); ++i)
|
||||
{
|
||||
os << '[';
|
||||
|
||||
for (std::size_t j = 0; j < m.dim_n(); ++j)
|
||||
{
|
||||
os << m(i, j);
|
||||
if (j + 1 < m.dim_n())
|
||||
os << ", ";
|
||||
}
|
||||
|
||||
if (i + 1 < m.dim_m())
|
||||
os << ", ";
|
||||
|
||||
os << ']';
|
||||
}
|
||||
|
||||
os << ']';
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/// compare two matrices
|
||||
template <typename M2>
|
||||
constexpr bool operator==(const matrix_expression<M2> &m) const
|
||||
{
|
||||
bool same = false;
|
||||
if (dim_m() == m.dim_m() and dim_n() == m.dim_n())
|
||||
{
|
||||
same = true;
|
||||
for (std::size_t i = 0; same and i < m.dim_m(); ++i)
|
||||
{
|
||||
for (std::size_t j = 0; same and j < m.dim_n(); ++j)
|
||||
same = operator()(i, j) == m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return same;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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 (std::size_t i = 0; i < m_m; ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < m_n; ++j)
|
||||
operator()(i, j) = m(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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 */
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] 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];
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < m_m);
|
||||
assert(j < m_n);
|
||||
return m_data[i * m_n + j];
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t m_m = 0, m_n = 0;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// special case, 3x3 matrix
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/** 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 (std::size_t i = 0; i < M; ++i)
|
||||
{
|
||||
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 */
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return N; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] 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];
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
assert(i < M);
|
||||
assert(j < N);
|
||||
return m_data[i * N + j];
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
|
||||
/** 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 */
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] 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];
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
assert(j < m_n);
|
||||
return m_data[(j * (j + 1)) / 2 + i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t m_n;
|
||||
std::vector<value_type> m_data;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return M; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return M; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] 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];
|
||||
}
|
||||
|
||||
/** Return a reference to element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type &operator()(std::size_t i, std::size_t j)
|
||||
{
|
||||
if (i > j)
|
||||
std::swap(i, j);
|
||||
assert(j < M);
|
||||
return m_data[(j * (j + 1)) / 2 + i];
|
||||
}
|
||||
|
||||
private:
|
||||
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>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A transposed matrix view
|
||||
|
||||
template <typename M>
|
||||
class transposed_matrix : public cif::matrix_expression<transposed_matrix<M>>
|
||||
{
|
||||
public:
|
||||
transposed_matrix(const M &m)
|
||||
: m_m(m)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_n(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_m(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(j, i);
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/** constructor taking a dimension @a n */
|
||||
identity_matrix(std::size_t n)
|
||||
: m_n(n)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_n; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_n; } ///< Return dimension n
|
||||
|
||||
/** Return the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr value_type operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return static_cast<value_type>(i == j ? 1 : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
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)
|
||||
{
|
||||
assert(m_m1.dim_m() == m_m2.dim_m());
|
||||
assert(m_m1.dim_n() == m_m2.dim_n());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m1(i, j) - m_m2(i, j);
|
||||
}
|
||||
|
||||
private:
|
||||
const M1 &m_m1;
|
||||
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)
|
||||
{
|
||||
assert(m1.dim_n() == m2.dim_m());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m1.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m1.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
using value_type = decltype(m_m1(0, 0));
|
||||
|
||||
value_type result = {};
|
||||
|
||||
for (std::size_t k = 0; k < m_m1.dim_n(); ++k)
|
||||
result += m_m1(i, k) * m_m2(k, j);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
const M1 &m_m1;
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(i, j) * m_v;
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
value_type m_v;
|
||||
};
|
||||
|
||||
/** First implementation of operator*, enabled if the second parameter is a scalar */
|
||||
template <typename M1, typename T>
|
||||
auto operator*(const matrix_expression<M1> &m, T v)
|
||||
requires(std::is_floating_point_v<T>)
|
||||
{
|
||||
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>
|
||||
auto operator*(const matrix_expression<M1> &m1, const matrix_expression<M2> &m2)
|
||||
requires(not std::is_floating_point_v<M2>)
|
||||
{
|
||||
return matrix_matrix_multiplication(m1, m2);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// A sub-view on a matrix
|
||||
template <typename M2>
|
||||
class sub_matrix : public matrix_expression<sub_matrix<M2>>
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
sub_matrix(const M2 &m, int i, int j)
|
||||
: m_m(m)
|
||||
, m_i(i)
|
||||
, m_j(j)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_m() - 1; } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_n() - 1; } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
return m_m(
|
||||
i >= m_i ? i + 1 : i,
|
||||
j >= m_j ? j + 1 : j);
|
||||
}
|
||||
|
||||
private:
|
||||
const M2 &m_m;
|
||||
std::size_t m_i, m_j;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Generic routine to calculate the determinant of a matrix
|
||||
*
|
||||
* @note This is currently only implemented for fixed matrices of size 3x3
|
||||
*/
|
||||
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)
|
||||
{
|
||||
return (m(0, 0) * ((m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1))) +
|
||||
m(0, 1) * ((m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2))) +
|
||||
m(0, 2) * ((m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))));
|
||||
}
|
||||
|
||||
/** Implementation of the determinant function for fixed size matrices of size 4x4 */
|
||||
template <typename F = float>
|
||||
F determinant(const matrix4x4<F> &m)
|
||||
{
|
||||
return m(0, 0) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 0))) -
|
||||
m(0, 1) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 1))) +
|
||||
m(0, 2) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 2))) -
|
||||
m(0, 3) * determinant(matrix3x3<F>(sub_matrix<decltype(m)>(m, 0, 3)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** Generic routine to calculate the inverse of a matrix
|
||||
*
|
||||
* @note This is currently only implemented for fixed matrices of size 3x3
|
||||
*/
|
||||
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)
|
||||
{
|
||||
F det = determinant(m);
|
||||
|
||||
matrix3x3<F> result;
|
||||
|
||||
result(0, 0) = (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) / det;
|
||||
result(1, 0) = (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) / det;
|
||||
result(2, 0) = (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)) / det;
|
||||
result(0, 1) = (m(2, 1) * m(0, 2) - m(2, 2) * m(0, 1)) / det;
|
||||
result(1, 1) = (m(2, 2) * m(0, 0) - m(2, 0) * m(0, 2)) / det;
|
||||
result(2, 1) = (m(2, 0) * m(0, 1) - m(2, 1) * m(0, 0)) / det;
|
||||
result(0, 2) = (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) / det;
|
||||
result(1, 2) = (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) / det;
|
||||
result(2, 2) = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) / det;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t dim_m() const { return m_m.dim_m(); } ///< Return dimension m
|
||||
[[nodiscard]] constexpr std::size_t dim_n() const { return m_m.dim_n(); } ///< Return dimension n
|
||||
|
||||
/** Access to the value of element [ @a i, @a j ] */
|
||||
[[nodiscard]] constexpr auto operator()(std::size_t i, std::size_t j) const
|
||||
{
|
||||
const std::size_t ixs[4][3] = {
|
||||
{ 1, 2, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 1, 2 }
|
||||
};
|
||||
|
||||
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]) +
|
||||
m_m(ix[0], iy[1]) * m_m(ix[1], iy[2]) * m_m(ix[2], iy[0]) +
|
||||
m_m(ix[0], iy[2]) * m_m(ix[1], iy[0]) * m_m(ix[2], iy[1]) -
|
||||
m_m(ix[0], iy[2]) * m_m(ix[1], iy[1]) * m_m(ix[2], iy[0]) -
|
||||
m_m(ix[0], iy[1]) * m_m(ix[1], iy[0]) * m_m(ix[2], iy[2]) -
|
||||
m_m(ix[0], iy[0]) * m_m(ix[1], iy[2]) * m_m(ix[2], iy[1]);
|
||||
|
||||
return (i + j) % 2 == 1 ? -result : result;
|
||||
}
|
||||
|
||||
private:
|
||||
const M &m_m;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
1249
include/cif++/model.hpp
Normal file
1249
include/cif++/model.hpp
Normal file
File diff suppressed because it is too large
Load Diff
479
include/cif++/parser.hpp
Normal file
479
include/cif++/parser.hpp
Normal file
@@ -0,0 +1,479 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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++/category.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @file parser.hpp
|
||||
*
|
||||
* This file contains the declaration of an mmCIF parser
|
||||
*/
|
||||
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class category;
|
||||
class datablock;
|
||||
class file;
|
||||
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)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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:
|
||||
/** @cond */
|
||||
struct iless_op
|
||||
{
|
||||
bool operator()(std::string_view a, std::string_view b) const
|
||||
{
|
||||
return icompare(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
using datablock_index = std::map<std::string, std::size_t, iless_op>;
|
||||
|
||||
virtual ~sac_parser() = default;
|
||||
/** @endcond */
|
||||
|
||||
/// \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
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
10,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15, // 3
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15, // 4
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
14,
|
||||
15,
|
||||
14,
|
||||
15,
|
||||
14, // 5
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15, // 6
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
0, // 7
|
||||
};
|
||||
|
||||
enum class CIFToken
|
||||
{
|
||||
UNKNOWN,
|
||||
|
||||
END_OF_FILE,
|
||||
|
||||
DATA,
|
||||
LOOP,
|
||||
GLOBAL,
|
||||
SAVE_,
|
||||
SAVE_NAME,
|
||||
STOP,
|
||||
ITEM_NAME,
|
||||
|
||||
VALUE_INAPPLICABLE,
|
||||
VALUE_UNKNOWN,
|
||||
VALUE_NUMERIC_INTEGER,
|
||||
VALUE_NUMERIC_FLOAT,
|
||||
VALUE_CHARSTRING,
|
||||
VALUE_TEXTFIELD
|
||||
};
|
||||
|
||||
static constexpr const char *get_token_name(CIFToken token)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
using enum CIFToken;
|
||||
|
||||
case UNKNOWN: return "Unknown";
|
||||
case END_OF_FILE: return "Eof";
|
||||
case DATA: return "DATA";
|
||||
case LOOP: return "LOOP";
|
||||
case GLOBAL: return "GLOBAL";
|
||||
case SAVE_: return "SAVE";
|
||||
case SAVE_NAME: return "SAVE+name";
|
||||
case STOP: return "STOP";
|
||||
case ITEM_NAME:
|
||||
return "Tag";
|
||||
// case VALUE: return "Value";
|
||||
|
||||
case VALUE_INAPPLICABLE: return "Inapplicable value";
|
||||
case VALUE_UNKNOWN: return "'Unknown' value (=null)";
|
||||
case VALUE_NUMERIC_INTEGER: return "Integer value";
|
||||
case VALUE_NUMERIC_FLOAT: return "Float value";
|
||||
case VALUE_CHARSTRING: return "Charstring value";
|
||||
case VALUE_TEXTFIELD: return "Textfield value";
|
||||
|
||||
default: return "Invalid token parameter";
|
||||
}
|
||||
}
|
||||
|
||||
// get_next_char takes the next character from the istream.
|
||||
// This function also does carriage/linefeed translation.
|
||||
int get_next_char();
|
||||
|
||||
// Put the last read character back into the istream
|
||||
void retract();
|
||||
|
||||
CIFToken get_next_token();
|
||||
|
||||
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();
|
||||
|
||||
void parse_datablock();
|
||||
|
||||
virtual void parse_save_frame();
|
||||
|
||||
void error(const std::string &msg)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "Error parsing mmCIF: " << msg << '\n';
|
||||
|
||||
throw parse_error(m_line_nr, msg);
|
||||
}
|
||||
|
||||
void warning(const std::string &msg)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "parser warning at line " << m_line_nr << ": " << msg << '\n';
|
||||
}
|
||||
|
||||
// production methods, these are pure virtual here
|
||||
|
||||
virtual void produce_datablock(std::string_view name) = 0;
|
||||
virtual void produce_category(std::string_view name) = 0;
|
||||
virtual void produce_row() = 0;
|
||||
virtual void produce_item(std::string_view category, std::string_view item, item_value value) = 0;
|
||||
|
||||
protected:
|
||||
enum class State
|
||||
{
|
||||
Start,
|
||||
White,
|
||||
Esc,
|
||||
Comment,
|
||||
QuestionMark,
|
||||
Dot,
|
||||
QuotedString,
|
||||
QuotedStringQuote,
|
||||
UnquotedString,
|
||||
ItemName,
|
||||
TextItem,
|
||||
TextItemNL,
|
||||
Reserved,
|
||||
Value,
|
||||
|
||||
TextItemBS,
|
||||
TextItemBS2,
|
||||
TextItemBSNL,
|
||||
|
||||
Numeric_Zero,
|
||||
Numeric_Integer,
|
||||
Numeric_Float,
|
||||
Numeric_Exponent1,
|
||||
Numeric_Exponent2
|
||||
};
|
||||
|
||||
std::streambuf &m_source;
|
||||
|
||||
// Parser state
|
||||
uint32_t m_line_nr;
|
||||
bool m_bol;
|
||||
bool m_backslash_strings = false;
|
||||
CIFToken m_lookahead;
|
||||
|
||||
// token buffer
|
||||
std::vector<char> m_token_buffer;
|
||||
std::string_view m_token_value;
|
||||
int64_t m_token_value_int;
|
||||
double m_token_value_float;
|
||||
int m_float_precision;
|
||||
|
||||
/** @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;
|
||||
|
||||
void produce_row() override;
|
||||
|
||||
void produce_item(std::string_view category, std::string_view item, item_value value) override;
|
||||
|
||||
protected:
|
||||
file &m_file;
|
||||
datablock *m_datablock = nullptr;
|
||||
category *m_category = nullptr;
|
||||
const validator *m_validator = nullptr;
|
||||
row_handle m_row;
|
||||
|
||||
/** @endcond */
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
268
include/cif++/pdb.hpp
Normal file
268
include/cif++/pdb.hpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/*-
|
||||
* 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
|
||||
*/
|
||||
void read_pdb_file(std::istream &pdbFile, cif::file &cifFile);
|
||||
|
||||
// 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
|
||||
* \result Returns true if the file was valid and consistent
|
||||
*/
|
||||
|
||||
bool is_valid_pdbx_file(const file &pdbx_file);
|
||||
|
||||
/** \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);
|
||||
|
||||
/** \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 pdbx_file The input file
|
||||
* \param ec In case of error, this will contain what went wrong
|
||||
* \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 pdbx_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
|
||||
905
include/cif++/point.hpp
Normal file
905
include/cif++/point.hpp
Normal file
@@ -0,0 +1,905 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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 <array>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <format>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
#if __has_include(<clipper/core/coords.h>)
|
||||
# define HAVE_LIBCLIPPER 1
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
# include <clipper/core/clipper_types.h>
|
||||
# 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 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)
|
||||
, c(value_c)
|
||||
, d(value_d)
|
||||
{
|
||||
}
|
||||
|
||||
/// \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())
|
||||
, c(z1.real())
|
||||
, d(z1.imag())
|
||||
{
|
||||
}
|
||||
|
||||
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))
|
||||
, b(static_cast<value_type>(rhs.b))
|
||||
, c(static_cast<value_type>(rhs.c))
|
||||
, d(static_cast<value_type>(rhs.d))
|
||||
{
|
||||
}
|
||||
|
||||
// accessors
|
||||
|
||||
/// \brief See class description, return the *real* part of the quaternion
|
||||
[[nodiscard]] constexpr value_type real() const
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/// \brief See class description, return the *unreal* part of the quaternion
|
||||
[[nodiscard]] constexpr quaternion_type unreal() const
|
||||
{
|
||||
return { 0, b, c, d };
|
||||
}
|
||||
|
||||
/// \brief swap
|
||||
constexpr void swap(quaternion_type &o)
|
||||
{
|
||||
std::swap(a, o.a);
|
||||
std::swap(b, o.b);
|
||||
std::swap(c, o.c);
|
||||
std::swap(d, o.d);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
a = static_cast<value_type>(rhs.a);
|
||||
b = static_cast<value_type>(rhs.b);
|
||||
c = static_cast<value_type>(rhs.c);
|
||||
d = static_cast<value_type>(rhs.d);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Assignment operator
|
||||
constexpr quaternion_type &operator=(quaternion_type const &rhs) = default;
|
||||
|
||||
/// \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;
|
||||
|
||||
b = c = d = static_cast<value_type>(0);
|
||||
|
||||
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();
|
||||
b = rhs.imag();
|
||||
|
||||
c = d = static_cast<value_type>(0);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// other assignment-related operators
|
||||
|
||||
/// \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);
|
||||
b += std::imag(rhs);
|
||||
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)
|
||||
{
|
||||
a += rhs.a;
|
||||
b += rhs.b;
|
||||
c += rhs.c;
|
||||
d += rhs.d;
|
||||
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);
|
||||
b -= std::imag(rhs);
|
||||
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)
|
||||
{
|
||||
a -= rhs.a;
|
||||
b -= rhs.b;
|
||||
c -= rhs.c;
|
||||
d -= rhs.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief multiply all parts with value @a rhs
|
||||
constexpr quaternion_type &operator*=(value_type const &rhs)
|
||||
{
|
||||
a *= rhs;
|
||||
b *= rhs;
|
||||
c *= rhs;
|
||||
d *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief multiply with complex number @a rhs
|
||||
constexpr quaternion_type &operator*=(std::complex<value_type> const &rhs)
|
||||
{
|
||||
value_type ar = rhs.real();
|
||||
value_type br = rhs.imag();
|
||||
quaternion_type result(a * ar - b * br, a * br + b * ar, c * ar + d * br, -c * br + d * ar);
|
||||
swap(result);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \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)
|
||||
{
|
||||
auto ar = static_cast<value_type>(rhs.a);
|
||||
auto br = static_cast<value_type>(rhs.b);
|
||||
auto cr = static_cast<value_type>(rhs.c);
|
||||
auto dr = static_cast<value_type>(rhs.d);
|
||||
|
||||
quaternion_type result(a * ar - b * br - c * cr - d * dr, a * br + b * ar + c * dr - d * cr, a * cr - b * dr + c * ar + d * br, a * dr + b * cr - c * br + d * ar);
|
||||
swap(result);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief divide all parts by @a rhs
|
||||
constexpr quaternion_type &operator/=(value_type const &rhs)
|
||||
{
|
||||
a /= rhs;
|
||||
b /= rhs;
|
||||
c /= rhs;
|
||||
d /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief divide by complex number @a rhs
|
||||
constexpr quaternion_type &operator/=(std::complex<value_type> const &rhs)
|
||||
{
|
||||
value_type ar = rhs.real();
|
||||
value_type br = rhs.imag();
|
||||
value_type denominator = ar * ar + br * br;
|
||||
quaternion_type result((+a * ar + b * br) / denominator, (-a * br + b * ar) / denominator, (+c * ar - d * br) / denominator, (+c * br + d * ar) / denominator);
|
||||
swap(result);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief divide by quaternion @a rhs
|
||||
template <typename X>
|
||||
constexpr quaternion_type &operator/=(quaternion_type<X> const &rhs)
|
||||
{
|
||||
auto ar = static_cast<value_type>(rhs.a);
|
||||
auto br = static_cast<value_type>(rhs.b);
|
||||
auto cr = static_cast<value_type>(rhs.c);
|
||||
auto dr = static_cast<value_type>(rhs.d);
|
||||
|
||||
value_type denominator = ar * ar + br * br + cr * cr + dr * dr;
|
||||
quaternion_type result((+a * ar + b * br + c * cr + d * dr) / denominator, (-a * br + b * ar - c * dr + d * cr) / denominator, (-a * cr + b * dr + c * ar - d * br) / denominator, (-a * dr - b * cr + c * br + d * ar) / denominator);
|
||||
swap(result);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \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);
|
||||
|
||||
t[0] = q.a;
|
||||
t[1] = q.b;
|
||||
t[2] = q.c;
|
||||
t[3] = q.d;
|
||||
|
||||
t *= t;
|
||||
|
||||
value_type length = std::sqrt(t.sum());
|
||||
|
||||
if (length > 0.001)
|
||||
q /= static_cast<value_type>(length);
|
||||
else
|
||||
q = quaternion_type(1, 0, 0, 0);
|
||||
|
||||
return 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 };
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr value_type get_a() const { return a; } ///< Return part a
|
||||
[[nodiscard]] constexpr value_type get_b() const { return b; } ///< Return part b
|
||||
[[nodiscard]] constexpr value_type get_c() const { return c; } ///< Return part c
|
||||
[[nodiscard]] 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 explicit operator bool() const
|
||||
{
|
||||
return a != 0 or b != 0 or c != 0 or d != 0;
|
||||
}
|
||||
|
||||
/// \brief for debugging e.g.
|
||||
friend std::ostream &operator<<(std::ostream &os, const quaternion_type &rhs)
|
||||
{
|
||||
os << std::format("{{ a: {}, b: {}, c: {}, d: {} }}", rhs.a, rhs.b, rhs.c, rhs.d);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type a, b, c, d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
T cos_phi1 = std::cos(phi1);
|
||||
T cos_phi2 = std::cos(phi2);
|
||||
|
||||
T a = std::cos(theta) * cos_phi1 * cos_phi2;
|
||||
T b = std::sin(theta) * cos_phi1 * cos_phi2;
|
||||
T c = std::sin(phi1) * cos_phi2;
|
||||
T d = std::sin(phi2);
|
||||
|
||||
quaternion_type result(a, b, c, d);
|
||||
result *= rho;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief By default we use the float version of a quaternion
|
||||
using quaternion = quaternion_type<float>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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, ///< 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)
|
||||
, m_z(0)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor taking three values
|
||||
constexpr point_type(value_type x, value_type y, value_type z)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
, m_z(z)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief Copy constructor
|
||||
template <typename PF>
|
||||
constexpr point_type(const point_type<PF> &pt)
|
||||
: m_x(static_cast<F>(pt.m_x))
|
||||
, m_y(static_cast<F>(pt.m_y))
|
||||
, m_z(static_cast<F>(pt.m_z))
|
||||
{
|
||||
}
|
||||
|
||||
/// \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])
|
||||
, m_z(pt[2])
|
||||
{
|
||||
}
|
||||
|
||||
/// \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];
|
||||
m_y = rhs[1];
|
||||
m_z = rhs[2];
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Assignment operator
|
||||
template <typename PF>
|
||||
constexpr point_type &operator=(const point_type<PF> &rhs)
|
||||
{
|
||||
m_x = static_cast<F>(rhs.m_x);
|
||||
m_y = static_cast<F>(rhs.m_y);
|
||||
m_z = static_cast<F>(rhs.m_z);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr value_type &get_x() { return m_x; } ///< Get a reference to x
|
||||
[[nodiscard]] 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
|
||||
|
||||
[[nodiscard]] constexpr value_type &get_y() { return m_y; } ///< Get a reference to y
|
||||
[[nodiscard]] 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
|
||||
|
||||
[[nodiscard]] constexpr value_type &get_z() { return m_z; } ///< Get a reference to z
|
||||
[[nodiscard]] 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;
|
||||
m_y += rhs.m_y;
|
||||
m_z += rhs.m_z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief add @a d to all members
|
||||
constexpr point_type &operator+=(value_type d)
|
||||
{
|
||||
m_x += d;
|
||||
m_y += d;
|
||||
m_z += d;
|
||||
|
||||
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;
|
||||
m_y -= rhs.m_y;
|
||||
m_z -= rhs.m_z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief subtract @a d from all members
|
||||
constexpr point_type &operator-=(value_type d)
|
||||
{
|
||||
m_x -= d;
|
||||
m_y -= d;
|
||||
m_z -= d;
|
||||
|
||||
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;
|
||||
m_y *= rhs;
|
||||
m_z *= rhs;
|
||||
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;
|
||||
m_y /= rhs;
|
||||
m_z /= rhs;
|
||||
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;
|
||||
if (length > 0)
|
||||
{
|
||||
length = std::sqrt(length);
|
||||
operator/=(length);
|
||||
}
|
||||
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);
|
||||
|
||||
p = q * p * conj(q);
|
||||
|
||||
m_x = p.get_b();
|
||||
m_y = p.get_c();
|
||||
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);
|
||||
rotate(q);
|
||||
operator+=(pivot);
|
||||
}
|
||||
|
||||
#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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] constexpr value_type length() const
|
||||
{
|
||||
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>;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// several standard 3d operations
|
||||
|
||||
/// \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);
|
||||
}
|
||||
|
||||
/// \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) +
|
||||
(a.m_y - b.m_y) * (a.m_y - b.m_y) +
|
||||
(a.m_z - b.m_z) * (a.m_z - b.m_z));
|
||||
}
|
||||
|
||||
/// \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;
|
||||
}
|
||||
|
||||
/// \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<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 squared norm of point @a p
|
||||
template <typename F>
|
||||
constexpr F norm_squared(const point_type<F> &p)
|
||||
{
|
||||
return p.m_x * p.m_x + p.m_y * p.m_y + p.m_z * p.m_z;
|
||||
}
|
||||
|
||||
/// \brief return the norm of point @a p
|
||||
template <typename F>
|
||||
constexpr point_type<F> norm(const point_type<F> &p)
|
||||
{
|
||||
return std::sqrt(norm_squared(p));
|
||||
}
|
||||
|
||||
/// \brief return the point where two lines intersect, or an empty value if they don't intersect at all
|
||||
template <typename F>
|
||||
std::optional<cif::point> line_line_intersection(const point_type<F> &p1,
|
||||
const point_type<F> &p2, const point_type<F> &p3, const point_type<F> &p4)
|
||||
{
|
||||
auto p13 = p1 - p3;
|
||||
auto p43 = p4 - p3;
|
||||
if (std::abs(p43.m_x) < std::numeric_limits<F>::epsilon() and std::abs(p43.m_y) < std::numeric_limits<F>::epsilon() and std::abs(p43.m_z) < std::numeric_limits<F>::epsilon())
|
||||
return std::nullopt;
|
||||
|
||||
auto p21 = p2 - p1;
|
||||
if (std::abs(p21.m_x) < std::numeric_limits<F>::epsilon() and std::abs(p21.m_y) < std::numeric_limits<F>::epsilon() and std::abs(p21.m_z) < std::numeric_limits<F>::epsilon())
|
||||
return std::nullopt;
|
||||
|
||||
auto d1343 = cif::dot_product(p43, p13);
|
||||
auto d4321 = cif::dot_product(p43, p21);
|
||||
auto d1321 = cif::dot_product(p13, p21);
|
||||
auto d4343 = cif::dot_product(p43, p43);
|
||||
auto d2121 = cif::dot_product(p21, p21);
|
||||
|
||||
auto denom = d2121 * d4343 - d4321 * d4321;
|
||||
if (std::abs(denom) < std::numeric_limits<F>::epsilon())
|
||||
return std::nullopt;
|
||||
|
||||
auto numer = d1343 * d4321 - d1321 * d4343;
|
||||
|
||||
auto mua = numer / denom;
|
||||
auto mub = (d1343 + d4321 * mua) / d4343;
|
||||
|
||||
auto pa = p1 + mua * p21;
|
||||
auto pb = p3 + mub * p43;
|
||||
|
||||
return { (pa + pb) / 2 };
|
||||
}
|
||||
|
||||
/// \brief return the angle in degrees between the vectors from point @a p2 to @a p1 and @a p2 to @a p3
|
||||
template <typename F>
|
||||
constexpr auto angle(const point_type<F> &p1, const point_type<F> &p2, const point_type<F> &p3)
|
||||
{
|
||||
point_type<F> v1 = p1 - p2;
|
||||
point_type<F> v2 = p3 - p2;
|
||||
|
||||
return std::acos(dot_product(v1, v2) / (v1.length() * v2.length())) * 180 / std::numbers::pi_v<F>;
|
||||
}
|
||||
|
||||
/// \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)
|
||||
{
|
||||
point_type<F> v12 = p1 - p2; // vector from p2 to p1
|
||||
point_type<F> v43 = p4 - p3; // vector from p3 to p4
|
||||
|
||||
point_type<F> z = p2 - p3; // vector from p3 to p2
|
||||
|
||||
point_type<F> p = cross_product(z, v12);
|
||||
point_type<F> x = cross_product(z, v43);
|
||||
point_type<F> y = cross_product(z, x);
|
||||
|
||||
auto u = dot_product(x, x);
|
||||
auto v = dot_product(y, y);
|
||||
|
||||
F result = 360;
|
||||
if (u > 0 and v > 0)
|
||||
{
|
||||
u = dot_product(p, x) / std::sqrt(u);
|
||||
v = dot_product(p, y) / std::sqrt(v);
|
||||
if (u != 0 or v != 0)
|
||||
result = std::atan2(v, u) * static_cast<F>(180 / std::numbers::pi_v<F>);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
point_type<F> v12 = p1 - p2;
|
||||
point_type<F> v34 = p3 - p4;
|
||||
|
||||
auto x = dot_product(v12, v12) * dot_product(v34, v34);
|
||||
|
||||
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)
|
||||
{
|
||||
auto line = l2 - l1;
|
||||
auto p_to_l1 = p - l1;
|
||||
auto p_to_l2 = p - l2;
|
||||
auto cross = cross_product(p_to_l1, p_to_l2);
|
||||
return cross.length() / line.length();
|
||||
}
|
||||
|
||||
/// \brief return the smallest sphere around the points in @a pts
|
||||
std::tuple<point, float> smallest_sphere_around_points(std::vector<point> pts);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/**
|
||||
* @brief For e.g. simulated annealing, returns a new point that is moved in
|
||||
* 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<float, point> quaternion_to_angle_axis(quaternion q);
|
||||
|
||||
/// @brief Given four points and an angle, return the quaternion required to rotate
|
||||
/// point p4 along the p2-p3 axis and around point p3 to obtain the required within
|
||||
/// an accuracy of esd
|
||||
quaternion construct_for_dihedral_angle(point p1, point p2, point p3, point p4,
|
||||
float angle, float esd);
|
||||
|
||||
/// \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
|
||||
///
|
||||
/// \param a The first set of points
|
||||
/// \param b The second set of points
|
||||
/// \result The quaternion which should be applied to the points in \a a to
|
||||
/// obtain the best superposition.
|
||||
quaternion align_points(const std::vector<point> &a, const std::vector<point> &b);
|
||||
|
||||
/// \brief The RMSd for the points in \a a and \a b
|
||||
double RMSd(const std::vector<point> &a, const std::vector<point> &b);
|
||||
|
||||
} // namespace cif
|
||||
601
include/cif++/row.hpp
Normal file
601
include/cif++/row.hpp
Normal file
@@ -0,0 +1,601 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 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++/item.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @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 a reference to a cif::item_value 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"].get<std::string>();
|
||||
*
|
||||
* // by index:
|
||||
* uint16_t ix = atom_site.get_item_ix("label_atom_id");
|
||||
* assert(rh[ix].get<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
|
||||
{
|
||||
|
||||
class category;
|
||||
|
||||
namespace cql
|
||||
{
|
||||
struct connection_impl;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename... C>
|
||||
struct get_row_result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief the row class, this one is not directly accessible from the outside
|
||||
|
||||
class row : public std::vector<item_value>
|
||||
{
|
||||
public:
|
||||
row() = default;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Return the item_value pointer for item at index @a ix
|
||||
*/
|
||||
item_value *get(uint16_t ix)
|
||||
{
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
return &data()[ix];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the const item_value pointer for item at index @a ix
|
||||
*/
|
||||
[[nodiscard]] const item_value *get(uint16_t ix) const
|
||||
{
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
void set(uint16_t ix, item_value v)
|
||||
{
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
operator[](ix) = std::move(v);
|
||||
}
|
||||
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
row *m_next = nullptr;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief row_handle is the way to access data stored in rows
|
||||
|
||||
class row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool>
|
||||
friend struct item_handle_base;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
friend class const_row_handle;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
row_handle() = default;
|
||||
virtual ~row_handle() = default;
|
||||
|
||||
row_handle(const row_handle &) = default;
|
||||
row_handle(row_handle &&) = default;
|
||||
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(category &cat, row &r)
|
||||
: m_category(&cat)
|
||||
, m_row(&r)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief return the category this row belongs to
|
||||
[[nodiscard]] category &get_category() const
|
||||
{
|
||||
return *m_category;
|
||||
}
|
||||
|
||||
/// \brief return the row ID
|
||||
[[nodiscard]] int64_t row_id() const
|
||||
{
|
||||
return reinterpret_cast<int64_t>(m_row);
|
||||
}
|
||||
|
||||
/// \brief Return true if the row is empty or uninitialised
|
||||
[[nodiscard]] 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();
|
||||
}
|
||||
|
||||
/// \brief return the count of the items
|
||||
[[nodiscard]] size_t size() const { return m_row->size(); }
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
item_handle operator[](uint16_t item_ix)
|
||||
{
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
const item_handle operator[](uint16_t item_ix) const
|
||||
{
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \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 { *m_category, *m_row, add_item(item_name) };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
const item_handle operator[](std::string_view item_name) const
|
||||
{
|
||||
return { *m_category, *m_row, get_item_ix(item_name) };
|
||||
}
|
||||
|
||||
/// \brief assign each of the items named in @a values to their respective value
|
||||
void assign(const std::vector<item> &values, bool updateLinked = true)
|
||||
{
|
||||
for (auto &value : values)
|
||||
assign(value, updateLinked);
|
||||
}
|
||||
|
||||
/** \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, item_value value, bool updateLinked, bool validate = true)
|
||||
{
|
||||
assign(add_item(name), std::move(value), updateLinked, validate);
|
||||
}
|
||||
|
||||
/** \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, item_value value, bool updateLinked, bool validate = true);
|
||||
|
||||
/// \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>
|
||||
[[nodiscard]] auto get(C... items) const
|
||||
{
|
||||
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::tuple<Ts...> get(C... items) const
|
||||
requires(sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1)
|
||||
{
|
||||
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>
|
||||
[[nodiscard]] T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \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; }
|
||||
|
||||
protected:
|
||||
/// Return the index number for the item named @a name
|
||||
[[nodiscard]] uint16_t get_item_ix(std::string_view name) const;
|
||||
|
||||
/// Return the name for the item with index number @a ix
|
||||
[[nodiscard]] std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
friend cql::connection_impl;
|
||||
|
||||
/// Return the actual row
|
||||
[[nodiscard]] auto get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
category *m_category = nullptr; ///< The category
|
||||
row *m_row = nullptr; ///< The row
|
||||
|
||||
private:
|
||||
/// @cond
|
||||
uint16_t add_item(std::string_view name);
|
||||
|
||||
void assign(const item &i, bool updateLinked)
|
||||
{
|
||||
assign(i.name(), i.value(), updateLinked);
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
/// A const version of row_handle.
|
||||
|
||||
class const_row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool>
|
||||
friend struct item_handle_base;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
const_row_handle() = default;
|
||||
virtual ~const_row_handle() = default;
|
||||
|
||||
const_row_handle(const const_row_handle &) = default;
|
||||
const_row_handle(const_row_handle &&) = default;
|
||||
const_row_handle &operator=(const const_row_handle &) = default;
|
||||
const_row_handle &operator=(const_row_handle &&) = default;
|
||||
|
||||
const_row_handle(row_handle rh)
|
||||
: m_category(rh.m_category)
|
||||
, m_row(rh.m_row)
|
||||
{
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/// \brief constructor taking a category @a cat and a row @a r
|
||||
const_row_handle(const category &cat, const row &r)
|
||||
: m_category(&cat)
|
||||
, m_row(&r)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief return the category this row belongs to
|
||||
[[nodiscard]] const category &get_category() const
|
||||
{
|
||||
return *m_category;
|
||||
}
|
||||
|
||||
/// \brief return the row ID
|
||||
[[nodiscard]] int64_t row_id() const
|
||||
{
|
||||
return reinterpret_cast<int64_t>(m_row);
|
||||
}
|
||||
|
||||
/// \brief Return true if the row is empty or uninitialised
|
||||
[[nodiscard]] 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();
|
||||
}
|
||||
|
||||
/// \brief return the count of the items
|
||||
[[nodiscard]] size_t size() const { return m_row->size(); }
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
const item_handle operator[](uint16_t item_ix) const
|
||||
{
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
const item_handle operator[](std::string_view item_name) const
|
||||
{
|
||||
return operator[](get_item_ix(item_name));
|
||||
}
|
||||
|
||||
/// \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>
|
||||
[[nodiscard]] auto get(C... items) const
|
||||
{
|
||||
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::tuple<Ts...> get(C... items) const
|
||||
requires(sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1)
|
||||
{
|
||||
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>
|
||||
[[nodiscard]] T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief compare two rows
|
||||
// bool operator==(const const_row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
|
||||
friend bool operator==(const_row_handle a, const_row_handle b)
|
||||
{
|
||||
return a.m_category == b.m_category and a.m_row == b.m_row;
|
||||
}
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator!=(const const_row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
|
||||
|
||||
protected:
|
||||
/// Return the index number for the item named @a name
|
||||
[[nodiscard]] uint16_t get_item_ix(std::string_view name) const;
|
||||
|
||||
/// Return the name for the item with index number @a ix
|
||||
[[nodiscard]] std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
friend cql::connection_impl;
|
||||
|
||||
/// Return the actual row
|
||||
[[nodiscard]] auto get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
const category *m_category = nullptr; ///< The category
|
||||
const row *m_row = nullptr; ///< The row
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/// @cond
|
||||
|
||||
/// some helper classes to help create tuple result types
|
||||
template <typename... C>
|
||||
struct get_row_result
|
||||
{
|
||||
static constexpr std::size_t N = sizeof...(C);
|
||||
|
||||
get_row_result(const_row_handle r, std::array<uint16_t, N> &&items)
|
||||
: m_row(std::move(r))
|
||||
, m_items(std::move(items))
|
||||
{
|
||||
}
|
||||
|
||||
const item_handle operator[](uint16_t ix) const
|
||||
{
|
||||
return m_row[m_items[ix]];
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
operator std::tuple<Ts...>() const
|
||||
requires(N == sizeof...(Ts))
|
||||
{
|
||||
return get<Ts...>(std::index_sequence_for<Ts...>{});
|
||||
}
|
||||
|
||||
template <typename... Ts, std::size_t... Is>
|
||||
[[nodiscard]] std::tuple<Ts...> get(std::index_sequence<Is...>) const
|
||||
{
|
||||
return std::tuple<Ts...>{ m_row[m_items[Is]].template get<Ts>()... };
|
||||
}
|
||||
|
||||
const_row_handle m_row;
|
||||
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
|
||||
template <typename... Ts>
|
||||
struct tie_wrap
|
||||
{
|
||||
tie_wrap(Ts... args)
|
||||
: m_value(args...)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename RR>
|
||||
void operator=(const RR &&rr)
|
||||
{
|
||||
// get_row_result will do the conversion, but only if the types
|
||||
// are compatible. That means the number of parameters to the get()
|
||||
// of the row should be equal to the number of items in the tuple
|
||||
// you are trying to tie.
|
||||
|
||||
using RType = std::tuple<std::remove_reference_t<Ts>...>;
|
||||
|
||||
m_value = static_cast<RType>(rr);
|
||||
}
|
||||
|
||||
std::tuple<Ts...> m_value;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // 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)
|
||||
{
|
||||
return detail::tie_wrap<Ts &...>(std::forward<Ts &>(v)...);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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;
|
||||
row_initializer(const row_initializer &) = default;
|
||||
row_initializer(row_initializer &&) = default;
|
||||
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>
|
||||
row_initializer(ItemIter b, ItemIter e)
|
||||
requires(std::is_constructible_v<item, typename ItemIter::value_type>)
|
||||
: std::vector<item>(b, e)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor taking the values of an existing row
|
||||
row_initializer(row_handle rh)
|
||||
: cif::row_initializer(const_row_handle{ rh })
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
row_initializer(const_row_handle rh);
|
||||
|
||||
/// \brief set the value for item name @a name to @a value
|
||||
void set_value(std::string name, item_value value);
|
||||
|
||||
/// \brief set the value for item based on @a i
|
||||
void set_value(const item &i)
|
||||
{
|
||||
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 name, item_value value);
|
||||
|
||||
/// \brief set the value for item @a i, but only if the item did not have a value already
|
||||
void set_value_if_empty(const item &i)
|
||||
{
|
||||
set_value_if_empty(i.name(), i.value());
|
||||
}
|
||||
|
||||
/// \brief enable emplace_back for more complex items (floats with precission)
|
||||
auto emplace_back(std::string name, item_value value)
|
||||
{
|
||||
return std::vector<item>::emplace_back(item(std::forward<std::string>(name), std::forward<item_value>(value)));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
543
include/cif++/symmetry.hpp
Normal file
543
include/cif++/symmetry.hpp
Normal file
@@ -0,0 +1,543 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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++/exports.hpp"
|
||||
#include "cif++/matrix.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#if defined(__cpp_impl_three_way_comparison)
|
||||
# include <utility>
|
||||
#endif
|
||||
|
||||
/** \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 {
|
||||
m(0, 0) * pt.m_x + m(0, 1) * pt.m_y + m(0, 2) * pt.m_z,
|
||||
m(1, 0) * pt.m_x + m(1, 1) * pt.m_y + m(1, 2) * pt.m_z,
|
||||
m(2, 0) * pt.m_x + m(2, 1) * pt.m_y + m(2, 2) * pt.m_z
|
||||
};
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief the space groups we know
|
||||
enum class space_group_name
|
||||
{
|
||||
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; ///< 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) noexcept
|
||||
: m_packed((data[0] bitand 0x03ULL) << 34 bitor
|
||||
(data[1] bitand 0x03ULL) << 32 bitor
|
||||
(data[2] bitand 0x03ULL) << 30 bitor
|
||||
(data[3] bitand 0x03ULL) << 28 bitor
|
||||
(data[4] bitand 0x03ULL) << 26 bitor
|
||||
(data[5] bitand 0x03ULL) << 24 bitor
|
||||
(data[6] bitand 0x03ULL) << 22 bitor
|
||||
(data[7] bitand 0x03ULL) << 20 bitor
|
||||
(data[8] bitand 0x03ULL) << 18 bitor
|
||||
(data[9] bitand 0x07ULL) << 15 bitor
|
||||
(data[10] bitand 0x07ULL) << 12 bitor
|
||||
(data[11] bitand 0x07ULL) << 9 bitor
|
||||
(data[12] bitand 0x07ULL) << 6 bitor
|
||||
(data[13] bitand 0x07ULL) << 3 bitor
|
||||
(data[14] bitand 0x07ULL) << 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// \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
|
||||
[[nodiscard]] inline constexpr int unpack3(int offset) const
|
||||
{
|
||||
int result = static_cast<int>((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
|
||||
[[nodiscard]] inline constexpr int unpack7(int offset) const
|
||||
{
|
||||
return static_cast<int>((m_packed >> offset) bitand 0x07);
|
||||
}
|
||||
|
||||
/// \brief return an array of 15 ints representing the values stored
|
||||
[[nodiscard]] constexpr std::array<int, 15> data() const
|
||||
{
|
||||
return {
|
||||
unpack3(34),
|
||||
unpack3(32),
|
||||
unpack3(30),
|
||||
unpack3(28),
|
||||
unpack3(26),
|
||||
unpack3(24),
|
||||
unpack3(22),
|
||||
unpack3(20),
|
||||
unpack3(18),
|
||||
unpack7(15),
|
||||
unpack7(12),
|
||||
unpack7(9),
|
||||
unpack7(6),
|
||||
unpack7(3),
|
||||
unpack7(0)
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct symop_datablock;
|
||||
|
||||
const uint64_t kPackMask = (~0ULL >> (64 - 36));
|
||||
|
||||
symop_data(uint64_t v)
|
||||
: m_packed(v bitand kPackMask)
|
||||
{
|
||||
}
|
||||
|
||||
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) noexcept
|
||||
: m_v((spacegroup bitand 0xffffULL) << 48 bitor
|
||||
(rotational_number bitand 0xffULL) << 40 bitor
|
||||
symop_data(rt_data).m_packed)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] int spacegroup() const { return m_v >> 48; } ///< Return the spacegroup
|
||||
[[nodiscard]] symop_data symop() const { return { m_v }; } ///< Return the symmetry operation
|
||||
[[nodiscard]] uint8_t rotational_number() const { return (m_v >> 40) bitand 0xff; } ///< Return the rotational_number
|
||||
|
||||
private:
|
||||
uint64_t m_v;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Some more symmetry related stuff here.
|
||||
|
||||
class datablock;
|
||||
|
||||
class cell;
|
||||
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].
|
||||
*/
|
||||
|
||||
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)
|
||||
, m_tb(tb)
|
||||
, m_tc(tc)
|
||||
{
|
||||
}
|
||||
|
||||
/// \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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] 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
|
||||
{
|
||||
/**
|
||||
* @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 });
|
||||
}
|
||||
} // 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)
|
||||
pt.rotate(m_q);
|
||||
else
|
||||
pt = m_rotation * pt;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
void try_create_quaternion();
|
||||
|
||||
matrix3x3<float> m_rotation;
|
||||
quaternion m_q;
|
||||
point m_translation;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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);
|
||||
|
||||
[[nodiscard]] float get_a() const { return m_a; } ///< return dimension a
|
||||
[[nodiscard]] float get_b() const { return m_b; } ///< return dimension b
|
||||
[[nodiscard]] float get_c() const { return m_c; } ///< return dimension c
|
||||
|
||||
[[nodiscard]] float get_alpha() const { return m_alpha; } ///< return angle alpha
|
||||
[[nodiscard]] float get_beta() const { return m_beta; } ///< return angle beta
|
||||
[[nodiscard]] float get_gamma() const { return m_gamma; } ///< return angle gamma
|
||||
|
||||
[[nodiscard]] float get_volume() const; ///< return the calculated volume for this cell
|
||||
|
||||
[[nodiscard]] matrix3x3<float> get_orthogonal_matrix() const { return m_orthogonal; } ///< return the matrix to use to transform coordinates from fractional to orthogonal
|
||||
[[nodiscard]] matrix3x3<float> get_fractional_matrix() const { return m_fractional; } ///< return the matrix to use to transform coordinates from orthogonal to fractional
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
float m_a, m_b, m_c, m_alpha, m_beta, m_gamma;
|
||||
matrix3x3<float> m_orthogonal, m_fractional;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \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);
|
||||
|
||||
[[nodiscard]] int get_nr() const { return m_nr; } ///< Return the nr
|
||||
[[nodiscard]] 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
|
||||
*/
|
||||
[[nodiscard]] point inverse(const point &pt, const cell &c, sym_op symop) const;
|
||||
|
||||
private:
|
||||
int m_nr;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/**
|
||||
* @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, spacegroup sg)
|
||||
: m_cell(c)
|
||||
, m_spacegroup(std::move(sg))
|
||||
{
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
crystal(const crystal &) = default;
|
||||
crystal(crystal &&) = default;
|
||||
crystal &operator=(const crystal &) = default;
|
||||
crystal &operator=(crystal &&) = default;
|
||||
/** @endcond */
|
||||
|
||||
[[nodiscard]] const cell &get_cell() const { return m_cell; } ///< Return the cell
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] point inverse_symmetry_copy(const point &pt, sym_op symop) const
|
||||
{
|
||||
return m_spacegroup.inverse(pt, m_cell, symop);
|
||||
}
|
||||
|
||||
/// \brief Return a tuple consisting of distance, new location and symmetry operation
|
||||
/// for the point @a b with respect to point @a a.
|
||||
[[nodiscard]] std::tuple<float, point, sym_op> closest_symmetry_copy(point a, point b) const;
|
||||
|
||||
private:
|
||||
cell m_cell;
|
||||
spacegroup m_spacegroup;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
} // namespace cif
|
||||
399
include/cif++/text.hpp
Normal file
399
include/cif++/text.hpp
Normal file
@@ -0,0 +1,399 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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++/exports.hpp"
|
||||
|
||||
#include <charconv>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if __has_include(<experimental/type_traits>)
|
||||
|
||||
# include <experimental/type_traits>
|
||||
namespace std_experimental = std::experimental;
|
||||
|
||||
#else
|
||||
|
||||
// A quick hack to work around the missing is_detected in MSVC
|
||||
/// @cond
|
||||
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;
|
||||
|
||||
/// @endcond
|
||||
} // namespace std_experimental
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \file text.hpp
|
||||
*
|
||||
* Various text manipulating routines
|
||||
*/
|
||||
|
||||
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) noexcept;
|
||||
|
||||
/// \brief compare string @a is to string @a b ignoring changes in character case
|
||||
int icompare(std::string_view a, std::string_view b) noexcept;
|
||||
|
||||
/// \brief return whether string @a is equal to string @a b ignoring changes in character case
|
||||
bool iequals(const char *a, const char *b) noexcept;
|
||||
|
||||
/// \brief compare string @a is to string @a b ignoring changes in character case
|
||||
int icompare(const char *a, const char *b) noexcept;
|
||||
|
||||
/// \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);
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
std::ostringstream s;
|
||||
|
||||
if (b != e)
|
||||
{
|
||||
auto ai = b;
|
||||
auto ni = std::next(ai);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
s << *ai;
|
||||
|
||||
if (ni == e)
|
||||
break;
|
||||
|
||||
ai = ni;
|
||||
ni = std::next(ai);
|
||||
|
||||
s << 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)
|
||||
{
|
||||
std::vector<StringType> result;
|
||||
|
||||
auto b = s.data();
|
||||
auto e = b;
|
||||
|
||||
while (e != s.data() + s.length())
|
||||
{
|
||||
if (separators.find(*e) != std::string_view::npos)
|
||||
{
|
||||
if (e > b or not suppress_empty)
|
||||
result.emplace_back(b, e - b);
|
||||
b = e = e + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
++e;
|
||||
}
|
||||
|
||||
if (e > b or not suppress_empty)
|
||||
result.emplace_back(b, e - 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);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
};
|
||||
|
||||
/// 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)]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** \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);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \brief generate a cif name, used e.g. to generate asym_id's
|
||||
std::string cif_id_for_number(int number);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** \brief custom word wrapping routine.
|
||||
*
|
||||
* Wrap the text in @a text based on a maximum line width @a width using
|
||||
* a dynamic programming approach to get the most efficient filling of
|
||||
* the space.
|
||||
*/
|
||||
std::vector<std::string> word_wrap(const std::string &text, std::size_t width);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// @cond
|
||||
// Code to select a version of from_chars that is implemented...
|
||||
|
||||
template <typename T>
|
||||
using from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<T &>()));
|
||||
|
||||
template <typename T>
|
||||
struct std_charconv
|
||||
{
|
||||
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
|
||||
{
|
||||
return std::from_chars(a, b, d);
|
||||
}
|
||||
};
|
||||
|
||||
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 charconv = typename std::conditional_t<std_experimental::is_detected_v<from_chars_function, T>, std_charconv<T>, ff_charconv<T>>;
|
||||
|
||||
template <typename T>
|
||||
constexpr auto from_chars(const char *s, const char *e, T &v)
|
||||
{
|
||||
return charconv<T>::from_chars(s, e, v);
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace cif
|
||||
382
include/cif++/utilities.hpp
Normal file
382
include/cif++/utilities.hpp
Normal file
@@ -0,0 +1,382 @@
|
||||
/*-
|
||||
* 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
|
||||
* 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++/exports.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#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
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
# pragma warning(disable : 4996) // unsafe function or variable (strcpy e.g.)
|
||||
# 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)
|
||||
|
||||
// Truncation warnings: yes, perhaps, but I think they are okay
|
||||
# pragma warning(disable : 4244)
|
||||
# pragma warning(disable : 4267)
|
||||
# pragma warning(disable : 4305)
|
||||
|
||||
# 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;
|
||||
|
||||
/// return the git 'build' number
|
||||
[[nodiscard]] std::string get_version_nr();
|
||||
|
||||
/// return the width of the current output terminal, or 80 if it cannot be determined
|
||||
[[nodiscard]] uint32_t get_terminal_width();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
namespace colour
|
||||
{
|
||||
/// @brief The defined colours
|
||||
enum colour_type
|
||||
{
|
||||
black,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
_unused,
|
||||
none
|
||||
};
|
||||
|
||||
/// @brief The defined styles
|
||||
enum style_type
|
||||
{
|
||||
bold = 1,
|
||||
underlined = 4,
|
||||
blink = 5,
|
||||
inverse = 7,
|
||||
regular = 22,
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* @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))
|
||||
{
|
||||
}
|
||||
|
||||
coloured_string_t(coloured_string_t &) = delete;
|
||||
coloured_string_t &operator=(coloured_string_t &) = delete;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
if ((os.rdbuf() == std::cout.rdbuf() and isatty(STDOUT_FILENO)) or (os.rdbuf() == std::cerr.rdbuf() and isatty(STDERR_FILENO)))
|
||||
{
|
||||
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 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:
|
||||
progress_bar(const progress_bar &) = delete;
|
||||
progress_bar &operator=(const progress_bar &) = delete;
|
||||
|
||||
/**
|
||||
* @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:
|
||||
struct progress_bar_impl *m_impl = nullptr;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// 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
|
||||
614
include/cif++/validate.hpp
Normal file
614
include/cif++/validate.hpp
Normal file
@@ -0,0 +1,614 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 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++/category.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/text.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <iosfwd>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
value_is_not_a_number, /**< The value is not a number */
|
||||
value_is_not_a_char_string, /**< The value is not a character string */
|
||||
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:
|
||||
/**
|
||||
* @brief User friendly name
|
||||
*
|
||||
* @return const char*
|
||||
*/
|
||||
|
||||
[[nodiscard]] 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
|
||||
*/
|
||||
|
||||
[[nodiscard]] std::string message(int ev) const override
|
||||
{
|
||||
switch (static_cast<validation_error>(ev))
|
||||
{
|
||||
using enum validation_error;
|
||||
|
||||
case value_does_not_match_rx:
|
||||
return "Value in item does not match regular expression";
|
||||
case value_is_not_in_enumeration_list:
|
||||
return "Value is not in the enumerated list of valid values";
|
||||
case value_is_not_a_number:
|
||||
return "Value is not a number";
|
||||
case value_is_not_a_char_string:
|
||||
return "Value is not a character string";
|
||||
case not_a_known_primitive_type:
|
||||
return "The type is not a known primitive type";
|
||||
case undefined_category:
|
||||
return "Category has no definition in the dictionary";
|
||||
case unknown_item:
|
||||
return "Item is not defined to be part of the category";
|
||||
case incorrect_item_validator:
|
||||
return "Incorrectly specified validator for item";
|
||||
case missing_mandatory_items:
|
||||
return "Missing mandatory items";
|
||||
case missing_key_items:
|
||||
return "An index could not be constructed due to missing key items";
|
||||
case item_not_allowed_in_category:
|
||||
return "Requested item not allowed in category according to dictionary";
|
||||
case empty_file:
|
||||
return "The file contains no datablocks";
|
||||
case empty_datablock:
|
||||
return "The datablock contains no categories";
|
||||
case empty_category:
|
||||
return "The category is empty";
|
||||
case 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
|
||||
*
|
||||
*/
|
||||
|
||||
[[nodiscard]] 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;
|
||||
}
|
||||
|
||||
/// Return a std::error_code for a validation error
|
||||
inline std::error_code make_error_code(validation_error e)
|
||||
{
|
||||
return { static_cast<int>(e), validation_category() };
|
||||
}
|
||||
|
||||
/// Return a std::error_condition for a validation error
|
||||
inline std::error_condition make_error_condition(validation_error e)
|
||||
{
|
||||
return { static_cast<int>(e), validation_category() };
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// Exception class for validation errors
|
||||
class validation_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
/// @cond
|
||||
|
||||
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);
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/** @brief the primitive types known */
|
||||
enum class DDL_PrimitiveType
|
||||
{
|
||||
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; ///< 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);
|
||||
|
||||
/// @brief Copy constructor
|
||||
type_validator(const type_validator &tv) = default;
|
||||
|
||||
/// @brief Move constructor
|
||||
type_validator(type_validator &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// @brief Move constructor
|
||||
type_validator &operator=(type_validator rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
~type_validator() = default;
|
||||
|
||||
/// Swap two type validators
|
||||
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
|
||||
[[nodiscard]] int compare(const item_value &a, const item_value &b) const;
|
||||
};
|
||||
|
||||
/** @brief Item alias, items can be renamed over time
|
||||
*/
|
||||
|
||||
struct item_alias
|
||||
{
|
||||
/// constructor
|
||||
item_alias(std::string alias_name, std::string dictionary, std::string version)
|
||||
: m_name(std::move(alias_name))
|
||||
, m_dict(std::move(dictionary))
|
||||
, m_vers(std::move(version))
|
||||
{
|
||||
}
|
||||
|
||||
/// default copy constructor
|
||||
item_alias(const item_alias &) = default;
|
||||
|
||||
/// default copy assignment
|
||||
item_alias &operator=(const item_alias &) = default;
|
||||
|
||||
std::string m_name; ///< The alias_name
|
||||
std::string m_dict; ///< The dictionary in which it was known
|
||||
std::string m_vers; ///< The version of the dictionary
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An item_validator binds a type_validator to an item in
|
||||
* a category along with other information found in the dictionary.
|
||||
*
|
||||
* 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
|
||||
std::set<std::string> 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 value @a value, throws if invalid
|
||||
void validate_value(const item_value &value) const;
|
||||
|
||||
/// @brief Validate value @a value and return potential error in @a ec
|
||||
bool validate_value(const item_value &value, std::error_code &ec) const noexcept;
|
||||
|
||||
/// @brief Validate value @a value and return potential error in @a ec
|
||||
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; ///< 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::vector<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;
|
||||
}
|
||||
|
||||
/// @brief Add item_validator @a v to the list of item validators
|
||||
void add_item_validator(item_validator &&v);
|
||||
|
||||
/// @brief Return the item_validator for item @a item_name, may return nullptr
|
||||
[[nodiscard]] const item_validator *get_validator_for_item(std::string_view item_name) const;
|
||||
|
||||
/// @brief Return the item_validator for an item that has as alias name @a item_name, may return nullptr
|
||||
[[nodiscard]] 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; ///< 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:
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*/
|
||||
validator()
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a new validator object
|
||||
*
|
||||
* @param is The data to parse
|
||||
*/
|
||||
validator(std::istream &is)
|
||||
: m_audit_conform("audit_conform")
|
||||
{
|
||||
parse(is);
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
~validator() = default;
|
||||
|
||||
/// default copy constructor
|
||||
validator(const validator &rhs) = default;
|
||||
|
||||
/// @brief move constructor
|
||||
validator(validator &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
/// default copy assignment
|
||||
validator &operator=(validator rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap the two validators
|
||||
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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] std::vector<const link_validator *> get_links_for_child(std::string_view category) const;
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(validation_error err, bool fatal = true) const
|
||||
{
|
||||
report_error(make_error_code(err), fatal);
|
||||
}
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(std::error_code ec, bool fatal = true) const;
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(validation_error err, std::string value, std::string_view category,
|
||||
std::string_view item, bool fatal = true) const
|
||||
{
|
||||
report_error(make_error_code(err), value, category, item, fatal);
|
||||
}
|
||||
|
||||
/// @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
|
||||
{
|
||||
report_error(ec, "", category, item, fatal);
|
||||
}
|
||||
|
||||
/// @brief Bottleneck function to report an error in validation
|
||||
void report_error(std::error_code ec, std::string value, 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
|
||||
[[nodiscard]] 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:
|
||||
[[nodiscard]] item_validator *get_validator_for_item(std::string_view name) const;
|
||||
|
||||
category m_audit_conform;
|
||||
|
||||
bool m_strict = false;
|
||||
std::set<type_validator> m_type_validators;
|
||||
std::set<category_validator> m_category_validators;
|
||||
std::vector<link_validator> m_link_validators;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Validators are globally unique objects, use the validator_factory
|
||||
* class to construct them. This class is a singleton.
|
||||
*/
|
||||
|
||||
class validator_factory
|
||||
{
|
||||
public:
|
||||
/// @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
|
||||
/// and the dictionary name may be a set of dictionaries separated by comma
|
||||
const validator *get(std::string_view dictionary_name);
|
||||
|
||||
/// @brief Return validator with info recorded in @a audit_conform
|
||||
const validator &operator[](const category &audit_conform);
|
||||
|
||||
/// @brief Return the single-file validator with name @a dictionary_name
|
||||
/// and the dictionary name may be a set of dictionaries separated by comma
|
||||
const validator &operator[](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)
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
return m_validators.emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
// #if __cplusplus >= 202302L
|
||||
// /// @brief Return validator with info recorded in @a audit_conform
|
||||
// static validator &operator[](const category &audit_conform)
|
||||
// {
|
||||
// return instance()[audit_conform];
|
||||
// }
|
||||
|
||||
// /// @brief Return the single-file validator with name @a dictionary_name
|
||||
// /// and the dictionary name may be a set of dictionaries separated by comma
|
||||
// static validator &operator[](std::string_view dict)
|
||||
// {
|
||||
// return instance()[dict];
|
||||
// }
|
||||
// #endif
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace cif
|
||||
@@ -1,10 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libcif++
|
||||
Description: C++ library for the manipulation of mmCIF files.
|
||||
Version: @PACKAGE_VERSION@
|
||||
Libs: -L${libdir} -lcif++
|
||||
Cflags: -I${includedir}
|
||||
316
pcre2-simple/CMakeLists.txt
Normal file
316
pcre2-simple/CMakeLists.txt
Normal file
@@ -0,0 +1,316 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2025 Maarten L. Hekkelman
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# A simplified wrapper CMakeLists.txt file for PCRE2
|
||||
#
|
||||
# This will generate an OBJECT library so it can be linked into another library
|
||||
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
project(pcre2s VERSION 1.0.0 LANGUAGES C CXX)
|
||||
|
||||
# The original code:
|
||||
|
||||
file(DOWNLOAD https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.46/pcre2-10.46.tar.gz
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2-code.tgz
|
||||
EXPECTED_HASH SHA256=8d28d7f2c3b970c3a4bf3776bcbb5adfc923183ce74bc8df1ebaad8c1985bd07)
|
||||
file(ARCHIVE_EXTRACT INPUT ${CMAKE_CURRENT_BINARY_DIR}/pcre2-code.tgz
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(PCRE2_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/pcre2-10.46)
|
||||
set(PCRE2_MAJOR 10)
|
||||
set(PCRE2_MINOR 46)
|
||||
set(PCRE2_VERSION "${PCRE2_MAJOR}.${PCRE2_MINOR}")
|
||||
set(PCRE2_DATE "2024-06-09")
|
||||
|
||||
# Some needed configuration options
|
||||
|
||||
# option(PCRE2_BUILD_PCRE2_8 "Build 8 bit PCRE2 library" ON)
|
||||
# option(PCRE2_BUILD_PCRE2_16 "Build 16 bit PCRE2 library" OFF)
|
||||
# option(PCRE2_BUILD_PCRE2_32 "Build 32 bit PCRE2 library" OFF)
|
||||
|
||||
option(PCRE2_STATIC_PIC "Build the static library with the option position independent code enabled." OFF)
|
||||
|
||||
set(PCRE2_NEWLINE "LF" CACHE STRING "What to recognize as a newline (one of CR, LF, CRLF, ANY, ANYCRLF, NUL)." FORCE)
|
||||
set_property(CACHE PCRE2_NEWLINE PROPERTY STRINGS "CR" "LF" "CRLF" "ANY" "ANYCRLF" "NUL")
|
||||
|
||||
set(PCRE2_LINK_SIZE "2" CACHE STRING "Internal link size (2, 3 or 4 allowed). See LINK_SIZE in config.h.in for details.")
|
||||
set_property(CACHE PCRE2_LINK_SIZE PROPERTY STRINGS "2" "3" "4")
|
||||
|
||||
set(PCRE2_PARENS_NEST_LIMIT "250" CACHE STRING "Default nested parentheses limit. See PARENS_NEST_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_HEAP_LIMIT "20000000" CACHE STRING "Default limit on heap memory (kibibytes). See HEAP_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_MAX_VARLOOKBEHIND "255" CACHE STRING "Default limit on variable lookbehinds.")
|
||||
set(PCRE2_MATCH_LIMIT "10000000" CACHE STRING "Default limit on internal looping. See MATCH_LIMIT in config.h.in for details.")
|
||||
set(PCRE2_MATCH_LIMIT_DEPTH "MATCH_LIMIT" CACHE STRING "Default limit on internal depth of search. See MATCH_LIMIT_DEPTH in config.h.in for details.")
|
||||
set(PCRE2GREP_BUFSIZE "20480" CACHE STRING "Buffer starting size parameter for pcre2grep. See PCRE2GREP_BUFSIZE in config.h.in for details.")
|
||||
set(PCRE2GREP_MAX_BUFSIZE "1048576" CACHE STRING "Buffer maximum size parameter for pcre2grep. See PCRE2GREP_MAX_BUFSIZE in config.h.in for details.")
|
||||
set(PCRE2_SUPPORT_JIT OFF CACHE BOOL "Enable support for Just-in-time compiling.")
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES Linux|NetBSD)
|
||||
set(PCRE2_SUPPORT_JIT_SEALLOC OFF CACHE BOOL "Enable SELinux compatible execmem allocator in JIT (experimental).")
|
||||
else()
|
||||
set(PCRE2_SUPPORT_JIT_SEALLOC IGNORE)
|
||||
endif()
|
||||
|
||||
set(PCRE2GREP_SUPPORT_JIT ON CACHE BOOL "Enable use of Just-in-time compiling in pcre2grep.")
|
||||
set(PCRE2GREP_SUPPORT_CALLOUT ON CACHE BOOL "Enable callout string support in pcre2grep.")
|
||||
set(PCRE2GREP_SUPPORT_CALLOUT_FORK ON CACHE BOOL "Enable callout string fork support in pcre2grep.")
|
||||
set(PCRE2_SUPPORT_UNICODE ON CACHE BOOL "Enable support for Unicode and UTF-8/UTF-16/UTF-32 encoding.")
|
||||
set(PCRE2_SUPPORT_BSR_ANYCRLF OFF CACHE BOOL "ON=Backslash-R matches only LF CR and CRLF, OFF=Backslash-R matches all Unicode Linebreaks")
|
||||
set(PCRE2_NEVER_BACKSLASH_C OFF CACHE BOOL "If ON, backslash-C (upper case C) is locked out.")
|
||||
set(PCRE2_SUPPORT_VALGRIND OFF CACHE BOOL "Enable Valgrind support.")
|
||||
|
||||
if(MINGW)
|
||||
option(NON_STANDARD_LIB_PREFIX "ON=Shared libraries built in mingw will be named pcre2.dll, etc., instead of libpcre2.dll, etc." OFF)
|
||||
option(NON_STANDARD_LIB_SUFFIX "ON=Shared libraries built in mingw will be named libpcre2-0.dll, etc., instead of libpcre2.dll, etc." OFF)
|
||||
endif()
|
||||
|
||||
#
|
||||
|
||||
set(NEWLINE_DEFAULT "")
|
||||
|
||||
if(PCRE2_NEWLINE STREQUAL "CR")
|
||||
set(NEWLINE_DEFAULT "1")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "LF")
|
||||
set(NEWLINE_DEFAULT "2")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "CRLF")
|
||||
set(NEWLINE_DEFAULT "3")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "ANY")
|
||||
set(NEWLINE_DEFAULT "4")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "ANYCRLF")
|
||||
set(NEWLINE_DEFAULT "5")
|
||||
elseif(PCRE2_NEWLINE STREQUAL "NUL")
|
||||
set(NEWLINE_DEFAULT "6")
|
||||
else()
|
||||
message(FATAL_ERROR "The PCRE2_NEWLINE variable must be set to one of the following values: \"LF\", \"CR\", \"CRLF\", \"ANY\", \"ANYCRLF\".")
|
||||
endif()
|
||||
|
||||
# Some tests
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckIncludeFile)
|
||||
|
||||
check_include_file(assert.h HAVE_ASSERT_H)
|
||||
check_include_file(dirent.h HAVE_DIRENT_H)
|
||||
check_include_file(sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
check_include_file(windows.h HAVE_WINDOWS_H)
|
||||
|
||||
check_symbol_exists(bcopy "strings.h" HAVE_BCOPY)
|
||||
check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
|
||||
check_symbol_exists(memmove "string.h" HAVE_MEMMOVE)
|
||||
check_symbol_exists(secure_getenv "stdlib.h" HAVE_SECURE_GETENV)
|
||||
check_symbol_exists(strerror "string.h" HAVE_STRERROR)
|
||||
|
||||
check_c_source_compiles(
|
||||
"int main(void) { char buf[128] __attribute__((uninitialized)); (void)buf; return 0; }"
|
||||
HAVE_ATTRIBUTE_UNINITIALIZED
|
||||
)
|
||||
|
||||
check_c_source_compiles(
|
||||
[=[
|
||||
extern __attribute__ ((visibility ("default"))) int f(void);
|
||||
int main(void) { return f(); }
|
||||
int f(void) { return 42; }
|
||||
]=]
|
||||
HAVE_VISIBILITY
|
||||
)
|
||||
|
||||
if(HAVE_VISIBILITY)
|
||||
set(PCRE2_EXPORT [=[__attribute__ ((visibility ("default")))]=])
|
||||
else()
|
||||
set(PCRE2_EXPORT)
|
||||
endif()
|
||||
|
||||
check_c_source_compiles("int main(void) { __assume(1); return 0; }" HAVE_BUILTIN_ASSUME)
|
||||
|
||||
check_c_source_compiles(
|
||||
[=[
|
||||
#include <stddef.h>
|
||||
int main(void) { int a,b; size_t m; __builtin_mul_overflow(a,b,&m); return 0; }
|
||||
]=]
|
||||
HAVE_BUILTIN_MUL_OVERFLOW
|
||||
)
|
||||
|
||||
check_c_source_compiles(
|
||||
"int main(int c, char *v[]) { if (c) __builtin_unreachable(); return (int)(*v[0]); }"
|
||||
HAVE_BUILTIN_UNREACHABLE
|
||||
)
|
||||
|
||||
# # Check whether Intel CET is enabled, and if so, adjust compiler flags. This
|
||||
# # code was written by PH, trying to imitate the logic from the autotools
|
||||
# # configuration.
|
||||
|
||||
# check_c_source_compiles(
|
||||
# [=[
|
||||
# #ifndef __CET__
|
||||
# #error CET is not enabled
|
||||
# #endif
|
||||
# int main() { return 0; }
|
||||
# ]=]
|
||||
# INTEL_CET_ENABLED
|
||||
# )
|
||||
|
||||
# if(INTEL_CET_ENABLED)
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mshstk")
|
||||
# endif()
|
||||
|
||||
# Set up some dependencies first
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_chartables.c.dist
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2_chartables.c
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/config-cmake.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/config.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/pcre2.h
|
||||
@ONLY
|
||||
)
|
||||
|
||||
# Define our library
|
||||
|
||||
list(APPEND PCRE2_HEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/interface/pcre2.h)
|
||||
|
||||
list(APPEND PCRE2_SOURCES
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_auto_possess.c
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pcre2_chartables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_chkdint.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_compile.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_compile_class.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_config.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_context.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_convert.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_dfa_match.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_error.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_extuni.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_find_bracket.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_jit_compile.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_maketables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_match.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_match_data.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_newline.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_ord2utf.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_pattern_info.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_script_run.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_serialize.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_string_utils.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_study.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_substitute.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_substring.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_tables.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_ucd.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_valid_utf.c
|
||||
${PCRE2_SOURCE_DIR}/src/pcre2_xclass.c
|
||||
)
|
||||
|
||||
add_library(pcre2s OBJECT)
|
||||
|
||||
target_sources(pcre2s
|
||||
PRIVATE ${PCRE2_SOURCES}
|
||||
PUBLIC
|
||||
FILE_SET pcre2_headers TYPE HEADERS
|
||||
BASE_DIRS ${PCRE2_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/interface
|
||||
FILES ${PCRE2_HEADERS}
|
||||
)
|
||||
|
||||
target_compile_definitions(pcre2s PUBLIC PCRE2_CODE_UNIT_WIDTH=8 HAVE_CONFIG_H)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(pcre2s PUBLIC PCRE2_STATIC)
|
||||
endif()
|
||||
|
||||
target_include_directories(pcre2s PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/interface ${PCRE2_SOURCE_DIR}/src)
|
||||
|
||||
if(PCRE2_STATIC_PIC)
|
||||
set_target_properties(pcre2s PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||
endif()
|
||||
|
||||
# # Installation and config files
|
||||
|
||||
# include(CMakePackageConfigHelpers)
|
||||
# include(GenerateExportHeader)
|
||||
|
||||
# # Install rules
|
||||
# install(TARGETS pcre2s
|
||||
# EXPORT pcre2s
|
||||
# FILE_SET pcre2_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# if(MSVC AND BUILD_SHARED_LIBS)
|
||||
# install(
|
||||
# FILES $<TARGET_PDB_FILE:pcre2s>
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
# OPTIONAL)
|
||||
# endif()
|
||||
|
||||
# install(EXPORT pcre2s
|
||||
# NAMESPACE pcre2s::
|
||||
# FILE "pcre2s-targets.cmake"
|
||||
# DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# configure_package_config_file(
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/pcre2s-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config.cmake
|
||||
# INSTALL_DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# install(
|
||||
# FILES "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config.cmake"
|
||||
# "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config-version.cmake"
|
||||
# DESTINATION lib/cmake/pcre2s)
|
||||
|
||||
# set_target_properties(
|
||||
# pcre2s
|
||||
# PROPERTIES VERSION ${PCRE2_VERSION}
|
||||
# SOVERSION ${PCRE2_VERSION}
|
||||
# INTERFACE_pcre2s_MAJOR_VERSION ${PCRE2_MAJOR})
|
||||
|
||||
# set_property(
|
||||
# TARGET pcre2s
|
||||
# APPEND
|
||||
# PROPERTY COMPATIBLE_INTERFACE_STRING pcre2s_MAJOR_VERSION)
|
||||
|
||||
# write_basic_package_version_file(
|
||||
# "${CMAKE_CURRENT_BINARY_DIR}/pcre2s/pcre2s-config-version.cmake"
|
||||
# VERSION "${PCRE2_VERSION}"
|
||||
# COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
# # Testing
|
||||
|
||||
# if(PROJECT_IS_TOP_LEVEL)
|
||||
# include(CTest)
|
||||
|
||||
# if(BUILD_TESTING)
|
||||
# add_subdirectory(test)
|
||||
# endif()
|
||||
# endif()
|
||||
2807
rsrc/ccd-subset.cif
Normal file
2807
rsrc/ccd-subset.cif
Normal file
File diff suppressed because it is too large
Load Diff
1871
rsrc/curves.xml
1871
rsrc/curves.xml
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user