forked from boostorg/container_hash
Compare commits
590 Commits
boost-1.47
...
feature/gh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d8b8ac2b9 | ||
|
|
1e1cf6c46e | ||
|
|
88aacb6d46 | ||
|
|
0a000167b7 | ||
|
|
d8f1075080 | ||
|
|
b8179488b2 | ||
|
|
edd436231a | ||
|
|
d56fc37fe5 | ||
|
|
fa6601f974 | ||
|
|
89e5b98f6b | ||
|
|
1193ed067c | ||
|
|
f85cb77bd3 | ||
|
|
7d68e5f1d2 | ||
|
|
3c9ce69f92 | ||
|
|
aa2e8b3674 | ||
|
|
c3cb5896fc | ||
|
|
58cd5e35b1 | ||
|
|
386d007088 | ||
|
|
b8090f9b87 | ||
|
|
a5c2949670 | ||
|
|
b16f42ef10 | ||
|
|
de85b0c248 | ||
|
|
583e14413c | ||
|
|
ef914e1b34 | ||
|
|
ee5285bfa6 | ||
|
|
0a9803dffe | ||
|
|
881448f75e | ||
|
|
c5b1f4894c | ||
|
|
6d214eb776 | ||
|
|
b0d3107b99 | ||
|
|
e2446b187e | ||
|
|
1dd2f73866 | ||
|
|
1278f1c2b5 | ||
|
|
067f636d6c | ||
|
|
338c053889 | ||
|
|
94d4f7cb88 | ||
|
|
6957a20ab1 | ||
|
|
28cc18a4bc | ||
|
|
7288df8bee | ||
|
|
5c2d5e5b36 | ||
|
|
db8743e1c3 | ||
|
|
48a306dcf2 | ||
|
|
f6279a0615 | ||
|
|
41746c0bdb | ||
|
|
07a0910640 | ||
|
|
4c32071739 | ||
|
|
30c05c93b1 | ||
|
|
197f75845c | ||
|
|
bf8ad2c0ee | ||
|
|
fef60938e5 | ||
|
|
f04d866fa7 | ||
|
|
17201433f8 | ||
|
|
9d09674f08 | ||
|
|
f8ecd66820 | ||
|
|
565bac8d31 | ||
|
|
b8496de2f2 | ||
|
|
641a59342e | ||
|
|
226eb066e9 | ||
|
|
d9cb23d96a | ||
|
|
bd8a5cb867 | ||
|
|
b43ce472fa | ||
|
|
e798972130 | ||
|
|
ebb49fa459 | ||
|
|
1e1c0ea38c | ||
|
|
e62a268566 | ||
|
|
ad89c02360 | ||
|
|
64948e5f57 | ||
|
|
1958e96561 | ||
|
|
4a7287d371 | ||
|
|
5638134081 | ||
|
|
7c49f0bfb1 | ||
|
|
9ae5790657 | ||
|
|
8ce81c361d | ||
|
|
4315faf470 | ||
|
|
eb049e0cae | ||
|
|
6373656710 | ||
|
|
ec1503bbc8 | ||
|
|
ee064dc7f8 | ||
|
|
b505e06b3c | ||
|
|
6075f3e1f5 | ||
|
|
0bfeabfd63 | ||
|
|
758596533d | ||
|
|
640bd48f51 | ||
|
|
b25fd745ca | ||
|
|
6fe3469a8b | ||
|
|
c07630ac60 | ||
|
|
45270ae11e | ||
|
|
5bef4901b9 | ||
|
|
d724bcd0ef | ||
|
|
ceb8303601 | ||
|
|
cf87e304f6 | ||
|
|
4d9f7b8931 | ||
|
|
2f4efbced4 | ||
|
|
bf7a78594e | ||
|
|
c0c70e5b3e | ||
|
|
891a64d45d | ||
|
|
08d69c31b1 | ||
|
|
6526b24900 | ||
|
|
1a8dca4f2c | ||
|
|
8761157a19 | ||
|
|
f2b2ef4ebe | ||
|
|
30560ada18 | ||
|
|
c61a4f691e | ||
|
|
fe28cdbd1f | ||
|
|
f98b943585 | ||
|
|
4aeb7b2285 | ||
|
|
e310932a9c | ||
|
|
558d0ead17 | ||
|
|
d6905ab159 | ||
|
|
251894540d | ||
|
|
ffadafa0c1 | ||
|
|
ce166d1030 | ||
|
|
8ab83c1cd4 | ||
|
|
16546190f6 | ||
|
|
5e26a3b807 | ||
|
|
bd5b7a359c | ||
|
|
f5f5476dcc | ||
|
|
228f7db5d3 | ||
|
|
f50b914456 | ||
|
|
c134ca39e9 | ||
|
|
f51f68fe93 | ||
|
|
0865c1d230 | ||
|
|
0d2266decb | ||
|
|
3c9ba89cf2 | ||
|
|
20ee3b60fd | ||
|
|
bdd3dcf944 | ||
|
|
018fc4e1fa | ||
|
|
7568176bfa | ||
|
|
08864cd1e9 | ||
|
|
5a616b9b54 | ||
|
|
16fb4cc749 | ||
|
|
0171246a61 | ||
|
|
29c85559e4 | ||
|
|
412bd51449 | ||
|
|
87196a503e | ||
|
|
df1671d593 | ||
|
|
1996cf36c1 | ||
|
|
a4b2048a29 | ||
|
|
85f9f8a97a | ||
|
|
e92eae9eb2 | ||
|
|
8a1335458a | ||
|
|
f7e537d1a1 | ||
|
|
607b73f1e0 | ||
|
|
789261c68c | ||
|
|
29ee19ee7f | ||
|
|
8bb7d43646 | ||
|
|
a426a1939f | ||
|
|
034b81594d | ||
|
|
75ef5a14f5 | ||
|
|
b5bb4405a9 | ||
|
|
d43ae22ab4 | ||
|
|
e061b3c4c0 | ||
|
|
9035aa5485 | ||
|
|
3ae0aea360 | ||
|
|
fc249670c0 | ||
|
|
30ffbf9f16 | ||
|
|
c36319c878 | ||
|
|
a2aaefc71a | ||
|
|
e3cd2d7de8 | ||
|
|
4571ec190a | ||
|
|
478730107d | ||
|
|
adcf81c732 | ||
|
|
75a37c2616 | ||
|
|
c01270b0bd | ||
|
|
123875dc83 | ||
|
|
ed235989ef | ||
|
|
bf0a77f062 | ||
|
|
79fff9e1ea | ||
|
|
6757bd4f00 | ||
|
|
20c03417b0 | ||
|
|
60be3b131e | ||
|
|
b148e34818 | ||
|
|
e391cf6841 | ||
|
|
b4e0643ecd | ||
|
|
dc9a6e3e68 | ||
|
|
f47772f6f4 | ||
|
|
c1e5427e8d | ||
|
|
866cff96e5 | ||
|
|
9d4971b81d | ||
|
|
4b5a1cf0f2 | ||
|
|
435ff87fd7 | ||
|
|
58934422fb | ||
|
|
3fe7bbdd6c | ||
|
|
fba63d4379 | ||
|
|
8adcaffcc2 | ||
|
|
eee5e3b7fd | ||
|
|
e98cae2c31 | ||
|
|
40ec854466 | ||
|
|
c5b63d2cbb | ||
|
|
882192ea3a | ||
|
|
03123685c4 | ||
|
|
95fe6bd9a3 | ||
|
|
6cb735fda6 | ||
|
|
10b4ad598f | ||
|
|
ce734b435e | ||
|
|
e387d14d36 | ||
|
|
1fb41a72ef | ||
|
|
c399cf6a38 | ||
|
|
30c32bb3df | ||
|
|
d1b2640dff | ||
|
|
f722383d1d | ||
|
|
21530840e1 | ||
|
|
d0c1e36fc1 | ||
|
|
e00f53a69c | ||
|
|
b0c9904414 | ||
|
|
2d557a746d | ||
|
|
417180dd03 | ||
|
|
5ba74cd3a9 | ||
|
|
c14d3a1e2b | ||
|
|
a3cac265b1 | ||
|
|
c28d0b813b | ||
|
|
e39bf42dfc | ||
|
|
58502fddca | ||
|
|
5701dd3119 | ||
|
|
53c12550fa | ||
|
|
561cc5d010 | ||
|
|
bdf4bfe910 | ||
|
|
06e1b613f0 | ||
|
|
12be64b71e | ||
|
|
4e2811c4e1 | ||
|
|
2dc57b745f | ||
|
|
de618bf974 | ||
|
|
87c9eefe6e | ||
|
|
98bbd2ba56 | ||
|
|
08ea1677be | ||
|
|
3d3350646f | ||
|
|
884ce4b708 | ||
|
|
db1e23b611 | ||
|
|
5ddcd7c8e7 | ||
|
|
0e2e911df5 | ||
|
|
b3c9b35a13 | ||
|
|
c9c77cb104 | ||
|
|
873a60d009 | ||
|
|
b8d315fac5 | ||
|
|
e0e86a1413 | ||
|
|
866bd60dd3 | ||
|
|
6781cff622 | ||
|
|
dd605d0d1c | ||
|
|
dd172db079 | ||
|
|
e04ca1f442 | ||
|
|
0eada2ae93 | ||
|
|
943ef0ab82 | ||
|
|
14f8934bff | ||
|
|
f08204e29a | ||
|
|
7ad0365048 | ||
|
|
b3e424b650 | ||
|
|
d2986d9a64 | ||
|
|
000276988f | ||
|
|
355603c0c2 | ||
|
|
33cd0a5964 | ||
|
|
fc11122353 | ||
|
|
cb233af718 | ||
|
|
8d820ee7d0 | ||
|
|
3800d712d5 | ||
|
|
dee871f45c | ||
|
|
143a55ea3b | ||
|
|
4ab431f12f | ||
|
|
773307fe1c | ||
|
|
06db43a56a | ||
|
|
5906cba1a0 | ||
|
|
b2222c2755 | ||
|
|
6600a26460 | ||
|
|
c95e02fe85 | ||
|
|
334eac8166 | ||
|
|
21dbdb9b47 | ||
|
|
74f9abe52c | ||
|
|
37f3e6fcb7 | ||
|
|
301c76646c | ||
|
|
a67e350fd9 | ||
|
|
2d23e7e056 | ||
|
|
9bdebb3df4 | ||
|
|
e9ffeceeab | ||
|
|
4a685b2b16 | ||
|
|
8315ec2ba7 | ||
|
|
1a4888cdb4 | ||
|
|
9e938aca41 | ||
|
|
7abcf22762 | ||
|
|
dbb410b7ef | ||
|
|
cab5c6c8d7 | ||
|
|
526e4d472d | ||
|
|
fca37b0d43 | ||
|
|
0a795c62a3 | ||
|
|
4ff953b568 | ||
|
|
cfbc94b128 | ||
|
|
f0bed67909 | ||
|
|
1c27af1e2e | ||
|
|
ebac66dc1e | ||
|
|
f0e75dd010 | ||
|
|
5959103346 | ||
|
|
3c3948ccdb | ||
|
|
998d8da8c8 | ||
|
|
bdc2840738 | ||
|
|
56f790d896 | ||
|
|
355c1cd7a4 | ||
|
|
c9b2d6fc90 | ||
|
|
2424ada9f9 | ||
|
|
faea988310 | ||
|
|
64c367734d | ||
|
|
6d84f9a41b | ||
|
|
aaa1f441ac | ||
|
|
3487450f62 | ||
|
|
8f163568f4 | ||
|
|
a4cbaa95b3 | ||
|
|
6ffc99adb7 | ||
|
|
bb99a2b1ae | ||
|
|
f05e8840d2 | ||
|
|
dff8843bb2 | ||
|
|
15ae39e176 | ||
|
|
39e4a4f184 | ||
|
|
88fbad7438 | ||
|
|
0737c56fec | ||
|
|
2b9251069f | ||
|
|
a63c85007f | ||
|
|
7a29dee42a | ||
|
|
a0a6fa0616 | ||
|
|
fe66085fbc | ||
|
|
24598bd45f | ||
|
|
7f2a43226e | ||
|
|
668f28660d | ||
|
|
9348a89fb4 | ||
|
|
3f2612d36e | ||
|
|
3cf502b34c | ||
|
|
b2e3beea3f | ||
|
|
d308495a67 | ||
|
|
00c837d523 | ||
|
|
415f2fafe2 | ||
|
|
9bbedce029 | ||
|
|
2fc970b6ae | ||
|
|
4e11c855cb | ||
|
|
bd379e1a46 | ||
|
|
b201ff97a8 | ||
|
|
e89fe04479 | ||
|
|
7ce3f759ec | ||
|
|
917ac6a88a | ||
|
|
9782883434 | ||
|
|
f0ef7b8e84 | ||
|
|
21f2b5e1db | ||
|
|
b55fbc9252 | ||
|
|
a0465807c7 | ||
|
|
e03c31c9bc | ||
|
|
c4d9a95b82 | ||
|
|
5f5a5d0648 | ||
|
|
fd2781afc9 | ||
|
|
d045cf2ecb | ||
|
|
b4e4bf577f | ||
|
|
310ca091a2 | ||
|
|
e69c4c830e | ||
|
|
aaf0d2525f | ||
|
|
171c012d47 | ||
|
|
e0331c0bd4 | ||
|
|
e30bbab19f | ||
|
|
1818113f4c | ||
|
|
8a7fc581ed | ||
|
|
5048576921 | ||
|
|
5f858645a0 | ||
|
|
fd310d2706 | ||
|
|
90a0e36638 | ||
|
|
1ce57acc41 | ||
|
|
81a65eb01c | ||
|
|
9fbda1a98a | ||
|
|
62f29ea201 | ||
|
|
f054fe932f | ||
|
|
83a874ed49 | ||
|
|
59f9543c10 | ||
|
|
a6da082784 | ||
|
|
e73522f296 | ||
|
|
3e8dbcbcc5 | ||
|
|
601b8d0378 | ||
|
|
60f5e0d393 | ||
|
|
e67d20d1c3 | ||
|
|
8c9bd9eccd | ||
|
|
88d1c5c395 | ||
|
|
957818bb97 | ||
|
|
21f32243a8 | ||
|
|
9fafa9e37b | ||
|
|
cc541b71c5 | ||
|
|
d20a68efdb | ||
|
|
d45e3986f3 | ||
|
|
1e263669cb | ||
|
|
8ea85f5ad2 | ||
|
|
e01239286c | ||
|
|
17809c3cbc | ||
|
|
8963c38770 | ||
|
|
0ad83592af | ||
|
|
cb6a0246df | ||
|
|
27b2732916 | ||
|
|
4d9f438823 | ||
|
|
ddc05d17df | ||
|
|
b9ae7e7fb6 | ||
|
|
42bb81befa | ||
|
|
f81ee167c5 | ||
|
|
5c4edf4d7d | ||
|
|
b5c3b5d00a | ||
|
|
def7a785a5 | ||
|
|
3521c417b5 | ||
|
|
8b77644ea0 | ||
|
|
d41ead127d | ||
|
|
f460c21dd0 | ||
|
|
c3e070a244 | ||
|
|
9d5a16c288 | ||
|
|
e80c0c84bb | ||
|
|
c64e516518 | ||
|
|
b40b795572 | ||
|
|
8d784ed76d | ||
|
|
6ca88a8146 | ||
|
|
53fbb04e88 | ||
|
|
c7fc03d2b9 | ||
|
|
fc3e0bff4f | ||
|
|
376000169c | ||
|
|
bc09240437 | ||
|
|
dfa8fa5d91 | ||
|
|
8098c5b302 | ||
|
|
7f3a063064 | ||
|
|
d803b3bdc0 | ||
|
|
170558e4fa | ||
|
|
4a4cb9f7a4 | ||
|
|
7a6c0f20d5 | ||
|
|
8bdfb0cf90 | ||
|
|
3ee110f82c | ||
|
|
f7ad177dae | ||
|
|
955cdaed3d | ||
|
|
9c82e48bc9 | ||
|
|
1b3bed82aa | ||
|
|
6dd58674aa | ||
|
|
4a530f85d0 | ||
|
|
babb4f8f73 | ||
|
|
01b81754cf | ||
|
|
5210c845f5 | ||
|
|
4b99dbdb64 | ||
|
|
2cdf1c7d9e | ||
|
|
a489b08e27 | ||
|
|
b9c3499f45 | ||
|
|
ab9f98455a | ||
|
|
7159a86166 | ||
|
|
d0ee8e13bd | ||
|
|
98140b7373 | ||
|
|
e2d7225f57 | ||
|
|
36545f62cf | ||
|
|
618fc6d074 | ||
|
|
c2764e22a7 | ||
|
|
9148cde86f | ||
|
|
5a811f25aa | ||
|
|
b790429529 | ||
|
|
1e6cefbfeb | ||
|
|
b0ddb244be | ||
|
|
3dfdb19bfd | ||
|
|
f184dd019f | ||
|
|
0361d416b7 | ||
|
|
7838c3678f | ||
|
|
5856bff480 | ||
|
|
468516ed71 | ||
|
|
c8d8c7edd4 | ||
|
|
e76c3dc1a2 | ||
|
|
8171dbb465 | ||
|
|
99d4923496 | ||
|
|
29865a5bca | ||
|
|
8b05fd5fdf | ||
|
|
ada1369a14 | ||
|
|
4977373964 | ||
|
|
8b19e7eaa0 | ||
|
|
75ae18ef54 | ||
|
|
754d5f535e | ||
|
|
ebc607d44e | ||
|
|
549196ca7d | ||
|
|
f2761964bd | ||
|
|
41487a2e8c | ||
|
|
ca52df8a05 | ||
|
|
b39e6e96f0 | ||
|
|
8266a55b26 | ||
|
|
711b2b6d69 | ||
|
|
d888097468 | ||
|
|
23f1db7729 | ||
|
|
35ef2502d5 | ||
|
|
aa3ab0790a | ||
|
|
6c3e20ac18 | ||
|
|
97cc6fbbc1 | ||
|
|
309d17f387 | ||
|
|
928767f2bd | ||
|
|
bb2a91bf47 | ||
|
|
496bf24900 | ||
|
|
09f197abf6 | ||
|
|
582671543b | ||
|
|
6157ad5267 | ||
|
|
844d9758bd | ||
|
|
7dbc8b593f | ||
|
|
3c22fce14c | ||
|
|
b066a9c509 | ||
|
|
74603822f4 | ||
|
|
998f714f8f | ||
|
|
614feab582 | ||
|
|
999c2d5963 | ||
|
|
c3e54942e8 | ||
|
|
10c83e95d9 | ||
|
|
734eb87d2a | ||
|
|
af17fa46fb | ||
|
|
e26c102522 | ||
|
|
378007cf94 | ||
|
|
61df9052e1 | ||
|
|
dea8d12a04 | ||
|
|
1870aa9534 | ||
|
|
b1ca4cf0d4 | ||
|
|
0d6cee7e64 | ||
|
|
9dad407f06 | ||
|
|
7d148af8d2 | ||
|
|
4aec4be0ed | ||
|
|
bb8ebafca1 | ||
|
|
7e162c4f03 | ||
|
|
061e0d9d6d | ||
|
|
cc091d5d98 | ||
|
|
e5f3356742 | ||
|
|
9721f9c764 | ||
|
|
713b688159 | ||
|
|
8a8ab9ec70 | ||
|
|
13a86a7a26 | ||
|
|
0e0906b0a4 | ||
|
|
67ad8c2151 | ||
|
|
be4292842d | ||
|
|
473b1da8de | ||
|
|
8afae2e762 | ||
|
|
03380087a9 | ||
|
|
9dcc33ab1b | ||
|
|
d8adc5aa24 | ||
|
|
7f7ecfc717 | ||
|
|
dfd48ef498 | ||
|
|
a2756e75e8 | ||
|
|
9c37cd46b1 | ||
|
|
acf1f3bc48 | ||
|
|
b856e6308d | ||
|
|
b4b4a559e0 | ||
|
|
853a713cf2 | ||
|
|
043571dabf | ||
|
|
7b2f73c225 | ||
|
|
eec47991f9 | ||
|
|
f1de575546 | ||
|
|
05f16beaf0 | ||
|
|
34a6eebf7e | ||
|
|
9119b2646b | ||
|
|
12f49f7c53 | ||
|
|
0757aea7cb | ||
|
|
92fe67f714 | ||
|
|
73b507c728 | ||
|
|
330040aea9 | ||
|
|
5ebe3ad87d | ||
|
|
411ac66581 | ||
|
|
75bcfdeb36 | ||
|
|
af3a31090c | ||
|
|
dfe0ad3a60 | ||
|
|
806abd0ddf | ||
|
|
c409903f5e | ||
|
|
8ef04ed807 | ||
|
|
6be66ba092 | ||
|
|
033ef4b507 | ||
|
|
0d4c55854b | ||
|
|
18b143cad1 | ||
|
|
8bc410f571 | ||
|
|
68f0d9bc6b | ||
|
|
5611f4238e | ||
|
|
346e62f53f | ||
|
|
963d06acb8 | ||
|
|
f3229da836 | ||
|
|
441cea413d | ||
|
|
4f3265079d | ||
|
|
98953a28c7 | ||
|
|
c3d01123fa | ||
|
|
f98a942e2e | ||
|
|
9a38ebf8c3 | ||
|
|
a6f8c51afb | ||
|
|
903b1e409e | ||
|
|
eb040cb89b | ||
|
|
d92209d725 | ||
|
|
58e42260d5 | ||
|
|
56293f4313 | ||
|
|
335930c652 | ||
|
|
da096ddf8c | ||
|
|
8c0e9a2b09 | ||
|
|
664522596f | ||
|
|
ce885af9b0 | ||
|
|
9e641187c6 | ||
|
|
7dc95d044d | ||
|
|
ad614b3d5f | ||
|
|
ed598f865e | ||
|
|
482f038837 | ||
|
|
a2e947588d | ||
|
|
982b350d71 | ||
|
|
577054de93 | ||
|
|
fc3b3863b4 | ||
|
|
906f632706 | ||
|
|
bbfb6fd32c | ||
|
|
38d131c158 | ||
|
|
2553a5fbdc |
69
.appveyor.yml
Normal file
69
.appveyor.yml
Normal file
@@ -0,0 +1,69 @@
|
||||
# Copyright 2017 Daniel James
|
||||
# Copyright 2016-2021 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
version: 1.0.{build}-{branch}
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- /feature\/.*/
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
TOOLSET: msvc-14.0
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc-14.1
|
||||
CXXSTD: 14,17
|
||||
ADDRMD: 32,64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: clang-win
|
||||
ADDRMD: 64
|
||||
CXXSTD: 14,17
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
TOOLSET: clang-win
|
||||
CXXSTD: 14,17,latest
|
||||
ADDRMD: 64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 11,14,1z
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 11,14,17
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 11,14,17
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
TOOLSET: gcc
|
||||
CXXSTD: 11,14,17
|
||||
|
||||
install:
|
||||
- set BOOST_BRANCH=develop
|
||||
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
|
||||
- cd ..
|
||||
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- cd boost-root
|
||||
- git submodule update --init tools/boostdep
|
||||
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\container_hash\
|
||||
- python tools/boostdep/depinst/depinst.py -I examples container_hash
|
||||
- cmd /c bootstrap
|
||||
- b2 -d0 headers
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- PATH=%ADDPATH%%PATH%
|
||||
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
- b2 -j3 --verbose-test libs/container_hash/test//hash_info toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
- b2 -j3 libs/container_hash/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
423
.drone.jsonnet
Normal file
423
.drone.jsonnet
Normal file
@@ -0,0 +1,423 @@
|
||||
# Copyright 2022 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
local library = "container_hash";
|
||||
|
||||
local triggers =
|
||||
{
|
||||
branch: [ "master", "develop", "feature/*" ]
|
||||
};
|
||||
|
||||
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
|
||||
local asan = { ASAN: '1' };
|
||||
|
||||
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
|
||||
{
|
||||
name: name,
|
||||
kind: "pipeline",
|
||||
type: "docker",
|
||||
trigger: triggers,
|
||||
platform:
|
||||
{
|
||||
os: "linux",
|
||||
arch: arch
|
||||
},
|
||||
steps:
|
||||
[
|
||||
{
|
||||
name: "everything",
|
||||
image: image,
|
||||
environment: environment,
|
||||
commands:
|
||||
[
|
||||
'set -e',
|
||||
'uname -a',
|
||||
'echo $DRONE_STAGE_MACHINE',
|
||||
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
|
||||
] +
|
||||
(if sources != [] then [ 'apt-get update' ] + [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
|
||||
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
|
||||
[
|
||||
'export LIBRARY=' + library,
|
||||
'./.drone/drone.sh',
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") =
|
||||
{
|
||||
name: name,
|
||||
kind: "pipeline",
|
||||
type: "exec",
|
||||
trigger: triggers,
|
||||
platform: {
|
||||
"os": "darwin",
|
||||
"arch": arch
|
||||
},
|
||||
node: {
|
||||
"os": osx_version
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: "everything",
|
||||
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
|
||||
commands:
|
||||
[
|
||||
'export LIBRARY=' + library,
|
||||
'./.drone/drone.sh',
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
{
|
||||
name: name,
|
||||
kind: "pipeline",
|
||||
type: "docker",
|
||||
trigger: triggers,
|
||||
platform:
|
||||
{
|
||||
os: "windows",
|
||||
arch: arch
|
||||
},
|
||||
"steps":
|
||||
[
|
||||
{
|
||||
name: "everything",
|
||||
image: image,
|
||||
environment: environment,
|
||||
commands:
|
||||
[
|
||||
'cmd /C .drone\\\\drone.bat ' + library,
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
[
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.7 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '0x', ADDRMD: '32,64' },
|
||||
"g++-4.7-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.8* 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.9 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '11', ADDRMD: '32,64' },
|
||||
"g++-4.9-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 GCC 5* 32/64",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 6 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
"g++-6-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 7* 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 8 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '11,14,17', ADDRMD: '32,64' },
|
||||
"g++-8-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* ARM64",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* S390x",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
|
||||
arch="s390x",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 10 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '11,14,17,20', ADDRMD: '32,64' },
|
||||
"g++-10-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 11* 32/64",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 32/64",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' },
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 GCC 13 32/64 UBSAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' } + ubsan,
|
||||
"g++-13-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 GCC 13 32 ASAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + asan,
|
||||
"g++-13-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 GCC 14 UBSAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b' } + ubsan,
|
||||
"g++-14-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 GCC 14 ASAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b' } + asan,
|
||||
"g++-14-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.5",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '11' },
|
||||
"clang-3.5",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.6",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '11,14' },
|
||||
"clang-3.6",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.7",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '11,14' },
|
||||
"clang-3.7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.8",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '11,14' },
|
||||
"clang-3.8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 3.9",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '11,14' },
|
||||
"clang-3.9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 4.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '11,14' },
|
||||
"clang-4.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 5.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '11,14,1z' },
|
||||
"clang-5.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 6.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '11,14,17' },
|
||||
"clang-6.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 7",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '11,14,17' },
|
||||
"clang-7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 8",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '11,14,17' },
|
||||
"clang-8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 9",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '11,14,17,2a' },
|
||||
"clang-9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 10",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '11,14,17,2a' },
|
||||
"clang-10",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 11",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '11,14,17,2a' },
|
||||
"clang-11",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 12",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '11,14,17,2a' },
|
||||
"clang-12",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 13",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '11,14,17,20,2b' },
|
||||
"clang-13",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '11,14,17,20,2b' },
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 15",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' },
|
||||
"clang-15",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 16",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' },
|
||||
"clang-16",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 17 UBSAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + ubsan,
|
||||
"clang-17",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 17 ASAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + asan,
|
||||
"clang-17",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 18 UBSAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + ubsan,
|
||||
"clang-18",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 18 ASAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + asan,
|
||||
"clang-18",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.10 Clang 19",
|
||||
"cppalliance/droneubuntu2410:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-19', CXXSTD: '11,14,17,20,2b' },
|
||||
"clang-19",
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 UBSAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,2a' } + ubsan,
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 ASAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,2a' } + asan,
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 12.4 Xcode 13.4.1 UBSAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + ubsan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 12.4 Xcode 13.4.1 ASAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + asan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2015 msvc-14.0",
|
||||
"cppalliance/dronevs2015",
|
||||
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest', B2_DONT_EMBED_MANIFEST: '1' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2017 msvc-14.1",
|
||||
"cppalliance/dronevs2017",
|
||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2019 msvc-14.2",
|
||||
"cppalliance/dronevs2019",
|
||||
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2022 msvc-14.3",
|
||||
"cppalliance/dronevs2022:1",
|
||||
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
]
|
||||
24
.drone/drone.bat
Normal file
24
.drone/drone.bat
Normal file
@@ -0,0 +1,24 @@
|
||||
@REM Copyright 2022 Peter Dimov
|
||||
@REM Distributed under the Boost Software License, Version 1.0.
|
||||
@REM https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
@ECHO ON
|
||||
|
||||
set LIBRARY=%1
|
||||
set DRONE_BUILD_DIR=%CD%
|
||||
|
||||
set BOOST_BRANCH=develop
|
||||
if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init tools/boostdep
|
||||
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\
|
||||
python tools/boostdep/depinst/depinst.py -I examples %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
b2 -j3 --verbose-test libs/%LIBRARY%/test//hash_info toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
26
.drone/drone.sh
Executable file
26
.drone/drone.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2022 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
set -ex
|
||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||
|
||||
DRONE_BUILD_DIR=$(pwd)
|
||||
|
||||
BOOST_BRANCH=develop
|
||||
if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
|
||||
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init tools/boostdep
|
||||
cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY
|
||||
python tools/boostdep/depinst/depinst.py -I examples $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
|
||||
./b2 -j3 --verbose-test libs/$LIBRARY/test//hash_info toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
|
||||
675
.github/workflows/ci.yml
vendored
Normal file
675
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,675 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- feature/**
|
||||
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
|
||||
jobs:
|
||||
posix:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-4.8
|
||||
cxxstd: "11"
|
||||
container: ubuntu:18.04
|
||||
os: ubuntu-latest
|
||||
install: g++-4.8-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-5
|
||||
cxxstd: "11,14,1z"
|
||||
container: ubuntu:18.04
|
||||
os: ubuntu-latest
|
||||
install: g++-5-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-6
|
||||
cxxstd: "11,14,1z"
|
||||
container: ubuntu:18.04
|
||||
os: ubuntu-latest
|
||||
install: g++-6-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-7
|
||||
cxxstd: "11,14,17"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: g++-7-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-8
|
||||
cxxstd: "11,14,17,2a"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: g++-8-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-9
|
||||
cxxstd: "11,14,17,2a"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: g++-9-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-22.04
|
||||
install: g++-10-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-11
|
||||
cxxstd: "11,14,17,20"
|
||||
os: ubuntu-22.04
|
||||
install: g++-11-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-12
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
install: g++-12-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-13
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: g++-13-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-14
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: g++-14-multilib
|
||||
address-model: 32,64
|
||||
- toolset: gcc-15
|
||||
cxxstd: "11,14,17,20,23,2c"
|
||||
container: ubuntu:25.04
|
||||
os: ubuntu-latest
|
||||
install: g++-15-multilib
|
||||
address-model: 32,64
|
||||
- toolset: clang
|
||||
compiler: clang++-3.9
|
||||
cxxstd: "11,14"
|
||||
container: ubuntu:18.04
|
||||
os: ubuntu-latest
|
||||
install: clang-3.9
|
||||
- toolset: clang
|
||||
compiler: clang++-4.0
|
||||
cxxstd: "11,14"
|
||||
container: ubuntu:18.04
|
||||
os: ubuntu-latest
|
||||
install: clang-4.0
|
||||
- toolset: clang
|
||||
compiler: clang++-5.0
|
||||
cxxstd: "11,14,1z"
|
||||
container: ubuntu:18.04
|
||||
os: ubuntu-latest
|
||||
install: clang-5.0
|
||||
- toolset: clang
|
||||
compiler: clang++-6.0
|
||||
cxxstd: "11,14,17"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: clang-6.0
|
||||
- toolset: clang
|
||||
compiler: clang++-7
|
||||
cxxstd: "11,14,17"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: clang-7
|
||||
- toolset: clang
|
||||
compiler: clang++-8
|
||||
cxxstd: "11,14,17"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: clang-8
|
||||
- toolset: clang
|
||||
compiler: clang++-9
|
||||
cxxstd: "11,14,17,2a"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: clang-9
|
||||
- toolset: clang
|
||||
compiler: clang++-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: clang-10
|
||||
- toolset: clang
|
||||
compiler: clang++-11
|
||||
cxxstd: "11,14,17,2a"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: clang-11
|
||||
- toolset: clang
|
||||
compiler: clang++-12
|
||||
cxxstd: "11,14,17,20"
|
||||
container: ubuntu:20.04
|
||||
os: ubuntu-latest
|
||||
install: clang-12
|
||||
- toolset: clang
|
||||
compiler: clang++-13
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:22.04
|
||||
os: ubuntu-latest
|
||||
install: clang-13
|
||||
- toolset: clang
|
||||
compiler: clang++-14
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:22.04
|
||||
os: ubuntu-latest
|
||||
install: clang-14
|
||||
- toolset: clang
|
||||
compiler: clang++-15
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:22.04
|
||||
os: ubuntu-latest
|
||||
install: clang-15
|
||||
- toolset: clang
|
||||
compiler: clang++-16
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-16
|
||||
- toolset: clang
|
||||
compiler: clang++-17
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-17
|
||||
- toolset: clang
|
||||
compiler: clang++-18
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-18
|
||||
- toolset: clang
|
||||
compiler: clang++-19
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-19
|
||||
- toolset: clang
|
||||
compiler: clang++-20
|
||||
cxxstd: "11,14,17,20,23,2c"
|
||||
container: ubuntu:25.04
|
||||
os: ubuntu-latest
|
||||
install: clang-20
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-13
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-14
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-15
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
container:
|
||||
image: ${{matrix.container}}
|
||||
volumes:
|
||||
- /node20217:/node20217:rw,rshared
|
||||
- ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- name: Setup container environment
|
||||
if: matrix.container
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get -y install sudo python3 git g++ curl xz-utils
|
||||
|
||||
- name: Install nodejs20glibc2.17
|
||||
if: ${{ startsWith( matrix.container, 'ubuntu:1' ) }}
|
||||
run: |
|
||||
curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz
|
||||
tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217
|
||||
ldd /__e/node20/bin/node
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python3 tools/boostdep/depinst/depinst.py -I examples --git_args "--jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
- name: Create user-config.jam
|
||||
if: matrix.compiler
|
||||
run: |
|
||||
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
export ADDRMD=${{matrix.address-model}}
|
||||
./b2 -j3 --verbose-test libs/$LIBRARY/test//hash_info toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} variant=debug,release
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} ${ADDRMD:+address-model=$ADDRMD} variant=debug,release
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: msvc-14.0
|
||||
cxxstd: 14,latest
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.2
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: clang-win
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: gcc
|
||||
cxxstd: "11,14,17,2a"
|
||||
addrmd: 64
|
||||
os: windows-2022
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py -I examples --git_args "--jobs 3" %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 -j3 --verbose-test libs/%LIBRARY%/test//hash_info toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
|
||||
|
||||
posix-cmake-subdir:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
- os: macos-13
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Use library with add_subdirectory
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
|
||||
mkdir __build__ && cd __build__
|
||||
cmake ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
- os: macos-13
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install
|
||||
|
||||
- name: Use the installed library
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
- os: macos-13
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
windows-cmake-subdir:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2022
|
||||
- os: windows-2025
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Use library with add_subdirectory (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test
|
||||
mkdir __build__ && cd __build__
|
||||
cmake ..
|
||||
cmake --build . --config Debug
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Use library with add_subdirectory (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test/__build__
|
||||
cmake --build . --config Release
|
||||
ctest --output-on-failure --no-tests=error -C Release
|
||||
|
||||
windows-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2022
|
||||
- os: windows-2025
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
|
||||
|
||||
- name: Install (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install --config Debug
|
||||
|
||||
- name: Install (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install --config Release
|
||||
|
||||
- name: Use the installed library (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
|
||||
cmake --build . --config Debug
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Use the installed library (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test/__build__
|
||||
cmake --build . --config Release
|
||||
ctest --output-on-failure --no-tests=error -C Release
|
||||
|
||||
windows-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2022
|
||||
- os: windows-2025
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
|
||||
- name: Configure
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DBUILD_TESTING=ON ..
|
||||
|
||||
- name: Build tests (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests --config Debug
|
||||
|
||||
- name: Run tests (Debug)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error -C Debug
|
||||
|
||||
- name: Build tests (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests --config Release
|
||||
|
||||
- name: Run tests (Release)
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error -C Release
|
||||
78
.travis.yml
Normal file
78
.travis.yml
Normal file
@@ -0,0 +1,78 @@
|
||||
# Copyright (C) 2016 Daniel James.
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Use Trusty to get a reasonably recent version of Boost.
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
language: c++
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
env: |
|
||||
USER_CONFIG="using gcc : : g++-4.8 ;"
|
||||
CXXSTD=03,11
|
||||
- compiler: g++-7
|
||||
env: |
|
||||
USER_CONFIG="using gcc : : g++-7 ;"
|
||||
CXXSTD=11,14,17
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- compiler: clang
|
||||
env: |
|
||||
USER_CONFIG="using clang : : clang++ ;"
|
||||
CXXSTD=03,11
|
||||
- compiler: clang
|
||||
env: |
|
||||
USER_CONFIG="using clang : : clang++ -D_HAS_AUTO_PTR_ETC=0 ;"
|
||||
CXXSTD=11
|
||||
|
||||
before_script:
|
||||
- export BOOST_VERSION=1.67.0
|
||||
- export BOOST_FILENAME=boost_1_67_0
|
||||
- export BOOST_ROOT=${HOME}/boost
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- touch Jamroot.jam
|
||||
- cd $HOME
|
||||
- echo $USER_CONFIG > ~/user-config.jam
|
||||
- cat ~/user-config.jam
|
||||
- |
|
||||
mkdir $HOME/download
|
||||
mkdir $HOME/extract
|
||||
cd $HOME/download
|
||||
if [ "$TRAVIS_EVENT_TYPE" == "cron" ]
|
||||
then
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]
|
||||
then
|
||||
snapshot_branch=master
|
||||
else
|
||||
snapshot_branch=develop
|
||||
fi
|
||||
download_url=$(curl https://api.bintray.com/packages/boostorg/$snapshot_branch/snapshot/files |
|
||||
python -c "import os.path, sys, json; x = json.load(sys.stdin); print '\n'.join(a['path'] for a in x if os.path.splitext(a['path'])[1] == '.bz2')" |
|
||||
head -n 1 |
|
||||
sed "s/^/http:\/\/dl.bintray.com\/boostorg\/$snapshot_branch\//")
|
||||
else
|
||||
download_url=https://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/${BOOST_FILENAME}.tar.bz2/download
|
||||
fi
|
||||
echo "Downloading ${download_url}"
|
||||
wget -O boost.tar.bz2 $download_url
|
||||
cd $HOME/extract
|
||||
tar -xjf $HOME/download/boost.tar.bz2
|
||||
mv * ${BOOST_ROOT}
|
||||
- rm -r ${BOOST_ROOT}/boost/functional
|
||||
- cd ${BOOST_ROOT}/tools/build
|
||||
- mkdir ${HOME}/opt
|
||||
- ./bootstrap.sh
|
||||
- ./b2 install --prefix=$HOME/opt
|
||||
|
||||
script:
|
||||
- cd ${TRAVIS_BUILD_DIR}/test
|
||||
- ${HOME}/opt/bin/b2 --verbose-test -j 3 cxxstd=$CXXSTD -q ${BJAM_TOOLSET} include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include hash_info
|
||||
- ${HOME}/opt/bin/b2 -j 3 cxxstd=$CXXSTD -q ${BJAM_TOOLSET} include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include
|
||||
28
CMakeLists.txt
Normal file
28
CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# Generated by `boostdep --cmake container_hash`
|
||||
# Copyright 2020, 2021 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.8...3.20)
|
||||
|
||||
project(boost_container_hash VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_container_hash INTERFACE)
|
||||
add_library(Boost::container_hash ALIAS boost_container_hash)
|
||||
|
||||
target_include_directories(boost_container_hash INTERFACE include)
|
||||
|
||||
target_link_libraries(boost_container_hash
|
||||
INTERFACE
|
||||
Boost::config
|
||||
Boost::describe
|
||||
Boost::mp11
|
||||
)
|
||||
|
||||
target_compile_features(boost_container_hash INTERFACE cxx_std_11)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
||||
20
README.md
Normal file
20
README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Boost.ContainerHash
|
||||
|
||||
The Boost.ContainerHash library, part of [Boost C++ Libraries](https://boost.org),
|
||||
provides `boost::hash`, an enhanced implementation of the
|
||||
[hash function](https://en.wikipedia.org/wiki/Hash_function) object specified
|
||||
by C++11 as `std::hash`, and several support facilities (`hash_combine`,
|
||||
`hash_range`, `hash_unordered_range`).
|
||||
|
||||
`boost::hash` supports most standard types and some user-defined types out of
|
||||
the box, and is extensible; it's possible for a user-defined type `X` to make
|
||||
iself hashable via `boost::hash<X>` by defining an appropriate overload of the
|
||||
function `hash_value`.
|
||||
|
||||
See [the documentation of the library](https://www.boost.org/libs/container_hash)
|
||||
for more information.
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the
|
||||
[Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
4
benchmark/.gitignore
vendored
Normal file
4
benchmark/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
enwik8
|
||||
enwik9
|
||||
*.exe
|
||||
*.obj
|
||||
101
benchmark/char_seq.cpp
Normal file
101
benchmark/char_seq.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/core/type_name.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <chrono>
|
||||
|
||||
// test_hash_speed
|
||||
|
||||
template<class T, class V> void test_hash_speed( int N, V const& v )
|
||||
{
|
||||
std::vector<T> w;
|
||||
|
||||
w.reserve( N );
|
||||
|
||||
for( int i = 0; i < N; ++i )
|
||||
{
|
||||
w.emplace_back( v[i].begin(), v[i].end() );
|
||||
}
|
||||
|
||||
typedef std::chrono::steady_clock clock_type;
|
||||
|
||||
clock_type::time_point t1 = clock_type::now();
|
||||
|
||||
std::size_t q = 0;
|
||||
|
||||
boost::hash<T> const h;
|
||||
|
||||
for( int i = 0; i < N; ++i )
|
||||
{
|
||||
q += h( w[i] );
|
||||
}
|
||||
|
||||
clock_type::time_point t2 = clock_type::now();
|
||||
|
||||
long long ms1 = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
|
||||
|
||||
std::string type = boost::core::type_name<T>();
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
std::printf( "%25s : q=%20Iu, %lld ms\n", type.c_str(), q, ms1 );
|
||||
|
||||
#else
|
||||
|
||||
std::printf( "%25s : q=%20zu, %lld ms\n", type.c_str(), q, ms1 );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int const N = 1048576 * 8;
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
{
|
||||
v.reserve( N );
|
||||
|
||||
boost::detail::splitmix64 rnd;
|
||||
|
||||
for( int i = 0; i < N; ++i )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
|
||||
unsigned long long k = rnd();
|
||||
|
||||
if( k & 1 )
|
||||
{
|
||||
sprintf( buffer, "prefix_%llu_suffix", k );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buffer, "{%u}", static_cast<unsigned>( k ) );
|
||||
}
|
||||
|
||||
v.push_back( buffer );
|
||||
}
|
||||
}
|
||||
|
||||
std::puts( "Char sequence hashing test:\n" );
|
||||
|
||||
test_hash_speed< std::string >( N, v );
|
||||
test_hash_speed< std::vector<char> >( N, v );
|
||||
test_hash_speed< std::deque<char> >( N, v );
|
||||
test_hash_speed< std::list<char> >( N, v );
|
||||
|
||||
std::puts( "" );
|
||||
}
|
||||
461
benchmark/unordered.cpp
Normal file
461
benchmark/unordered.cpp
Normal file
@@ -0,0 +1,461 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/core/type_name.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/hash/hash.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
# include "mulxp_hash.hpp"
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
// mul31_hash
|
||||
|
||||
struct mul31_hash
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
for( std::size_t i = 0; i < n; ++i )
|
||||
{
|
||||
h = h * 31 + static_cast<unsigned char>( p[i] );
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
// mul31_x4_hash
|
||||
|
||||
struct mul31_x4_hash
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
while( n >= 4 )
|
||||
{
|
||||
h = h * (31u * 31u * 31u * 31u)
|
||||
+ static_cast<unsigned char>( p[0] ) * (31u * 31u * 31u)
|
||||
+ static_cast<unsigned char>( p[1] ) * (31u * 31u)
|
||||
+ static_cast<unsigned char>( p[2] ) * 31u
|
||||
+ static_cast<unsigned char>( p[3] );
|
||||
|
||||
p += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
h = h * 31u + static_cast<unsigned char>( *p );
|
||||
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
// mul31_x8_hash
|
||||
|
||||
struct mul31_x8_hash
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
char const * p = st.data();
|
||||
std::size_t n = st.size();
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
boost::uint64_t h = 0xCBF29CE484222325ull;
|
||||
#else
|
||||
boost::uint64_t h = 0x811C9DC5u;
|
||||
#endif
|
||||
|
||||
while( n >= 8 )
|
||||
{
|
||||
h = h * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[0] ) * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[1] ) * (31ull * 31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[2] ) * (31ull * 31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[3] ) * (31ull * 31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[4] ) * (31ull * 31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[5] ) * (31ull * 31ull)
|
||||
+ static_cast<unsigned char>( p[6] ) * 31ull
|
||||
+ static_cast<unsigned char>( p[7] );
|
||||
|
||||
p += 8;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
h = h * 31u + static_cast<unsigned char>( *p );
|
||||
|
||||
++p;
|
||||
--n;
|
||||
}
|
||||
|
||||
return static_cast<std::size_t>( h );
|
||||
}
|
||||
};
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
|
||||
template<> struct fnv1a_hash_impl<32>
|
||||
{
|
||||
std::size_t operator()( std::string const& s ) const
|
||||
{
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x01000193ul;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct fnv1a_hash_impl<64>
|
||||
{
|
||||
std::size_t operator()( std::string const& s ) const
|
||||
{
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x00000100000001B3ull;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {};
|
||||
|
||||
// mulxp_hash
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
struct mulxp1_hash_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp1_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp3_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp1_hash32_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp1_hash32( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash32_
|
||||
{
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp3_hash32( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// test_hash_speed
|
||||
|
||||
template<class H, class V> void test_hash_speed( int N, V const& v )
|
||||
{
|
||||
typedef std::chrono::steady_clock clock_type;
|
||||
|
||||
clock_type::time_point t1 = clock_type::now();
|
||||
|
||||
std::size_t q = 0;
|
||||
|
||||
H const h;
|
||||
|
||||
for( int i = 0; i < N; ++i )
|
||||
{
|
||||
q += h( v[i] );
|
||||
}
|
||||
|
||||
clock_type::time_point t2 = clock_type::now();
|
||||
|
||||
long long ms1 = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
|
||||
|
||||
std::string hash = boost::core::type_name<H>();
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
std::printf( "%57s : q=%20Iu, %lld ms\n", hash.c_str(), q, ms1 );
|
||||
|
||||
#else
|
||||
|
||||
std::printf( "%57s : q=%20zu, %lld ms\n", hash.c_str(), q, ms1 );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// test_hash_collision
|
||||
|
||||
template<class H, class V> void test_hash_collision( int N, V const& v, std::size_t n )
|
||||
{
|
||||
boost::unordered_set<std::size_t> s;
|
||||
H const h;
|
||||
|
||||
for( int i = 0; i < N; ++i )
|
||||
{
|
||||
s.insert( h( v[i] ) );
|
||||
}
|
||||
|
||||
std::string hash = boost::core::type_name<H>();
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
std::printf( "%57s : c=%Iu\n", hash.c_str(), n - s.size() );
|
||||
|
||||
#else
|
||||
|
||||
std::printf( "%57s : c=%zu\n", hash.c_str(), n - s.size() );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// test_container_speed
|
||||
|
||||
template<class V, class S> void test4( int N, V const& v, char const * hash, S s )
|
||||
{
|
||||
typedef std::chrono::steady_clock clock_type;
|
||||
|
||||
clock_type::time_point t1 = clock_type::now();
|
||||
|
||||
for( int i = 0; i < N; ++i )
|
||||
{
|
||||
s.insert( v[ i * 16 ] );
|
||||
}
|
||||
|
||||
clock_type::time_point t2 = clock_type::now();
|
||||
|
||||
std::size_t q = 0;
|
||||
|
||||
for( int i = 0; i < 16 * N; ++i )
|
||||
{
|
||||
q += s.count( v[ i ] );
|
||||
}
|
||||
|
||||
clock_type::time_point t3 = clock_type::now();
|
||||
|
||||
long long ms1 = std::chrono::duration_cast<std::chrono::milliseconds>( t2 - t1 ).count();
|
||||
long long ms2 = std::chrono::duration_cast<std::chrono::milliseconds>( t3 - t2 ).count();
|
||||
|
||||
std::size_t n = s.bucket_count();
|
||||
std::size_t m = 0;
|
||||
std::size_t c = 0;
|
||||
|
||||
for( std::size_t i = 0; i < n; ++i )
|
||||
{
|
||||
std::size_t k = s.bucket_size( i );
|
||||
|
||||
if( k > 1 )
|
||||
{
|
||||
c += k - 1;
|
||||
}
|
||||
|
||||
if( k > m )
|
||||
{
|
||||
m = k;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
std::printf( "%57s : n=%Iu, m=%Iu, c=%Iu, q=%Iu, %4lld + %4lld = %4lld ms\n", hash, n, m, c, q, ms1, ms2, ms1 + ms2 );
|
||||
|
||||
#else
|
||||
|
||||
std::printf( "%57s : n=%zu, m=%zu, c=%zu, q=%zu, %4lld + %4lld = %4lld ms\n", hash, n, m, c, q, ms1, ms2, ms1 + ms2 );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class K, class H, class V> void test_container_speed( int N, V const& v )
|
||||
{
|
||||
boost::unordered_set<K, H> s( 0 );
|
||||
test4( N, v, boost::core::type_name<H>().c_str(), s );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int const N = 1048576 / 2; // 1048576 is too much for 32 bit
|
||||
|
||||
std::vector<std::string> v;
|
||||
|
||||
{
|
||||
v.reserve( N * 16 );
|
||||
|
||||
boost::detail::splitmix64 rnd;
|
||||
|
||||
for( int i = 0; i < 16 * N; ++i )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
|
||||
unsigned long long k = rnd();
|
||||
|
||||
if( k & 1 )
|
||||
{
|
||||
sprintf( buffer, "prefix_%llu_suffix", k );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buffer, "{%u}", static_cast<unsigned>( k ) );
|
||||
}
|
||||
|
||||
v.push_back( buffer );
|
||||
}
|
||||
}
|
||||
|
||||
std::puts( "Hash speed test:\n" );
|
||||
|
||||
test_hash_speed<mul31_hash>( N * 16, v );
|
||||
test_hash_speed<mul31_x4_hash>( N * 16, v );
|
||||
test_hash_speed<mul31_x8_hash>( N * 16, v );
|
||||
test_hash_speed<fnv1a_hash>( N * 16, v );
|
||||
test_hash_speed<boost::hash<std::string> >( N * 16, v );
|
||||
test_hash_speed<std::hash<std::string> >( N * 16, v );
|
||||
#ifdef HAVE_ABSEIL
|
||||
test_hash_speed<absl::Hash<std::string> >( N * 16, v );
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
test_hash_speed<ankerl::unordered_dense::hash<std::string> >( N * 16, v );
|
||||
#endif
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
test_hash_speed<mulxp1_hash_>( N * 16, v );
|
||||
test_hash_speed<mulxp3_hash_>( N * 16, v );
|
||||
test_hash_speed<mulxp1_hash32_>( N * 16, v );
|
||||
test_hash_speed<mulxp3_hash32_>( N * 16, v );
|
||||
#endif
|
||||
|
||||
std::puts( "" );
|
||||
|
||||
std::puts( "Hash collision test:\n" );
|
||||
|
||||
{
|
||||
std::size_t n = 0;
|
||||
|
||||
{
|
||||
boost::unordered_set<std::string> s;
|
||||
|
||||
for( int i = 0; i < N * 16; ++i )
|
||||
{
|
||||
s.insert( v[i] );
|
||||
}
|
||||
|
||||
n = s.size();
|
||||
}
|
||||
|
||||
test_hash_collision<mul31_hash>( N * 16, v, n );
|
||||
test_hash_collision<mul31_x4_hash>( N * 16, v, n );
|
||||
test_hash_collision<mul31_x8_hash>( N * 16, v, n );
|
||||
test_hash_collision<fnv1a_hash>( N * 16, v, n );
|
||||
test_hash_collision<boost::hash<std::string> >( N * 16, v, n );
|
||||
test_hash_collision<std::hash<std::string> >( N * 16, v, n );
|
||||
#ifdef HAVE_ABSEIL
|
||||
test_hash_collision<absl::Hash<std::string> >( N * 16, v, n );
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
test_hash_collision<ankerl::unordered_dense::hash<std::string> >( N * 16, v, n );
|
||||
#endif
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
test_hash_collision<mulxp1_hash_>( N * 16, v, n );
|
||||
test_hash_collision<mulxp3_hash_>( N * 16, v, n );
|
||||
test_hash_collision<mulxp1_hash32_>( N * 16, v, n );
|
||||
test_hash_collision<mulxp3_hash32_>( N * 16, v, n );
|
||||
#endif
|
||||
}
|
||||
|
||||
std::puts( "" );
|
||||
|
||||
typedef std::string K;
|
||||
|
||||
std::puts( "Container speed test:\n---\n" );
|
||||
|
||||
test_container_speed<K, mul31_hash>( N, v );
|
||||
test_container_speed<K, mul31_x4_hash>( N, v );
|
||||
test_container_speed<K, mul31_x8_hash>( N, v );
|
||||
test_container_speed<K, fnv1a_hash>( N, v );
|
||||
test_container_speed<K, boost::hash<std::string> >( N, v );
|
||||
test_container_speed<K, std::hash<std::string> >( N, v );
|
||||
#ifdef HAVE_ABSEIL
|
||||
test_container_speed<K, absl::Hash<std::string> >( N, v );
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
test_container_speed<K, ankerl::unordered_dense::hash<std::string> >( N, v );
|
||||
#endif
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
test_container_speed<K, mulxp1_hash_>( N, v );
|
||||
test_container_speed<K, mulxp3_hash_>( N, v );
|
||||
test_container_speed<K, mulxp1_hash32_>( N, v );
|
||||
test_container_speed<K, mulxp3_hash32_>( N, v );
|
||||
#endif
|
||||
|
||||
std::puts( "" );
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
386
benchmark/unordered_flat.cpp
Normal file
386
benchmark/unordered_flat.cpp
Normal file
@@ -0,0 +1,386 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/hash/hash.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
# include "mulxp_hash.hpp"
|
||||
#endif
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
constexpr unsigned N = 2'000'000;
|
||||
constexpr int K = 10;
|
||||
|
||||
static std::vector<std::string> indices1, indices2;
|
||||
|
||||
static std::string make_index( unsigned x )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
std::snprintf( buffer, sizeof(buffer), "pfx_%u_sfx", x );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static std::string make_random_index( unsigned x )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
std::snprintf( buffer, sizeof(buffer), "pfx_%0*d_%u_sfx", x % 8 + 1, 0, x );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void init_indices()
|
||||
{
|
||||
indices1.reserve( N*2+1 );
|
||||
indices1.push_back( make_index( 0 ) );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices1.push_back( make_index( i ) );
|
||||
}
|
||||
|
||||
indices2.reserve( N*2+1 );
|
||||
indices2.push_back( make_index( 0 ) );
|
||||
|
||||
{
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices2.push_back( make_random_index( static_cast<std::uint32_t>( rng() ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices1[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices2[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Random insert", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::uint32_t s;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices1[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices2[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Random lookup", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
auto it = map.begin();
|
||||
|
||||
while( it != map.end() )
|
||||
{
|
||||
if( it->second & 1 )
|
||||
{
|
||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
||||
{
|
||||
map.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
it = map.erase( it );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices1[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices2[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Random erase", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<class Hash> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
boost::unordered_flat_map<std::string, std::uint32_t, Hash> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_insert( map, t1 );
|
||||
|
||||
record rec = { label, 0 };
|
||||
|
||||
test_lookup( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
test_lookup( map, t1 );
|
||||
test_erase( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
|
||||
template<> struct fnv1a_hash_impl<32>
|
||||
{
|
||||
std::size_t operator()( std::string const& s ) const
|
||||
{
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x01000193ul;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct fnv1a_hash_impl<64>
|
||||
{
|
||||
std::size_t operator()( std::string const& s ) const
|
||||
{
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x00000100000001B3ull;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
// std_hash
|
||||
|
||||
struct std_hash: std::hash<std::string>
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
// absl_hash
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
struct absl_hash: absl::Hash<std::string>
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// mulxp_hash
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
struct mulxp1_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp1_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp3_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp1_hash32_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t r = mulxp1_hash32( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
r |= r << 32;
|
||||
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash32_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t r = mulxp3_hash32( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
r |= r << 32;
|
||||
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
test< boost::hash<std::string> >( "boost::hash" );
|
||||
test< std_hash >( "std::hash" );
|
||||
test< fnv1a_hash >( "fnv1a_hash" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test< absl_hash >( "absl::Hash" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test< ankerl::unordered_dense::hash<std::string> >( "ankerl::unordered_dense::hash" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
test< mulxp1_hash_ >( "mulxp1_hash" );
|
||||
test< mulxp3_hash_ >( "mulxp3_hash" );
|
||||
test< mulxp1_hash32_ >( "mulxp1_hash32" );
|
||||
test< mulxp3_hash32_ >( "mulxp3_hash32" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 32 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
319
benchmark/word_count.cpp
Normal file
319
benchmark/word_count.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/hash/hash.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
# include "mulxp_hash.hpp"
|
||||
#endif
|
||||
#include <boost/regex.hpp>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
static std::vector<std::string> words;
|
||||
|
||||
static void init_words()
|
||||
{
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
|
||||
|
||||
#else
|
||||
|
||||
char const* fn = "enwik8"; // ditto
|
||||
|
||||
#endif
|
||||
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::ifstream is( fn );
|
||||
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
|
||||
|
||||
boost::regex re( "[a-zA-Z]+");
|
||||
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
|
||||
|
||||
words.assign( it, end );
|
||||
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_word_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
++map[ word ];
|
||||
++s;
|
||||
}
|
||||
|
||||
print_time( t1, "Word count", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_contains( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
std::string_view w2( word );
|
||||
w2.remove_prefix( 1 );
|
||||
|
||||
s += map.contains( w2 );
|
||||
}
|
||||
|
||||
print_time( t1, "Contains", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
std::string_view w2( word );
|
||||
w2.remove_prefix( 1 );
|
||||
|
||||
s += map.count( w2 );
|
||||
}
|
||||
|
||||
print_time( t1, "Count", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<class Hash> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
boost::unordered_flat_map<std::string_view, std::size_t, Hash> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_word_count( map, t1 );
|
||||
|
||||
record rec = { label, 0 };
|
||||
|
||||
test_contains( map, t1 );
|
||||
test_count( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
|
||||
template<> struct fnv1a_hash_impl<32>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x01000193ul;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct fnv1a_hash_impl<64>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x00000100000001B3ull;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
// std_hash
|
||||
|
||||
struct std_hash: std::hash<std::string_view>
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
// absl_hash
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
struct absl_hash: absl::Hash<std::string_view>
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
struct mulxp1_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp1_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return mulxp3_hash( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp3_hash32_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t r = mulxp3_hash32( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
r |= r << 32;
|
||||
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
struct mulxp1_hash32_
|
||||
{
|
||||
using is_avalanching = void;
|
||||
|
||||
std::size_t operator()( std::string_view const& st ) const BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t r = mulxp1_hash32( (unsigned char const*)st.data(), st.size(), 0 );
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
r |= r << 32;
|
||||
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
int main()
|
||||
{
|
||||
init_words();
|
||||
|
||||
test< boost::hash<std::string_view> >( "boost::hash" );
|
||||
test< std_hash >( "std::hash" );
|
||||
test< fnv1a_hash >( "fnv1a_hash" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test< absl_hash >( "absl::Hash" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test< ankerl::unordered_dense::hash<std::string_view> >( "ankerl::unordered_dense::hash" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MULXP_HASH
|
||||
|
||||
test< mulxp1_hash_ >( "mulxp1_hash" );
|
||||
test< mulxp3_hash_ >( "mulxp3_hash" );
|
||||
test< mulxp1_hash32_ >( "mulxp1_hash32" );
|
||||
test< mulxp3_hash32_ >( "mulxp3_hash32" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 32 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
22
build.jam
Normal file
22
build.jam
Normal file
@@ -0,0 +1,22 @@
|
||||
# Copyright 2023-2024 René Ferdinand Rivera Morell
|
||||
# Copyright 2024 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
constant boost_dependencies :
|
||||
/boost/config//boost_config
|
||||
/boost/describe//boost_describe
|
||||
/boost/mp11//boost_mp11
|
||||
;
|
||||
|
||||
project /boost/container_hash ;
|
||||
|
||||
explicit
|
||||
[ alias boost_container_hash : : : : <include>include <library>$(boost_dependencies) ]
|
||||
[ alias all : boost_container_hash examples test ]
|
||||
;
|
||||
|
||||
call-if : boost-library container_hash
|
||||
;
|
||||
2
doc/.gitignore
vendored
Normal file
2
doc/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/html/
|
||||
/pdf/
|
||||
@@ -3,17 +3,20 @@
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
using boostbook ;
|
||||
using quickbook ;
|
||||
import asciidoctor ;
|
||||
|
||||
xml hash : hash.qbk ;
|
||||
boostbook standalone : hash :
|
||||
<xsl:param>boost.root=../../../..
|
||||
html hash.html : hash.adoc ;
|
||||
|
||||
<xsl:param>chunk.first.sections=1
|
||||
<xsl:param>chunk.section.depth=2
|
||||
<xsl:param>generate.section.toc.level=2
|
||||
<xsl:param>toc.section.depth=1
|
||||
<xsl:param>toc.max.depth=1
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/functional/hash/doc/html
|
||||
;
|
||||
install html_ : hash.html : <location>html ;
|
||||
|
||||
pdf hash.pdf : hash.adoc ;
|
||||
explicit hash.pdf ;
|
||||
|
||||
install pdf_ : hash.pdf : <location>pdf ;
|
||||
explicit pdf_ ;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease : html_ ;
|
||||
explicit boostrelease ;
|
||||
|
||||
126
doc/changes.qbk
126
doc/changes.qbk
@@ -1,126 +0,0 @@
|
||||
|
||||
[/ Copyright 2005-2008 Daniel James.
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[section:changes Change Log]
|
||||
|
||||
[h2 Boost 1.33.0]
|
||||
|
||||
* Initial Release
|
||||
|
||||
[h2 Boost 1.33.1]
|
||||
|
||||
* Fixed the points example, as pointed out by 沈慧峰.
|
||||
|
||||
[h2 Boost 1.34.0]
|
||||
|
||||
* Use declarations for standard classes, so that the library
|
||||
doesn't need to include all of their headers
|
||||
* Deprecated the `<boost/functional/hash/*.hpp>` headers. Now a single header,
|
||||
<[headerref boost/functional/hash.hpp]> is used.
|
||||
* Add support for the `BOOST_HASH_NO_EXTENSIONS` macro, which
|
||||
disables the extensions to TR1.
|
||||
|
||||
* Minor improvements to the hash functions for floating point numbers.
|
||||
* Update the portable example to hopefully be more generally portable.
|
||||
|
||||
[h2 Boost 1.34.1]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/952 Ticket 952]:
|
||||
Suppress incorrect 64-bit warning on Visual C++.
|
||||
|
||||
[h2 Boost 1.35.0]
|
||||
|
||||
* Support for `long long`, `std::complex`.
|
||||
* Improved algorithm for hashing floating point numbers:
|
||||
* Improved portablity, as described by Daniel Krügler in
|
||||
[@http://lists.boost.org/boost-users/2005/08/13418.php
|
||||
a post to the boost users list].
|
||||
* Fits more information into each combine loop, which can reduce the
|
||||
the number of times combine is called and hopefully give a better
|
||||
quality hash function.
|
||||
* Improved the algorithm for hashing floating point numbers.
|
||||
* On Cygwin use a binary hash function for floating point numbers, as
|
||||
Cygwin doesn't have decent floating point functions for `long double`.
|
||||
* Never uses `fpclass` which doesn't support `long double`.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/1064 Ticket 1064]:
|
||||
Removed unnecessary use of `errno`.
|
||||
* Explicitly overload for more built in types.
|
||||
* Minor improvements to the documentation.
|
||||
* A few bug and warning fixes:
|
||||
* [@http://svn.boost.org/trac/boost/ticket/1509 Ticket 1509]:
|
||||
Suppress another Visual C++ warning.
|
||||
* Some workarounds for the Sun compilers.
|
||||
|
||||
[h2 Boost 1.36.0]
|
||||
|
||||
* Stop using OpenBSD's dodgy `std::numeric_limits`.
|
||||
* Using the boost typedefs for `long long` and `unsigned long long`.
|
||||
* Move the extensions into their own header.
|
||||
|
||||
[h2 Boost 1.37.0]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2264 Ticket 2264]:
|
||||
In Visual C++, always use C99 float functions for `long double` and `float` as
|
||||
the C++ overloads aren't always availables.
|
||||
|
||||
[h2 Boost 1.38.0]
|
||||
|
||||
* Changed the warnings in the deprecated headers from 1.34.0 to errors. These
|
||||
will be removed in a future version of Boost.
|
||||
* Moved detail headers out of `boost/functional/detail`, since they are part of
|
||||
functional/hash, not functional. `boost/functional/detail/container_fwd.hpp`
|
||||
has been moved to `boost/detail/container_fwd.hpp` as it's used outside of
|
||||
this library, the others have been moved to `boost/functional/hash/detail`.
|
||||
|
||||
[h2 Boost 1.39.0]
|
||||
|
||||
* Move the hash_fwd.hpp implementation into the hash subdirectory, leaving a
|
||||
forwarding header in the old location. You should still use the old location,
|
||||
the new location is mainly for implementation and possible modularization.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2412 Ticket 2412]: Removed deprecated
|
||||
headers.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2957 Ticket 2957]: Fix configuration
|
||||
for vxworks.
|
||||
|
||||
[h2 Boost 1.40.0]
|
||||
|
||||
* Automatically configure the float functions using template metaprogramming
|
||||
instead of trying to configure every possibility manually.
|
||||
* Workaround for when STLport doesn't support long double.
|
||||
|
||||
[h2 Boost 1.42.0]
|
||||
|
||||
* Reduce the number of warnings for Visual C++ warning level 4.
|
||||
* Some code formatting changes to fit lines into 80 characters.
|
||||
* Rename an internal namespace.
|
||||
|
||||
[h2 Boost 1.43.0]
|
||||
|
||||
* [@https://svn.boost.org/trac/boost/ticket/3866 Ticket 3866]:
|
||||
Don't foward declare containers when using gcc's parallel library,
|
||||
allow user to stop forward declaration by defining the
|
||||
`BOOST_DETAIL_NO_CONTAINER_FWD` macro.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/4038 Ticket 4038]:
|
||||
Avoid hashing 0.5 and 0 to the same number.
|
||||
* Stop using deprecated `BOOST_HAS_*` macros.
|
||||
|
||||
[h2 Boost 1.44.0]
|
||||
|
||||
* Add option to prevent implicit conversions when calling `hash_value` by
|
||||
defining `BOOST_HASH_NO_IMPLICIT_CASTS`. When using `boost::hash`
|
||||
for a type that does not have `hash_value` declared but does have
|
||||
an implicit conversion to a type that does, it would use that
|
||||
implicit conversion to hash it. Which can sometimes go very wrong,
|
||||
e.g. using a conversion to bool and only hashing to 2 possible
|
||||
values. Since fixing this is a breaking change and was only
|
||||
approached quite late in the release cycle with little discussion
|
||||
it's opt-in for now. This, or something like it, will become the
|
||||
default in a future version.
|
||||
|
||||
[h2 Boost 1.46.0]
|
||||
|
||||
* Avoid warning due with gcc's `-Wconversion` flag.
|
||||
|
||||
[endsect]
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
[/ Copyright 2005-2008 Daniel James.
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[section:disable Disabling The Extensions]
|
||||
|
||||
While [classref boost::hash]'s extensions are generally useful, you might want
|
||||
to turn them of in order to check that your code will work with other
|
||||
implementations of TR1. To do this define the macro `BOOST_HASH_NO_EXTENSIONS`.
|
||||
When this macro is defined, only the specialisations detailed
|
||||
in TR1 will be declared. But, if you later undefine the macro and include
|
||||
<[headerref boost/functional/hash.hpp]> then the non-specialised form will be defined
|
||||
- activating the extensions.
|
||||
|
||||
It is strongly recommended that you never undefine the macro - and only define
|
||||
it so that it applies to the complete translation unit, either by defining it
|
||||
at the beginning of the main source file or, preferably, by using a compiler
|
||||
switch or preference. And you really should never define it in header files.
|
||||
|
||||
If you are writing a library which has code in the header which requires the
|
||||
extensions, then the best action is to tell users not to define the macro.
|
||||
Their code won't ['require] the macro.
|
||||
|
||||
Translation units that are compiled with the macro defined will link with units
|
||||
that were compiled without it. This feature has been designed to avoid ODR
|
||||
violations.
|
||||
|
||||
[endsect]
|
||||
31
doc/hash.adoc
Normal file
31
doc/hash.adoc
Normal file
@@ -0,0 +1,31 @@
|
||||
////
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
= Boost.ContainerHash
|
||||
:toc: left
|
||||
:toclevels: 3
|
||||
:idprefix:
|
||||
:docinfo: private-footer
|
||||
:source-highlighter: rouge
|
||||
:nofooter:
|
||||
:sectlinks:
|
||||
:source-language: c++
|
||||
|
||||
:leveloffset: +1
|
||||
|
||||
include::hash/intro.adoc[]
|
||||
include::hash/recent.adoc[]
|
||||
include::hash/tutorial.adoc[]
|
||||
include::hash/user.adoc[]
|
||||
include::hash/combine.adoc[]
|
||||
include::hash/describe.adoc[]
|
||||
include::hash/reference.adoc[]
|
||||
include::hash/notes.adoc[]
|
||||
include::hash/links.adoc[]
|
||||
include::hash/thanks.adoc[]
|
||||
include::hash/changes.adoc[]
|
||||
include::hash/copyright.adoc[]
|
||||
24
doc/hash.qbk
24
doc/hash.qbk
@@ -1,24 +0,0 @@
|
||||
[library Boost.Functional/Hash
|
||||
[quickbook 1.4]
|
||||
[authors [James, Daniel]]
|
||||
[copyright 2005 2006 2007 2008 Daniel James]
|
||||
[purpose A TR1 hash function object that can be extended to hash user
|
||||
defined types]
|
||||
[category higher-order]
|
||||
[id hash]
|
||||
[dirname functional/hash]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
[@http://www.boost.org/LICENSE_1_0.txt])
|
||||
]
|
||||
]
|
||||
|
||||
[include:hash intro.qbk]
|
||||
[include:hash tutorial.qbk]
|
||||
[include:hash portability.qbk]
|
||||
[include:hash disable.qbk]
|
||||
[include:hash changes.qbk]
|
||||
[xinclude ref.xml]
|
||||
[include:hash links.qbk]
|
||||
[include:hash thanks.qbk]
|
||||
161
doc/hash/changes.adoc
Normal file
161
doc/hash/changes.adoc
Normal file
@@ -0,0 +1,161 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#changes]
|
||||
= Change Log
|
||||
:idprefix: changes_
|
||||
|
||||
:int128: __int128
|
||||
|
||||
== Boost 1.67.0
|
||||
* Moved library into its own module, `container_hash`.
|
||||
* Moved headers for new module name, now at: `<boost/container_hash/hash.hpp>`, `<boost/container_hash/hash_fwd.hpp>`, `<boost/container_hash/extensions.hpp>`.
|
||||
* Added forwarding headers to support the old headers locations.
|
||||
* Support `std::string_view`, `std::error_code`, `std::error_condition`, `std::optional`, `std::variant`, `std::monostate` where available.
|
||||
* Update include paths from other Boost libraries.
|
||||
* Manually write out tuple overloads, rather than using the preprocessor to generate them. Should improve usability, due to better error messages, and easier debugging.
|
||||
* Fix tutorial example (https://svn.boost.org/trac/boost/ticket/11017[#11017]).
|
||||
* Quick fix for hashing `vector<bool>` when using libc++. Will try to introduce a more general fix in the next release.
|
||||
|
||||
== Boost 1.66.0
|
||||
* Avoid float comparison warning when using Clang - this workaround was already in place for GCC, and was used when Clang pretends to be GCC, but the warning was appearing when running Clang in other contexts.
|
||||
|
||||
== Boost 1.65.0
|
||||
* Support for `char16_t`, `char32_t`, `u16string`, `u32string`
|
||||
|
||||
[discrete]
|
||||
== Boost 1.64.0
|
||||
* Fix for recent versions of Visual {cpp} which have removed `std::unary_function` and `std::binary_function` (https://svn.boost.org/trac/boost/ticket/12353[#12353]).
|
||||
|
||||
[discrete]
|
||||
== Boost 1.63.0
|
||||
* Fixed some warnings.
|
||||
* Only define hash for `std::wstring` when we know we have a `wchar_t`. Otherwise there's a compile error as there's no overload for hashing the characters in wide strings (https://svn.boost.org/trac/boost/ticket/8552[#8552]).
|
||||
|
||||
[discrete]
|
||||
== Boost 1.58.0
|
||||
* Fixed strict aliasing violation (https://github.com/boostorg/container_hash/issues/3[GitHub #3]).
|
||||
|
||||
[discrete]
|
||||
== Boost 1.56.0
|
||||
* Removed some Visual {cpp} 6 workarounds.
|
||||
* Ongoing work on improving `hash_combine`. This changes the combine function which was previously defined in the reference documentation.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.55.0
|
||||
* Simplify a SFINAE check so that it will hopefully work on Sun 5.9 (https://svn.boost.org/trac10/ticket/8822[#8822]).
|
||||
* Suppress Visual {cpp} infinite loop warning (https://svn.boost.org/trac10/ticket/8568[#8568]).
|
||||
|
||||
[discrete]
|
||||
== Boost 1.54.0
|
||||
* https://svn.boost.org/trac/boost/ticket/7957[Ticket 7957]: Fixed a typo.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.53.0
|
||||
* Add support for `boost::int128_type` and `boost::uint128_type` where available - currently only `{int128}` and `unsigned {int128}` on some versions of gcc.
|
||||
* On platforms that are known to have the standard floating point functions, don't use automatic detection - which can break if there are ambiguous overloads.
|
||||
* Fix undefined behaviour when using the binary `float` hash (Thomas Heller).
|
||||
|
||||
[discrete]
|
||||
== Boost 1.52.0
|
||||
* Restore `enum` support, which was accidentally removed in the last version.
|
||||
* New floating point hasher - will hash the binary representation on more platforms, which should be faster.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.51.0
|
||||
* Support the standard smart pointers.
|
||||
* `hash_value` now implemented using SFINAE to avoid implicit casts to built in types when calling it.
|
||||
* Updated to use the new config macros.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.50.0
|
||||
* https://svn.boost.org/trac/boost/ticket/6771[Ticket 6771]: Avoid gcc's `-Wfloat-equal` warning.
|
||||
* https://svn.boost.org/trac/boost/ticket/6806[Ticket 6806]: Support `std::array` and `std::tuple` when available.
|
||||
* Add deprecation warning to the long deprecated `boost/container_hash/detail/container_fwd.hpp`.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.46.0
|
||||
* Avoid warning due with gcc's `-Wconversion` flag.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.44.0
|
||||
* Add option to prevent implicit conversions when calling `hash_value` by defining `BOOST_HASH_NO_IMPLICIT_CASTS`. When using `boost::hash` for a type that does not have `hash_value` declared but does have an implicit conversion to a type that does, it would use that implicit conversion to hash it. Which can sometimes go very wrong, e.g. using a conversion to `bool` and only hashing to 2 possible values. Since fixing this is a breaking change and was only approached quite late in the release cycle with little discussion it's opt-in for now. This, or something like it, will become the default in a future version.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.43.0
|
||||
* https://svn.boost.org/trac/boost/ticket/3866[Ticket 3866]: Don't foward declare containers when using gcc's parallel library, allow user to stop forward declaration by defining the `BOOST_DETAIL_NO_CONTAINER_FWD` macro.
|
||||
* https://svn.boost.org/trac/boost/ticket/4038[Ticket 4038]: Avoid hashing `0.5` and `0` to the same number.
|
||||
* Stop using deprecated `BOOST_HAS_*` macros.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.42.0
|
||||
* Reduce the number of warnings for Visual {cpp} warning level 4.
|
||||
* Some code formatting changes to fit lines into 80 characters.
|
||||
* Rename an internal namespace.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.40.0
|
||||
* Automatically configure the `float` functions using template metaprogramming instead of trying to configure every possibility manually.
|
||||
* Workaround for when STLport doesn't support long double.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.39.0
|
||||
* Move the `hash_fwd.hpp` implementation into the hash subdirectory, leaving a forwarding header in the old location. You should still use the old location, the new location is mainly for implementation and possible modularization.
|
||||
* https://svn.boost.org/trac/boost/ticket/2412[Ticket 2412]: Removed deprecated headers.
|
||||
* https://svn.boost.org/trac/boost/ticket/2957[Ticket 2957]: Fix configuration for vxworks.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.38.0
|
||||
* Changed the warnings in the deprecated headers from 1.34.0 to errors. These will be removed in a future version of Boost.
|
||||
* Moved detail headers out of `boost/container_hash/detail`, since they are part of `functional/hash`, not `container_hash`. `boost/container_hash/detail/container_fwd.hpp` has been moved to `boost/detail/container_fwd.hpp` as it's used outside of this library, the others have been moved to `boost/functional/hash/detail`.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.37.0
|
||||
* http://svn.boost.org/trac/boost/ticket/2264[Ticket 2264]: In Visual {cpp}, always use C99 float functions for long double and float as the {cpp} overloads aren't always availables.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.36.0
|
||||
* Stop using OpenBSD's dodgy `std::numeric_limits`.
|
||||
* Using the boost typedefs for `long long` and `unsigned long long`.
|
||||
* Move the extensions into their own header.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.35.0
|
||||
* Support for `long long`, `std::complex`.
|
||||
* Improved algorithm for hashing floating point numbers:
|
||||
** Improved portablity, as described by Daniel Krügler in http://lists.boost.org/boost-users/2005/08/13418.php[a post to the boost users list].
|
||||
** Fits more information into each combine loop, which can reduce the the number of times combine is called and hopefully give a better quality hash function.
|
||||
** Improved the algorithm for hashing floating point numbers.
|
||||
** On Cygwin use a binary hash function for floating point numbers, as Cygwin doesn't have decent floating point functions for `long double`.
|
||||
** Never uses `fpclass` which doesn't support `long double`.
|
||||
** http://svn.boost.org/trac/boost/ticket/1064[Ticket 1064]: Removed unnecessary use of errno.
|
||||
* Explicitly overload for more built in types.
|
||||
* Minor improvements to the documentation.
|
||||
* A few bug and warning fixes:
|
||||
** http://svn.boost.org/trac/boost/ticket/1509[Ticket 1509]: Suppress another Visual {cpp} warning.
|
||||
** Some workarounds for the Sun compilers.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.34.1
|
||||
* https://svn.boost.org/trac10/ticket/952[Ticket 952]: Suppress incorrect 64-bit warning on Visual {cpp}.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.34.0
|
||||
* Use declarations for standard classes, so that the library doesn't need to include all of their headers
|
||||
* Deprecated the `<boost/functional/hash/*.hpp>` headers. Now a single header, `<boost/functional/hash.hpp>` is used.
|
||||
* Add support for the `BOOST_HASH_NO_EXTENSIONS` macro, which disables the extensions to TR1.
|
||||
* Minor improvements to the hash functions for floating point numbers.
|
||||
* Update the portable example to hopefully be more generally portable.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.33.1
|
||||
* Fixed the points example, as pointed out by 沈慧峰.
|
||||
|
||||
[discrete]
|
||||
== Boost 1.33.0
|
||||
* Initial Release
|
||||
123
doc/hash/combine.adoc
Normal file
123
doc/hash/combine.adoc
Normal file
@@ -0,0 +1,123 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#combine]
|
||||
= Combining Hash Values
|
||||
:idprefix: combine_
|
||||
|
||||
Say you have a point class, representing a two dimensional location:
|
||||
|
||||
[source]
|
||||
----
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
|
||||
bool operator==(point const& other) const
|
||||
{
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
};
|
||||
----
|
||||
|
||||
and you wish to use it as the key for an `unordered_map`. You need to
|
||||
customise the hash for this structure. To do this we need to combine the
|
||||
hash values for `x` and `y`. The function `boost::hash_combine` is supplied
|
||||
for this purpose:
|
||||
|
||||
[source]
|
||||
----
|
||||
class point
|
||||
{
|
||||
...
|
||||
|
||||
friend std::size_t hash_value(point const& p)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine(seed, p.x);
|
||||
boost::hash_combine(seed, p.y);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
...
|
||||
};
|
||||
----
|
||||
|
||||
Calls to `hash_combine` incrementally build the hash from the different
|
||||
members of `point`, it can be repeatedly called for any number of elements.
|
||||
It calls `hash_value` on the supplied element, and combines it with the seed.
|
||||
|
||||
Full code for this example is at link:../../examples/point.cpp[examples/point.cpp].
|
||||
|
||||
Note that when using `boost::hash_combine` the order of the calls matters.
|
||||
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, 1);
|
||||
boost::hash_combine(seed, 2);
|
||||
----
|
||||
|
||||
and
|
||||
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, 2);
|
||||
boost::hash_combine(seed, 1);
|
||||
----
|
||||
|
||||
result in a different values in `seed`.
|
||||
|
||||
To calculate the hash of an iterator range you can use `boost::hash_range`:
|
||||
|
||||
[source]
|
||||
----
|
||||
std::vector<std::string> some_strings;
|
||||
std::size_t hash = boost::hash_range(some_strings.begin(), some_strings.end());
|
||||
----
|
||||
|
||||
Since `hash_range` works by repeatedly invoking `hash_combine` on the elements
|
||||
of the range, the hash value will also be dependent on the element order.
|
||||
|
||||
If you are calculating a hash value for a range where the order of the data
|
||||
doesn't matter, such as `unordered_set`, you can use
|
||||
`boost::hash_unordered_range` instead.
|
||||
|
||||
[source]
|
||||
----
|
||||
std::unordered_set<std::string> set;
|
||||
std::size_t hash = boost::hash_unordered_range(set.begin(), set.end());
|
||||
----
|
||||
|
||||
When writing template classes, you might not want to include the main
|
||||
`hash.hpp` header as it's quite an expensive include that brings in a lot of
|
||||
other headers, so instead you can include the
|
||||
`<boost/container_hash/hash_fwd.hpp>` header which forward declares
|
||||
`boost::hash`, `boost::hash_combine`, `boost::hash_range`, and
|
||||
`boost::hash_unordered_range`. You'll need to include the main header before
|
||||
instantiating `boost::hash`. When using a container that uses `boost::hash` it
|
||||
should do that for you, so your type will work fine with the Boost hash
|
||||
containers. There's an example of this in
|
||||
link:../../examples/template.hpp[examples/template.hpp] and
|
||||
link:../../examples/template.cpp[examples/template.cpp].
|
||||
|
||||
To avoid including even `hash_fwd.hpp` - which still requires the contents
|
||||
of Boost.ContainerHash to be physically present - you are allowed to copy the
|
||||
declarations from `hash_fwd.hpp` (and only those) directly into your own
|
||||
header. This is a special exception guaranteed by the library; in general,
|
||||
you can't declare library functions, Boost or otherwise, without risk of
|
||||
breakage in a subsequent release.
|
||||
18
doc/hash/copyright.adoc
Normal file
18
doc/hash/copyright.adoc
Normal file
@@ -0,0 +1,18 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#copyright]
|
||||
= Copyright and License
|
||||
:idprefix:
|
||||
|
||||
This documentation is
|
||||
|
||||
* Copyright 2005-2008 Daniel James
|
||||
* Copyright 2022 Peter Dimov
|
||||
|
||||
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
|
||||
61
doc/hash/describe.adoc
Normal file
61
doc/hash/describe.adoc
Normal file
@@ -0,0 +1,61 @@
|
||||
////
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#describe]
|
||||
= Hashing User Types with Boost.Describe
|
||||
:idprefix: describe_
|
||||
|
||||
Let's look at our `point` class again:
|
||||
|
||||
[source]
|
||||
----
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
};
|
||||
----
|
||||
|
||||
If you're using {cpp}14 or above, a much easier way to add
|
||||
support for `boost::hash` to `point` is by using
|
||||
link:../../../describe/index.html[Boost.Describe] (and
|
||||
get an automatic definition of `operator==` for free):
|
||||
|
||||
[source]
|
||||
----
|
||||
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/describe/operators.hpp>
|
||||
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
BOOST_DESCRIBE_CLASS(point, (), (), (), (x, y))
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
};
|
||||
|
||||
using boost::describe::operators::operator==;
|
||||
using boost::describe::operators::operator!=;
|
||||
----
|
||||
|
||||
(Full code for this example is at
|
||||
link:../../examples/point2.cpp[examples/point2.cpp].)
|
||||
|
||||
Since the `point` class has been annotated with `BOOST_DESCRIBE_CLASS`,
|
||||
the library can enumerate its members (and base classes) and automatically
|
||||
synthesize the appropriate `hash_value` overload for it, without us needing
|
||||
to do so.
|
||||
66
doc/hash/intro.adoc
Normal file
66
doc/hash/intro.adoc
Normal file
@@ -0,0 +1,66 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#intro]
|
||||
= Introduction
|
||||
:idprefix: intro_
|
||||
|
||||
`boost::hash` is an enhanced implementation of the
|
||||
https://en.wikipedia.org/wiki/Hash_function[hash function] object specified by
|
||||
{cpp}11 as `std::hash`. It is the default hash function for
|
||||
link:../../../unordered/index.html[Boost.Unordered],
|
||||
link:../../../intrusive/index.html[Boost.Intrusive]'s unordered associative
|
||||
containers, link:../../../multi_index/index.html[Boost.MultiIndex]'s hash
|
||||
indices, and link:../../../bimap/index.html[Boost.Bimap]'s `unordered_set_of`.
|
||||
|
||||
Out of the box, `boost::hash` supports
|
||||
|
||||
* standard integral types (integers, character types, and `bool`);
|
||||
* standard floating point types (`float`, `double`, `long double`);
|
||||
* pointers (to objects and to functions, but not pointers to members)
|
||||
and `nullptr`;
|
||||
* enumeration types;
|
||||
* C arrays;
|
||||
* `std::complex`;
|
||||
* tuple-like types, such as `std::pair`, `std::tuple`, and user-defined
|
||||
types that specialize `std::tuple_size` and provide `get<I>`;
|
||||
* sequence-like types, both standard and user-defined (sequence-like types
|
||||
have `begin()` and `end()` member functions returning iterators);
|
||||
* unordered sequences, standard or user-defined (sequences for which the hash
|
||||
value does not depend on the element order, such as `std::unordered_set` and
|
||||
`std::unordered_map`);
|
||||
* described structs and classes -- ones that have been annotated with the
|
||||
`BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS` macros from
|
||||
link:../../../describe/index.html[Boost.Describe];
|
||||
* `std::unique_ptr`, `std::shared_ptr`;
|
||||
* `std::type_index`;
|
||||
* `std::error_code`, `std::error_condition`;
|
||||
* `std::optional`;
|
||||
* `std::variant`, `std::monostate`.
|
||||
|
||||
`boost::hash` is extensible; it's possible for a user-defined type `X` to make
|
||||
iself hashable via `boost::hash<X>` by defining an appropriate overload of the
|
||||
function `hash_value`. Many, if not most, Boost types already contain the
|
||||
necessary support.
|
||||
|
||||
`boost::hash` meets the requirements for `std::hash` specified in the {cpp}11
|
||||
standard, namely, that for two different input values their corresponding hash
|
||||
values are either guaranteed to be distinct, or the probability of their being
|
||||
the same (a hash collision) is small. Standard unordered containers, and the
|
||||
hash-based Boost containers, are designed to work well with such hash functions.
|
||||
|
||||
`boost::hash` does not meet the stronger requirements often placed on hash
|
||||
functions in a more general context. In particular, the hash function is not
|
||||
cryptographic, is not collision-resistant against a determined adversary, and
|
||||
does not necessarily possess good "avalanche" properties; that is, small
|
||||
(single bit) perturbations in the input do not necessarily result in large
|
||||
(half bits changing) perturbations in the output.
|
||||
|
||||
In particular, `boost::hash` has traditionally been the identity function for
|
||||
all integral types that fit into `std::size_t`, because this guarantees lack of
|
||||
collisions and is as fast as possible.
|
||||
114
doc/hash/links.adoc
Normal file
114
doc/hash/links.adoc
Normal file
@@ -0,0 +1,114 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#links]
|
||||
= Links
|
||||
:idprefix: links_
|
||||
|
||||
*A Proposal to Add Hash Tables to the Standard Library* +
|
||||
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html
|
||||
|
||||
The hash table proposal explains much of the design. The hash function object is discussed in Section D.
|
||||
|
||||
---
|
||||
|
||||
*The {cpp} Standard Library Technical Report* +
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
|
||||
|
||||
Contains the hash function specification in section 6.3.2.
|
||||
|
||||
---
|
||||
|
||||
*Library Extension Technical Report Issues List* +
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf
|
||||
|
||||
The library implements the extension described in Issue 6.18, pages 63-67.
|
||||
|
||||
---
|
||||
|
||||
*Methods for Identifying Versioned and Plagiarised Documents* +
|
||||
_Timothy C. Hoad, Justin Zobel_ +
|
||||
https://people.eng.unimelb.edu.au/jzobel/fulltext/jasist03thz.pdf
|
||||
|
||||
Contains the hash function that the initial implementation of `boost::hash_combine` was based on.
|
||||
|
||||
---
|
||||
|
||||
*Performance in Practice of String Hashing Functions* +
|
||||
_M.V. Ramakrishna, J. Zobel_ +
|
||||
In Proc. Int. Conf. on Database Systems for Advanced Applications, pages 215-223, Melbourne, Australia, April 1997. +
|
||||
https://www.comp.nus.edu.sg/~lingtw/dasfaa_proceedings/DASFAA97/P215.pdf
|
||||
|
||||
Referenced in the above paper as the source of the hash function.
|
||||
|
||||
---
|
||||
|
||||
*MurmurHash3 hash function source* +
|
||||
_Austin Appleby_ +
|
||||
https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp#L65-L90
|
||||
|
||||
Austin Appleby's 32 and 64 bit finalization mixing functions that
|
||||
introduced the "xmxmx" general form of a high quality bijective
|
||||
transformation that approximates a random permutation.
|
||||
|
||||
---
|
||||
|
||||
*SMHasher hash function test suite* +
|
||||
_Austin Appleby_ +
|
||||
https://github.com/aappleby/smhasher
|
||||
|
||||
Contains a battery of tests for evaluating hash functions. The current
|
||||
64 bit implementation of `boost::hash` for strings passes SMHasher.
|
||||
Previous iterations did not.
|
||||
|
||||
---
|
||||
|
||||
*Better Bit Mixing - Improving on MurmurHash3's 64-bit Finalizer* +
|
||||
_David Stafford_ +
|
||||
https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
|
||||
|
||||
Describes the so-called "variant 13" mixing function, an improvement
|
||||
over `fmix64` from MurmurHash3, made famous by its adoption by the
|
||||
`splitmix64` http://xorshift.di.unimi.it/splitmix64.c[random number generator].
|
||||
|
||||
---
|
||||
|
||||
*Stronger, better, morer, Moremur; a better Murmur3-type mixer* +
|
||||
_Pelle Evensen_ +
|
||||
https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html
|
||||
|
||||
Describes Moremur, an improvement over MurmurHash3 `fmix64` and Stafford
|
||||
"variant 13".
|
||||
|
||||
---
|
||||
|
||||
*Improved mx3 and the RRC test* +
|
||||
_Jon Maiga_ +
|
||||
http://jonkagstrom.com/mx3/mx3_rev2.html
|
||||
|
||||
Contains another improvement over MurmurHash3 `fmix64` and "variant 13". This
|
||||
is what the current implementation of `boost::hash_combine` uses when
|
||||
`std::size_t` is 64 bits.
|
||||
|
||||
---
|
||||
|
||||
*Prospecting for Hash Functions* +
|
||||
_Chris Wellons_ +
|
||||
https://nullprogram.com/blog/2018/07/31/
|
||||
|
||||
Describes https://github.com/skeeto/hash-prospector[Hash Prospector],
|
||||
a utility for discovering and evaluating mixing functions.
|
||||
|
||||
---
|
||||
|
||||
*New best known functions* +
|
||||
_"TheIronBorn"_ +
|
||||
https://github.com/skeeto/hash-prospector/issues/19
|
||||
|
||||
Describes a good 32 bit mixing function, used by the current implementation
|
||||
of `boost::hash_combine` when `std::size_t` is 32 bits.
|
||||
228
doc/hash/notes.adoc
Normal file
228
doc/hash/notes.adoc
Normal file
@@ -0,0 +1,228 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#notes]
|
||||
= Design and Implementation Notes
|
||||
:idprefix: notes_
|
||||
|
||||
== Quality of the Hash Function
|
||||
|
||||
Many hash functions strive to have little correlation between the input and
|
||||
output values. They attempt to uniformally distribute the output values for
|
||||
very similar inputs. This hash function makes no such attempt. In fact, for
|
||||
integers, the result of the hash function is often just the input value. So
|
||||
similar but different input values will often result in similar but different
|
||||
output values. This means that it is not appropriate as a general hash
|
||||
function. For example, a hash table may discard bits from the hash function
|
||||
resulting in likely collisions, or might have poor collision resolution when
|
||||
hash values are clustered together. In such cases this hash function will
|
||||
perform poorly.
|
||||
|
||||
But the standard has no such requirement for the hash function, it just
|
||||
requires that the hashes of two different values are unlikely to collide.
|
||||
Containers or algorithms designed to work with the standard hash function will
|
||||
have to be implemented to work well when the hash function's output is
|
||||
correlated to its input. Since they are paying that cost a higher quality hash
|
||||
function would be wasteful.
|
||||
|
||||
== The hash_value Customization Point
|
||||
|
||||
The way one customizes the standard `std::hash` function object for user
|
||||
types is via a specialization. `boost::hash` chooses a different mechanism --
|
||||
an overload of a free function `hash_value` in the user namespace that is
|
||||
found via argument-dependent lookup.
|
||||
|
||||
Both approaches have their pros and cons. Specializing the function object
|
||||
is stricter in that it only applies to the exact type, and not to derived
|
||||
or convertible types. Defining a function, on the other hand, is easier
|
||||
and more convenient, as it can be done directly in the type definition as
|
||||
an `inline` `friend`.
|
||||
|
||||
The fact that overloads can be invoked via conversions did cause issues in
|
||||
an earlier iteration of the library that defined `hash_value` for all
|
||||
integral types separately, including `bool`. Especially under {cpp}03,
|
||||
which doesn't have `explicit` conversion operators, some types were
|
||||
convertible to `bool` to allow their being tested in e.g. `if` statements,
|
||||
which caused them to hash to 0 or 1, rarely what one expects or wants.
|
||||
|
||||
This, however, was fixed by declaring the built-in `hash_value` overloads
|
||||
to be templates constrained on e.g. `std::is_integral` or its moral
|
||||
equivalent. This causes types convertible to an integral to no longer
|
||||
match, avoiding the problem.
|
||||
|
||||
== Hash Value Stability
|
||||
|
||||
In general, the library does not promise that the hash values will stay
|
||||
the same from release to release (otherwise improvements would be
|
||||
impossible). However, historically values have been quite stable. Before
|
||||
release 1.81, the previous changes have been in 1.56 (a better
|
||||
`hash_combine`) and 1.78 (macOS-specific change to `hash_combine`.)
|
||||
|
||||
Code should generally not depend on specific hash values, but for those
|
||||
willing to take the risk of occasional breaks due to hash value changes,
|
||||
the library now has a test that checks hash values for a number of types
|
||||
against reference values (`test/hash_reference_values.cpp`),
|
||||
whose https://github.com/boostorg/container_hash/commits/develop/test/hash_reference_values.cpp[version history]
|
||||
can be used as a rough guide to when hash values have changed, and for what
|
||||
types.
|
||||
|
||||
== hash_combine
|
||||
|
||||
The initial implementation of the library was based on Issue 6.18 of the
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf[Library Extension Technical Report Issues List]
|
||||
(pages 63-67) which proposed the following implementation of `hash_combine`:
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T>
|
||||
void hash_combine(size_t & seed, T const & v)
|
||||
{
|
||||
seed ^= hash_value(v) + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
----
|
||||
|
||||
taken from the paper
|
||||
"https://people.eng.unimelb.edu.au/jzobel/fulltext/jasist03thz.pdf[Methods for Identifying Versioned and Plagiarised Documents]"
|
||||
by Timothy C. Hoad and Justin Zobel.
|
||||
|
||||
During the Boost formal review, Dave Harris pointed out that this suffers
|
||||
from the so-called "zero trap"; if `seed` is initially 0, and all the
|
||||
inputs are 0 (or hash to 0), `seed` remains 0 no matter how many input
|
||||
values are combined.
|
||||
|
||||
This is an undesirable property, because it causes containers of zeroes
|
||||
to have a zero hash value regardless of their sizes.
|
||||
|
||||
To fix this, the arbitrary constant `0x9e3779b9` (the golden ratio in a
|
||||
32 bit fixed point representation) was added to the computation, yielding
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T>
|
||||
void hash_combine(size_t & seed, T const & v)
|
||||
{
|
||||
seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
----
|
||||
|
||||
This is what shipped in Boost 1.33, the first release containing the library.
|
||||
|
||||
This function was a reasonable compromise between quality and speed for its
|
||||
time, when the input consisted of ``char``s, but it's less suitable for
|
||||
combining arbitrary `size_t` inputs.
|
||||
|
||||
In Boost 1.56, it was replaced by functions derived from Austin Appleby's
|
||||
https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L57-L62[MurmurHash2 hash function round].
|
||||
|
||||
In Boost 1.81, it was changed again -- to the equivalent of
|
||||
`mix(seed + 0x9e3779b9 + hash_value(v))`, where `mix(x)` is a high quality
|
||||
mixing function that is a bijection over the `size_t` values, of the form
|
||||
|
||||
[source]
|
||||
----
|
||||
x ^= x >> k1;
|
||||
x *= m1;
|
||||
x ^= x >> k2;
|
||||
x *= m2;
|
||||
x ^= x >> k3;
|
||||
----
|
||||
|
||||
This type of mixing function was originally devised by Austin Appleby as
|
||||
the "final mix" part of his MurmurHash3 hash function. He used
|
||||
|
||||
[source]
|
||||
----
|
||||
x ^= x >> 33;
|
||||
x *= 0xff51afd7ed558ccd;
|
||||
x ^= x >> 33;
|
||||
x *= 0xc4ceb9fe1a85ec53;
|
||||
x ^= x >> 33;
|
||||
----
|
||||
|
||||
as the https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L57-L62[64 bit function `fmix64`] and
|
||||
|
||||
[source]
|
||||
----
|
||||
x ^= x >> 16;
|
||||
x *= 0x85ebca6b;
|
||||
x ^= x >> 13;
|
||||
x *= 0xc2b2ae35;
|
||||
x ^= x >> 16;
|
||||
----
|
||||
|
||||
as the https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash3.cpp#L68-L77[32 bit function `fmix32`].
|
||||
|
||||
Several improvements of the 64 bit function have been subsequently proposed,
|
||||
by https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html[David Stafford],
|
||||
https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html[Pelle Evensen],
|
||||
and http://jonkagstrom.com/mx3/mx3_rev2.html[Jon Maiga]. We currently use Jon
|
||||
Maiga's function
|
||||
|
||||
[source]
|
||||
----
|
||||
x ^= x >> 32;
|
||||
x *= 0xe9846af9b1a615d;
|
||||
x ^= x >> 32;
|
||||
x *= 0xe9846af9b1a615d;
|
||||
x ^= x >> 28;
|
||||
----
|
||||
|
||||
Under 32 bit, we use a mixing function proposed by "TheIronBorn" in a
|
||||
https://github.com/skeeto/hash-prospector/issues/19[Github issue] in
|
||||
the https://github.com/skeeto/hash-prospector[repository] of
|
||||
https://nullprogram.com/blog/2018/07/31/[Hash Prospector] by Chris Wellons:
|
||||
|
||||
[source]
|
||||
----
|
||||
x ^= x >> 16;
|
||||
x *= 0x21f0aaad;
|
||||
x ^= x >> 15;
|
||||
x *= 0x735a2d97;
|
||||
x ^= x >> 15;
|
||||
----
|
||||
|
||||
With this improved `hash_combine`, `boost::hash` for strings now passes the
|
||||
https://github.com/aappleby/smhasher[SMHasher test suite] by Austin Appleby
|
||||
(for a 64 bit `size_t`).
|
||||
|
||||
== hash_range
|
||||
|
||||
The traditional implementation of `hash_range(seed, first, last)` has been
|
||||
|
||||
[source]
|
||||
----
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
|
||||
}
|
||||
----
|
||||
|
||||
(the explicit template parameter is needed to support iterators with proxy
|
||||
return types such as `std::vector<bool>::iterator`.)
|
||||
|
||||
This is logical, consistent and straightforward. In the common case where
|
||||
`typename std::iterator_traits<It>::value_type` is `char` -- which it is
|
||||
in the common case of `boost::hash<std::string>` -- this however leaves a
|
||||
lot of performance on the table, because processing each `char` individually
|
||||
is much less efficient than processing several in bulk.
|
||||
|
||||
In Boost 1.81, `hash_range` was changed to process elements of type `char`,
|
||||
`signed char`, `unsigned char`, `std::byte`, or `char8_t`, four of a time.
|
||||
A `uint32_t` is composed from `first[0]` to `first[3]`, and that `uint32_t`
|
||||
is fed to `hash_combine`.
|
||||
|
||||
In Boost 1.82, `hash_range` for these types was changed to use
|
||||
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`]. This improves both
|
||||
quality and speed of string hashing.
|
||||
|
||||
Note that `hash_range` has also traditionally guaranteed that the same element
|
||||
sequence yields the same hash value regardless of the iterator type. This
|
||||
property remains valid after the changes to `char` range hashing. `hash_range`,
|
||||
applied to the `char` sequence `{ 'a', 'b', 'c' }`, results in the same value
|
||||
whether the sequence comes from `char[3]`, `std::string`, `std::deque<char>`,
|
||||
or `std::list<char>`.
|
||||
60
doc/hash/recent.adoc
Normal file
60
doc/hash/recent.adoc
Normal file
@@ -0,0 +1,60 @@
|
||||
////
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#recent]
|
||||
= Recent Changes
|
||||
:idprefix: recent_
|
||||
|
||||
== Boost 1.89.0
|
||||
|
||||
* Added the `hash_is_avalanching` trait class.
|
||||
|
||||
== Boost 1.84.0
|
||||
|
||||
* {cpp}03 is no longer supported.
|
||||
|
||||
== Boost 1.82.0
|
||||
|
||||
* Added an overload of `hash_value` for `std::nullptr_t`.
|
||||
* Added `is_tuple_like` and an overload of `hash_value` for
|
||||
tuple-like types.
|
||||
* Changed string hashing to use
|
||||
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`],
|
||||
improving both quality and speed. This changes the hash values
|
||||
for string-like types (ranges of `char`, `signed char`,
|
||||
`unsigned char`, `std::byte`, `char8_t`).
|
||||
|
||||
== Boost 1.81.0
|
||||
|
||||
Major update.
|
||||
|
||||
* The specializations of `boost::hash` have been removed; it now
|
||||
always calls `hash_value`.
|
||||
* Support for `BOOST_HASH_NO_EXTENSIONS` has been removed. The
|
||||
extensions are always enabled.
|
||||
* All standard containers are now supported. This includes
|
||||
`std::forward_list` and the unordered associative containers.
|
||||
* User-defined containers (types that have `begin()` and `end()`
|
||||
member functions that return iterators) are now supported out
|
||||
of the box.
|
||||
* Described structs and classes (those annotated with
|
||||
`BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS`) are now
|
||||
supported out of the box.
|
||||
* `hash_combine` has been improved. This changes the hash values
|
||||
of composite (container and tuple) types and of scalar types
|
||||
bigger than `size_t`.
|
||||
* The performance (and quality, as a result of the above change)
|
||||
of string hashing has been improved. `boost::hash` for strings
|
||||
now passes SMHasher in 64 bit mode.
|
||||
* The documentation has been substantially revised to reflect
|
||||
the changes.
|
||||
|
||||
== Boost 1.78.0
|
||||
|
||||
* Fixed `hash_combine` so that its behavior no longer depends
|
||||
on whether `size_t` is the exact same type as `boost::uint64_t`
|
||||
(which wasn't the case on macOS). This changes the hash values
|
||||
of composite (container and tuple) types on macOS.
|
||||
806
doc/hash/reference.adoc
Normal file
806
doc/hash/reference.adoc
Normal file
@@ -0,0 +1,806 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022, 2025 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#reference]
|
||||
= Reference
|
||||
:idprefix: ref_
|
||||
|
||||
== <boost/container_hash/{zwsp}hash_fwd.hpp>
|
||||
|
||||
This header contains forward declarations for the library primitives.
|
||||
These declarations are guaranteed to be relatively stable, that is,
|
||||
best effort will be expended on their not changing from release to
|
||||
release, allowing their verbatim copy into user headers that do not
|
||||
wish to physically depend on Boost.ContainerHash.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_range;
|
||||
template<class T> struct is_contiguous_range;
|
||||
template<class T> struct is_unordered_range;
|
||||
template<class T> struct is_described_class;
|
||||
template<class T> struct is_tuple_like;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
template<class T> struct hash;
|
||||
|
||||
template<class T> void hash_combine( std::size_t& seed, T const& v );
|
||||
|
||||
template<class It> void hash_range( std::size_t& seed, It first, It last );
|
||||
template<class It> std::size_t hash_range( It first, It last );
|
||||
|
||||
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
|
||||
template<class It> std::size_t hash_unordered_range( It first, It last );
|
||||
|
||||
template<class Hash> struct hash_is_avalanching;
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
== <boost/container_hash/{zwsp}hash.hpp>
|
||||
|
||||
Defines `boost::hash`, and helper functions.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<class T> struct hash;
|
||||
|
||||
template<class T> void hash_combine( std::size_t& seed, T const& v );
|
||||
|
||||
template<class It> void hash_range( std::size_t& seed, It first, It last );
|
||||
template<class It> std::size_t hash_range( It first, It last );
|
||||
|
||||
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
|
||||
template<class It> std::size_t hash_unordered_range( It first, It last );
|
||||
|
||||
// Enabled only when T is an integral type
|
||||
template<class T>
|
||||
std::size_t hash_value( T v );
|
||||
|
||||
// Enabled only when T is an enumeration type
|
||||
template<class T>
|
||||
std::size_t hash_value( T v );
|
||||
|
||||
// Enabled only when T is a floating point type
|
||||
template<class T>
|
||||
std::size_t hash_value( T v );
|
||||
|
||||
template<class T>
|
||||
std::size_t hash_value( T* const& v );
|
||||
|
||||
template<class T, std::size_t N>
|
||||
std::size_t hash_value( T const (&v)[N] );
|
||||
|
||||
template<class T>
|
||||
std::size_t hash_value( std::complex<T> const& v );
|
||||
|
||||
template<class A, class B>
|
||||
std::size_t hash_value( std::pair<A, B> const& v );
|
||||
|
||||
// Enabled only when container_hash::is_tuple_like<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
// Enabled only when container_hash::is_range<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
// Enabled only when container_hash::is_contiguous_range<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
// Enabled only when container_hash::is_unordered_range<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
// Enabled only when container_hash::is_described_class<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
|
||||
template<class T>
|
||||
std::size_t hash_value( std::shared_ptr<T> const& v );
|
||||
|
||||
template<class T, class D>
|
||||
std::size_t hash_value( std::unique_ptr<T, D> const& v );
|
||||
|
||||
std::size_t hash_value( std::type_index const& v );
|
||||
|
||||
std::size_t hash_value( std::error_code const& v );
|
||||
std::size_t hash_value( std::error_condition const& v );
|
||||
|
||||
template<class T>
|
||||
std::size_t hash_value( std::optional<T> const& v );
|
||||
|
||||
std::size_t hash_value( std::monostate v );
|
||||
|
||||
template<class... T>
|
||||
std::size_t hash_value( std::variant<T...> const& v );
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== hash<T>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> struct hash
|
||||
{
|
||||
std::size_t operator()( T const& v ) const;
|
||||
};
|
||||
----
|
||||
|
||||
==== operator()
|
||||
|
||||
[source]
|
||||
----
|
||||
std::size_t operator()( T const& v ) const;
|
||||
----
|
||||
|
||||
Returns: :: `hash_value(v)`.
|
||||
|
||||
Throws: :: Only throws if `hash_value(v)` throws.
|
||||
|
||||
Remarks: :: The call to `hash_value` is unqualified, so that user-supplied
|
||||
overloads will be found via argument dependent lookup.
|
||||
|
||||
=== hash_combine
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> void hash_combine( std::size_t& seed, T const& v );
|
||||
----
|
||||
|
||||
Called repeatedly to incrementally create a hash value from several variables.
|
||||
|
||||
Effects: :: Updates `seed` with a new hash value generated by
|
||||
deterministically combining it with the result of `boost::hash<T>()(v)`.
|
||||
|
||||
Throws: :: Only throws if `boost::hash<T>()(v)` throws. On exception,
|
||||
`seed` is not updated.
|
||||
|
||||
Remarks: ::
|
||||
+
|
||||
--
|
||||
Equivalent to `seed = combine(seed, boost::hash<T>()(v))`,
|
||||
where `combine(s, v)` is a mixing function that takes two arguments of
|
||||
type `std::size_t` and returns `std::size_t`, with the following desirable
|
||||
properties:
|
||||
|
||||
. For a constant `s`, when `v` takes all possible `size_t` values,
|
||||
`combine(s, v)` should also take all possible `size_t` values, producing
|
||||
a sequence that is close to random; that is, it should be a random
|
||||
permutation.
|
||||
+
|
||||
This guarantees that for a given `seed`, `combine` does not introduce
|
||||
hash collisions when none were produced by `boost::hash<T>(v)`; that is,
|
||||
it does not lose information from the input. It also implies that
|
||||
`combine(s, v)`, as a function of `v`, has good avalanche properties;
|
||||
that is, small (e.g. single bit) perturbations in the input `v` lead to
|
||||
large perturbations in the return value (half of the output bits changing,
|
||||
on average).
|
||||
|
||||
. For two different seeds `s1` and `s2`, `combine(s1, v)` and
|
||||
`combine(s2, v)`, treated as functions of `v`, should produce two
|
||||
different random permutations.
|
||||
|
||||
. `combine(0, 0)` should not be 0. Since a common initial value of `seed`
|
||||
is zero, `combine(0, 0) == 0` would imply that applying `hash_combine` on
|
||||
any sequence of zeroes, regardless of length, will produce zero. This is
|
||||
undesirable, as it would lead to e.g. `std::vector<int>()` and
|
||||
`std::vector<int>(4)` to have the same hash value.
|
||||
|
||||
The current implementation uses the function `mix(s + 0x9e3779b9 + v)` as
|
||||
`combine(s, v)`, where `mix(x)` is a high quality mixing function that is a
|
||||
bijection over the `std::size_t` values, of the form
|
||||
|
||||
[source]
|
||||
----
|
||||
x ^= x >> k1;
|
||||
x *= m1;
|
||||
x ^= x >> k2;
|
||||
x *= m2;
|
||||
x ^= x >> k3;
|
||||
----
|
||||
|
||||
where the constants `k1`, `k2`, `k3`, `m1`, `m2` are suitably chosen.
|
||||
|
||||
Note that `mix(0)` is 0. This is why we add the arbitrary constant
|
||||
`0x9e3779b9` to meet the third requirement above.
|
||||
--
|
||||
|
||||
=== hash_range
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class It> void hash_range( std::size_t& seed, It first, It last );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
--
|
||||
When `typename std::iterator_traits<It>::value_type` is not `char`, `signed char`,
|
||||
`unsigned char`, `std::byte`, or `char8_t`,
|
||||
|
||||
[source]
|
||||
----
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
boost::hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
|
||||
}
|
||||
----
|
||||
|
||||
Otherwise, bytes from `[first, last)` are coalesced and hashed in an
|
||||
unspecified manner. This is done in order to improve performance when hashing
|
||||
strings.
|
||||
--
|
||||
|
||||
Remarks: ::
|
||||
For chars, the current implementation uses
|
||||
https://github.com/pdimov/mulxp_hash[`mulxp1_hash`] when `std::size_t` is
|
||||
64 bit, and `mulxp1_hash32` when it's 32 bit.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class It> std::size_t hash_range( It first, It last );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
size_t seed = 0;
|
||||
boost::hash_range( seed, first, last );
|
||||
return seed;
|
||||
----
|
||||
|
||||
=== hash_unordered_range
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class It> void hash_unordered_range( std::size_t& seed, It first, It last );
|
||||
----
|
||||
|
||||
Effects: :: Updates `seed` with the values of
|
||||
`boost::hash<typename std::iterator_traits<It>::value_type>()(*i)`
|
||||
for each `i` in `[first, last)`, such that the order of elements does
|
||||
not affect the final result.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class It> std::size_t hash_unordered_range( It first, It last );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
size_t seed = 0;
|
||||
boost::hash_unordered_range( seed, first, last );
|
||||
return seed;
|
||||
----
|
||||
|
||||
=== hash_value
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when T is an integral type
|
||||
template<class T>
|
||||
std::size_t hash_value( T v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
When the value of `v` fits into `std::size_t`, when `T` is an unsigned type,
|
||||
or into `ssize_t`, when `T` is a signed type, `static_cast<std::size_t>(v)`.
|
||||
+
|
||||
Otherwise, an unspecified value obtained by mixing the value bits of `v`.
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when T is an enumeration type
|
||||
template<class T>
|
||||
std::size_t hash_value( T v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
`static_cast<std::size_t>(v)`.
|
||||
|
||||
Remarks: ::
|
||||
`hash_value(std::to_underlying(v))` would be better, but {cpp}03
|
||||
compatibility mandates the current implementation.
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when T is a floating point type
|
||||
template<class T>
|
||||
std::size_t hash_value( T v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
An unspecified value obtained by mixing the value bits of `v`.
|
||||
|
||||
Remarks: ::
|
||||
When `sizeof(v) \<= sizeof(std::size_t)`, the bits of `v` are returned
|
||||
as-is (except in the case of -0.0, which is treated as +0.0).
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T>
|
||||
std::size_t hash_value( T* const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
An unspecified value derived from `reinterpret_cast<std::uintptr_t>(v)`.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T, std::size_t N>
|
||||
std::size_t hash_value( T const (&v)[N] );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
`boost::hash_range( v, v + N )`.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T>
|
||||
std::size_t hash_value( std::complex<T> const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
An unspecified value derived from `boost::hash<T>()(v.real())` and
|
||||
`boost::hash<T>()(v.imag())` such that, if `v.imag() == 0`, the value
|
||||
is equal to `boost::hash<T>()(v.real())`.
|
||||
|
||||
Remarks: ::
|
||||
A more straightforward implementation would just have used `hash_combine`
|
||||
on `v.real()` and `v.imag()`, but the historical guarantee that real-valued
|
||||
complex numbers should match the hash value of their real part precludes it.
|
||||
+
|
||||
This guarantee may be dropped in a future release, as it's of questionable
|
||||
utility.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class A, class B>
|
||||
std::size_t hash_value( std::pair<A, B> const& v );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.first );
|
||||
boost::hash_combine( seed, v.second );
|
||||
|
||||
return seed;
|
||||
----
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when container_hash::is_tuple_like<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
|
||||
using std::get;
|
||||
|
||||
boost::hash_combine( seed, get<0>(v) );
|
||||
boost::hash_combine( seed, get<1>(v) );
|
||||
// ...
|
||||
boost::hash_combine( seed, get<N-1>(v) );
|
||||
|
||||
return seed;
|
||||
----
|
||||
+
|
||||
where `N` is `std::tuple_size<T>::value`.
|
||||
|
||||
Remarks: ::
|
||||
This overload is only enabled when
|
||||
`container_hash::is_range<T>::value` is `false`.
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when container_hash::is_range<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
`boost::hash_range( v.begin(), v.end() )`.
|
||||
|
||||
Remarks: ::
|
||||
This overload is only enabled when
|
||||
`container_hash::is_contiguous_range<T>::value` and
|
||||
`container_hash::is_unordered_range<T>::value` are both `false`.
|
||||
+
|
||||
It handles all standard containers that aren't contiguous or unordered, such
|
||||
as `std::deque`, `std::list`, `std::set`, `std::map`.
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when container_hash::is_contiguous_range<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
`boost::hash_range( v.data(), v.data() + v.size() )`.
|
||||
|
||||
Remarks: ::
|
||||
This overload handles all standard contiguous containers, such as
|
||||
`std::string`, `std::vector`, `std::array`, `std::string_view`.
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when container_hash::is_unordered_range<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
`boost::hash_unordered_range( v.begin(), v.end() )`.
|
||||
|
||||
Remarks: ::
|
||||
This overload handles the standard unordered containers, such as
|
||||
`std::unordered_set` and `std::unordered_map`.
|
||||
|
||||
[source]
|
||||
----
|
||||
// Enabled only when container_hash::is_described_class<T>::value is true
|
||||
template<class T>
|
||||
std::size_t hash_value( T const& v );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, b1 );
|
||||
boost::hash_combine( seed, b2 );
|
||||
// ...
|
||||
boost::hash_combine( seed, bM );
|
||||
|
||||
boost::hash_combine( seed, m1 );
|
||||
boost::hash_combine( seed, m2 );
|
||||
// ...
|
||||
boost::hash_combine( seed, mN );
|
||||
|
||||
return seed;
|
||||
----
|
||||
+
|
||||
where `bi` are the bases of `v` and `mi` are its members.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T>
|
||||
std::size_t hash_value( std::shared_ptr<T> const& v );
|
||||
|
||||
template<class T, class D>
|
||||
std::size_t hash_value( std::unique_ptr<T, D> const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
`boost::hash<T*>( v.get() )`.
|
||||
|
||||
[source]
|
||||
----
|
||||
std::size_t hash_value( std::type_index const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
`v.hash_code()`.
|
||||
|
||||
[source]
|
||||
----
|
||||
std::size_t hash_value( std::error_code const& v );
|
||||
std::size_t hash_value( std::error_condition const& v );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.value() );
|
||||
boost::hash_combine( seed, &v.category() );
|
||||
|
||||
return seed;
|
||||
----
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T>
|
||||
std::size_t hash_value( std::optional<T> const& v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
For a disengaged `v`, an unspecified constant value; otherwise,
|
||||
`boost::hash<T>()( *v )`.
|
||||
|
||||
[source]
|
||||
----
|
||||
std::size_t hash_value( std::monostate v );
|
||||
----
|
||||
|
||||
Returns: ::
|
||||
An unspecified constant value.
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class... T>
|
||||
std::size_t hash_value( std::variant<T...> const& v );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
[source]
|
||||
----
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.index() );
|
||||
boost::hash_combine( seed, x );
|
||||
|
||||
return seed;
|
||||
----
|
||||
+
|
||||
where `x` is the currently contained value in `v`.
|
||||
|
||||
Throws: ::
|
||||
`std::bad_variant_access` when `v.valueless_by_exception()` is `true`.
|
||||
|
||||
== <boost/container_hash/{zwsp}hash_is_avalanching.hpp>
|
||||
|
||||
Defines the trait `boost::hash_is_avalanching`.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<class Hash> struct hash_is_avalanching;
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== hash_is_avalanching<Hash>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class Hash> struct hash_is_avalanching
|
||||
{
|
||||
static constexpr bool value = /* see below */;
|
||||
};
|
||||
----
|
||||
|
||||
`hash_is_avalanching<Hash>::value` is:
|
||||
|
||||
* `false` if `Hash::is_avalanching` is not present,
|
||||
* `Hash::is_avalanching::value` if this is present and convertible at compile time to a `bool`,
|
||||
* `true` if `Hash::is_avalanching` is `void` (this usage is deprecated),
|
||||
* ill-formed otherwise.
|
||||
|
||||
A hash function is said to have the _avalanching property_ if small changes
|
||||
in the input translate to large changes in the returned hash code
|
||||
—ideally, flipping one bit in the representation of the input value results
|
||||
in each bit of the hash code flipping with probability 50%. Libraries
|
||||
such as link:../../../unordered/index.html[Boost.Unordered] consult this trait
|
||||
to determine if the supplied hash function is of high quality.
|
||||
`boost::hash` for `std::basic_string<Ch>` and `std::basic_string_view<Ch>`
|
||||
has this trait set to `true` when `Ch` is an integral type (this includes
|
||||
`std::string` and `std::string_view`, among others).
|
||||
Users can set this trait for a particular `Hash` type by:
|
||||
|
||||
* Inserting the nested `is_avalanching` typedef in the class definition
|
||||
if they have access to its source code.
|
||||
* Writing a specialization of `boost::hash_is_avalanching`
|
||||
for `Hash`.
|
||||
|
||||
Note that usage of this trait is not restricted to hash functions produced
|
||||
with Boost.ContainerHash.
|
||||
|
||||
== <boost/container_hash/{zwsp}is_range.hpp>
|
||||
|
||||
Defines the trait `boost::container_hash::is_range`.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_range;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== is_range<T>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> struct is_range
|
||||
{
|
||||
static constexpr bool value = /* see below */;
|
||||
};
|
||||
----
|
||||
|
||||
`is_range<T>::value` is `true` when, for a const value `x` of type
|
||||
`T`, `x.begin()` and `x.end()` return iterators of the same type
|
||||
`It` (such that `std::iterator_traits<It>` is a valid specialization.)
|
||||
|
||||
Users are allowed to specialize `is_range` for their types if the
|
||||
default behavior does not deduce the correct value.
|
||||
|
||||
== <boost/container_hash/{zwsp}is_contiguous_range.hpp>
|
||||
|
||||
Defines the trait `boost::container_hash::is_contiguous_range`.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_contiguous_range;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== is_contiguous_range<T>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> struct is_contiguous_range
|
||||
{
|
||||
static constexpr bool value = /* see below */;
|
||||
};
|
||||
----
|
||||
|
||||
`is_contiguous_range<T>::value` is `true` when `is_range<T>::value` is
|
||||
`true` and when, for a const value `x` of type `T`, `x.data()` returns
|
||||
a pointer to a type that matches the `value_type` of the iterator returned
|
||||
by `x.begin()` and `x.end()`, and `x.size()` returns a value of an integral
|
||||
type.
|
||||
|
||||
Users are allowed to specialize `is_contiguous_range` for their types
|
||||
if the default behavior does not deduce the correct value.
|
||||
|
||||
== <boost/container_hash/{zwsp}is_unordered_range.hpp>
|
||||
|
||||
Defines the trait `boost::container_hash::is_unordered_range`.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_unordered_range;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== is_unordered_range<T>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> struct is_unordered_range
|
||||
{
|
||||
static constexpr bool value = /* see below */;
|
||||
};
|
||||
----
|
||||
|
||||
`is_unordered_range<T>::value` is `true` when `is_range<T>::value` is
|
||||
`true` and when `T::hasher` is a valid type.
|
||||
|
||||
Users are allowed to specialize `is_unordered_range` for their types
|
||||
if the default behavior does not deduce the correct value.
|
||||
|
||||
== <boost/container_hash/{zwsp}is_described_class.hpp>
|
||||
|
||||
Defines the trait `boost::container_hash::is_described_class`.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_described_class;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== is_described_class<T>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> struct is_described_class
|
||||
{
|
||||
static constexpr bool value = /* see below */;
|
||||
};
|
||||
----
|
||||
|
||||
`is_described_class<T>::value` is `true` when
|
||||
`boost::describe::has_describe_bases<T>::value` is `true`,
|
||||
`boost::describe::has_describe_members<T>::value` is `true`, and
|
||||
`T` is not a union.
|
||||
|
||||
Users are allowed to specialize `is_described_class` for their types
|
||||
if the default behavior does not deduce the correct value.
|
||||
|
||||
== <boost/container_hash/{zwsp}is_tuple_like.hpp>
|
||||
|
||||
Defines the trait `boost::container_hash::is_tuple_like`.
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_tuple_like;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
} // namespace boost
|
||||
----
|
||||
|
||||
=== is_tuple_like<T>
|
||||
|
||||
[source]
|
||||
----
|
||||
template<class T> struct is_tuple_like
|
||||
{
|
||||
static constexpr bool value = /* see below */;
|
||||
};
|
||||
----
|
||||
|
||||
`is_tuple_like<T>::value` is `true` when `std::tuple_size<T>::value`
|
||||
is valid.
|
||||
|
||||
Users are allowed to specialize `is_tuple_like` for their types
|
||||
if the default behavior does not deduce the correct value.
|
||||
23
doc/hash/thanks.adoc
Normal file
23
doc/hash/thanks.adoc
Normal file
@@ -0,0 +1,23 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#thanks]
|
||||
= Acknowledgements
|
||||
:idprefix: thanks_
|
||||
|
||||
This library is based on the design by Peter Dimov. During the initial development Joaquín M López Muñoz made many useful suggestions and contributed fixes.
|
||||
|
||||
The formal review was managed by Thorsten Ottosen, and the library reviewed by: David Abrahams, Alberto Barbati, Topher Cooper, Caleb Epstein, Dave Harris, Chris Jefferson, Bronek Kozicki, John Maddock, Tobias Swinger, Jaap Suter, Rob Stewart and Pavel Vozenilek. Since then, further constructive criticism has been made by Daniel Krügler, Alexander Nasonov and 沈慧峰.
|
||||
|
||||
The implementation of the hash function for pointers is based on suggestions made by Alberto Barbati and Dave Harris. Dave Harris also suggested an important improvement to `boost::hash_combine` that was taken up.
|
||||
|
||||
Some useful improvements to the floating point hash algorithm were suggested by Daniel Krügler.
|
||||
|
||||
The original implementation came from Jeremy B. Maitin-Shepard's hash table library, although this is a complete rewrite.
|
||||
|
||||
The documentation was converted from Quickbook to AsciiDoc by Christian Mazakas.
|
||||
72
doc/hash/tutorial.adoc
Normal file
72
doc/hash/tutorial.adoc
Normal file
@@ -0,0 +1,72 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#tutorial]
|
||||
= Tutorial
|
||||
:idprefix: tutorial_
|
||||
|
||||
When using a Boost container such as
|
||||
link:../../../unordered/index.html[Boost.Unordered], you don't need to do
|
||||
anything to use `boost::hash` as it's the default. To find out how to use
|
||||
a user-defined type, read the <<user,section on extending boost::hash
|
||||
for user types>>.
|
||||
|
||||
If you wish to use `boost::hash` with the standard unordered associative
|
||||
containers, pass it as a template parameter:
|
||||
|
||||
[source]
|
||||
----
|
||||
std::unordered_multiset<int, boost::hash<int> >
|
||||
set_of_ints;
|
||||
|
||||
std::unordered_set<std::pair<int, int>, boost::hash<std::pair<int, int> > >
|
||||
set_of_pairs;
|
||||
|
||||
std::unordered_map<int, std::string, boost::hash<int> > map_int_to_string;
|
||||
----
|
||||
|
||||
To use `boost::hash` directly, create an instance and call it as a function:
|
||||
|
||||
[source]
|
||||
----
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::hash<std::string> string_hash;
|
||||
std::size_t h = string_hash("Hash me");
|
||||
}
|
||||
----
|
||||
|
||||
or alternatively:
|
||||
|
||||
[source]
|
||||
----
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::size_t h = boost::hash<std::string>()("Hash me");
|
||||
}
|
||||
----
|
||||
|
||||
For an example of generic use, here is a function to generate a vector
|
||||
containing the hashes of the elements of a container:
|
||||
|
||||
[source]
|
||||
----
|
||||
template <class Container>
|
||||
std::vector<std::size_t> get_hashes(Container const& x)
|
||||
{
|
||||
std::vector<std::size_t> hashes;
|
||||
std::transform(x.begin(), x.end(), std::back_inserter(hashes),
|
||||
boost::hash<typename Container::value_type>());
|
||||
|
||||
return hashes;
|
||||
}
|
||||
----
|
||||
86
doc/hash/user.adoc
Normal file
86
doc/hash/user.adoc
Normal file
@@ -0,0 +1,86 @@
|
||||
////
|
||||
Copyright 2005-2008 Daniel James
|
||||
Copyright 2022 Christian Mazakas
|
||||
Copyright 2022 Peter Dimov
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://www.boost.org/LICENSE_1_0.txt
|
||||
////
|
||||
|
||||
[#user]
|
||||
= Extending boost::hash for User Types
|
||||
:idprefix: user_
|
||||
|
||||
`boost::hash` is implemented by calling the function `hash_value`. The
|
||||
namespace isn't specified so that it can detect overloads via argument
|
||||
dependant lookup. So if there is a free function `hash_value` in the same
|
||||
namespace as a user type, it will get called.
|
||||
|
||||
If you have a structure `library::book`, where each book is uniquely defined
|
||||
by its member `id`:
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace library
|
||||
{
|
||||
struct book
|
||||
{
|
||||
int id;
|
||||
std::string author;
|
||||
std::string title;
|
||||
|
||||
// ....
|
||||
};
|
||||
|
||||
bool operator==(book const& a, book const& b)
|
||||
{
|
||||
return a.id == b.id;
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Then all you would need to do is write the function `library::hash_value`:
|
||||
|
||||
[source]
|
||||
----
|
||||
namespace library
|
||||
{
|
||||
std::size_t hash_value(book const& b)
|
||||
{
|
||||
boost::hash<int> hasher;
|
||||
return hasher(b.id);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
And you can now use `boost::hash` with book:
|
||||
|
||||
[source]
|
||||
----
|
||||
library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
|
||||
library::book dandelion(1354, "Paul J. Shanley",
|
||||
"Hash & Dandelion Greens");
|
||||
|
||||
boost::hash<library::book> book_hasher;
|
||||
std::size_t knife_hash_value = book_hasher(knife);
|
||||
|
||||
// If std::unordered_set is available:
|
||||
std::unordered_set<library::book, boost::hash<library::book> > books;
|
||||
books.insert(knife);
|
||||
books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
|
||||
books.insert(library::book(1953, "Snyder, Bernadette M.",
|
||||
"Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
|
||||
|
||||
assert(books.find(knife) != books.end());
|
||||
assert(books.find(dandelion) == books.end());
|
||||
----
|
||||
|
||||
The full example can be found in
|
||||
link:../../examples/books.hpp[examples/books.hpp] and
|
||||
link:../../examples/books.cpp[examples/books.cpp].
|
||||
|
||||
TIP: When writing a hash function, first look at how the equality function
|
||||
works. Objects that are equal must generate the same hash value. When objects
|
||||
are not equal they should generate different hash values. In this object
|
||||
equality was based just on `id` so the hash function only hashes `id`. If it
|
||||
was based on the object's name and author then the hash function should take
|
||||
them into account (how to do this is discussed in the next section).
|
||||
@@ -1,48 +0,0 @@
|
||||
|
||||
[/ Copyright 2005-2008 Daniel James.
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[section:intro Introduction]
|
||||
|
||||
[def __tr1-full__
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
|
||||
Draft Technical Report on C++ Library Extensions]]
|
||||
[def __tr1__
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
|
||||
TR1]]
|
||||
[def __unordered__ [link unordered Boost.Unordered]]
|
||||
[def __intrusive__ [link intrusive.unordered_set_unordered_multiset Boost.Intrusive]]
|
||||
[def __multi-index__ [@boost:/libs/multi_index/doc/index.html
|
||||
Boost Multi-Index Containers Library]]
|
||||
[def __multi-index-short__ [@boost:/libs/multi_index/doc/index.html
|
||||
Boost.MultiIndex]]
|
||||
[def __bimap__ [@boost:/libs/bimap/index.html Boost.Bimap]]
|
||||
[def __issues__
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf
|
||||
Library Extension Technical Report Issues List]]
|
||||
[def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function hash function]]
|
||||
[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]]
|
||||
|
||||
[classref boost::hash] is an implementation of the __hash-function__ object
|
||||
specified by the __tr1-full__ (TR1). It is the default hash function for
|
||||
__unordered__, __intrusive__'s unordered associative containers, and
|
||||
__multi-index-short__'s hash indicies and __bimap__'s `unordered_set_of`.
|
||||
|
||||
As it is compliant with __tr1__, it will work with:
|
||||
|
||||
* integers
|
||||
* floats
|
||||
* pointers
|
||||
* strings
|
||||
|
||||
It also implements the extension proposed by Peter Dimov in issue 6.18 of the
|
||||
__issues__ (page 63), this adds support for:
|
||||
|
||||
* arrays
|
||||
* `std::pair`
|
||||
* the standard containers.
|
||||
* extending [classref boost::hash] for custom types.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
[/ Copyright 2005-2008 Daniel James.
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[section:links Links]
|
||||
|
||||
[*A Proposal to Add Hash Tables to the Standard Library]
|
||||
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1456.html]
|
||||
The hash table proposal explains much of the design. The hash function object
|
||||
is discussed in Section D.
|
||||
|
||||
[*The C++ Standard Library Technical Report.]
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf]
|
||||
Contains the hash function specification in section 6.3.2.
|
||||
|
||||
[*Library Extension Technical Report Issues List.]
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf]
|
||||
The library implements the extension described in Issue 6.18, pages 63-67.
|
||||
|
||||
[*Methods for Identifying Versioned and Plagiarised Documents]
|
||||
Timothy C. Hoad, Justin Zobel
|
||||
[@http://www.cs.rmit.edu.au/~jz/fulltext/jasist-tch.pdf]
|
||||
Contains the hash function that [funcref boost::hash_combine] is based on.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
|
||||
[/ Copyright 2005-2008 Daniel James.
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[section:portability Portability]
|
||||
|
||||
[def __boost_hash__ [classref boost::hash]]
|
||||
|
||||
__boost_hash__ is written to be as portable as possible, but unfortunately, several
|
||||
older compilers don't support argument dependent lookup (ADL) - the mechanism
|
||||
used for customisation. On those compilers custom overloads for `hash_value`
|
||||
needs to be declared in the boost namespace.
|
||||
|
||||
On a strictly standards compliant compiler, an overload defined in the
|
||||
boost namespace won't be found when __boost_hash__ is instantiated,
|
||||
so for these compilers the overload should only be declared in the same
|
||||
namespace as the class.
|
||||
|
||||
Let's say we have a simple custom type:
|
||||
|
||||
namespace foo
|
||||
{
|
||||
template <class T>
|
||||
class custom_type
|
||||
{
|
||||
T value;
|
||||
public:
|
||||
custom_type(T x) : value(x) {}
|
||||
|
||||
friend std::size_t hash_value(custom_type x)
|
||||
{
|
||||
__boost_hash__<int> hasher;
|
||||
return hasher(x.value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
On a compliant compiler, when `hash_value` is called for this type,
|
||||
it will look at the namespace inside the type and find `hash_value`
|
||||
but on a compiler which doesn't support ADL `hash_value` won't be found.
|
||||
To make things worse, some compilers which do support ADL won't find
|
||||
a friend class defined inside the class.
|
||||
|
||||
So first move the member function out of the class:
|
||||
|
||||
namespace foo
|
||||
{
|
||||
template <class T>
|
||||
class custom_type
|
||||
{
|
||||
T value;
|
||||
public:
|
||||
custom_type(T x) : value(x) {}
|
||||
|
||||
std::size_t hash(custom_type x)
|
||||
{
|
||||
__boost_hash__<T> hasher;
|
||||
return hasher(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline std::size_t hash_value(custom_type<T> x)
|
||||
{
|
||||
return x.hash();
|
||||
}
|
||||
}
|
||||
|
||||
Unfortunately, I couldn't declare hash_value as a friend, as some compilers
|
||||
don't support template friends, so instead I declared a member function to
|
||||
calculate the hash, and called it from hash_value.
|
||||
|
||||
For compilers which don't support ADL, hash_value needs to be defined in the
|
||||
boost namespace:
|
||||
|
||||
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
|
||||
namespace boost
|
||||
#else
|
||||
namespace foo
|
||||
#endif
|
||||
{
|
||||
template <class T>
|
||||
std::size_t hash_value(foo::custom_type<T> x)
|
||||
{
|
||||
return x.hash();
|
||||
}
|
||||
}
|
||||
|
||||
Full code for this example is at
|
||||
[@boost:/libs/functional/hash/examples/portable.cpp /libs/functional/hash/examples/portable.cpp].
|
||||
|
||||
[h2 Other Issues]
|
||||
|
||||
On Visual C++ versions 6.5 and 7.0, `hash_value` isn't overloaded for built in
|
||||
arrays. __boost_hash__, [funcref boost::hash_combine] and [funcref boost::hash_range] all use a workaround to
|
||||
support built in arrays so this shouldn't be a problem in most cases.
|
||||
|
||||
On Visual C++ versions 6.5 and 7.0, function pointers aren't currently supported.
|
||||
|
||||
When using GCC on Solaris, `boost::hash_value(long double)` treats
|
||||
`long double`s as `double`s - so the hash function doesn't take into account the
|
||||
full range of values.
|
||||
|
||||
[endsect]
|
||||
844
doc/ref.xml
844
doc/ref.xml
@@ -1,844 +0,0 @@
|
||||
|
||||
<!--
|
||||
Copyright Daniel James 2005-2009
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
|
||||
<library-reference>
|
||||
<section id="hash.reference.specification">
|
||||
<para>For the full specification, see section 6.3 of the
|
||||
<ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf">C++ Standard Library Technical Report</ulink>
|
||||
and issue 6.18 of the
|
||||
<ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1837.pdf">Library Extension Technical Report Issues List</ulink> (page 63).
|
||||
</para>
|
||||
</section>
|
||||
<header name="boost/functional/hash.hpp">
|
||||
<para>
|
||||
Defines <code><classname>boost::hash</classname></code>,
|
||||
and helper functions.
|
||||
</para>
|
||||
|
||||
<namespace name="boost">
|
||||
|
||||
<!--
|
||||
boost::hash
|
||||
-->
|
||||
|
||||
<struct name="hash">
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
</template>
|
||||
|
||||
<inherit access="public">
|
||||
<classname>std::unary_function<T, std::size_t></classname>
|
||||
</inherit>
|
||||
|
||||
<purpose><simpara>A <ulink url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf">TR1</ulink> compliant hash function object.</simpara></purpose>
|
||||
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>T const&</paramtype>
|
||||
</parameter>
|
||||
<returns><para>
|
||||
<programlisting><functionname>hash_value</functionname>(val)</programlisting>
|
||||
</para></returns>
|
||||
<notes>
|
||||
<para>
|
||||
The call to <code><functionname>hash_value</functionname></code>
|
||||
is unqualified, so that custom overloads can be
|
||||
found via argument dependent lookup.
|
||||
</para>
|
||||
<para>
|
||||
This is not defined when the macro <code>BOOST_HASH_NO_EXTENSIONS</code>
|
||||
is defined. The specializations are still defined, so only the specializations
|
||||
required by TR1 are defined.
|
||||
</para>
|
||||
</notes>
|
||||
<throws><para>
|
||||
Only throws if
|
||||
<code><functionname>hash_value</functionname>(T)</code> throws.
|
||||
</para></throws>
|
||||
</method>
|
||||
</struct>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>bool</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>bool</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>char</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>char</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>signed char</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>signed char</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>unsigned char</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>unsigned char</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>wchar_t</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>wchar_t</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>short</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>short</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>unsigned short</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>unsigned short</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>int</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>int</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>unsigned int</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>unsigned int</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>long</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>long</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>unsigned long</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>unsigned long</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>long long</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>long long</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>unsigned long long</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>unsigned long long</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>float</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>float</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>double</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>double</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>long double</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>long double</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>std::string</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>std::string const&</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>std::wstring</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>std::wstring const&</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
<para><functionname>hash_value</functionname>(val) in Boost.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
</template>
|
||||
<specialization>
|
||||
<template-arg>T*</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>T*</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para>Unspecified in TR1, except that equal arguments yield the same result.</para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
</struct-specialization>
|
||||
|
||||
<struct-specialization name="hash">
|
||||
<template></template>
|
||||
<specialization>
|
||||
<template-arg>std::type_index</template-arg>
|
||||
</specialization>
|
||||
<method name="operator()" cv="const">
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>std::type_index</paramtype>
|
||||
</parameter>
|
||||
<returns>
|
||||
<para><code>val.hash_code()</code></para>
|
||||
</returns>
|
||||
<throws><para>Doesn't throw</para></throws>
|
||||
</method>
|
||||
<notes>
|
||||
<para>
|
||||
Only available if it's in your standard library and Boost.Config
|
||||
is aware of it.
|
||||
</para>
|
||||
</notes>
|
||||
</struct-specialization>
|
||||
|
||||
<free-function-group name="Support functions (Boost extension).">
|
||||
|
||||
<!--
|
||||
boost::hash_combine
|
||||
-->
|
||||
|
||||
<function name="hash_combine">
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
</template>
|
||||
<type>void</type>
|
||||
<parameter name="seed"><paramtype>size_t &</paramtype></parameter>
|
||||
<parameter name="v"><paramtype>T const&</paramtype></parameter>
|
||||
<purpose><simpara>
|
||||
Called repeatedly to incrementally create a hash value from
|
||||
several variables.
|
||||
</simpara></purpose>
|
||||
<effects><programlisting>seed ^= <functionname>hash_value</functionname>(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);</programlisting></effects>
|
||||
<notes>
|
||||
<para><functionname>hash_value</functionname> is called without
|
||||
qualification, so that overloads can be found via ADL.</para>
|
||||
<para>This is an extension to TR1</para>
|
||||
</notes>
|
||||
<throws>
|
||||
Only throws if <functionname>hash_value</functionname>(T) throws.
|
||||
Strong exception safety, as long as <functionname>hash_value</functionname>(T)
|
||||
also has strong exception safety.
|
||||
</throws>
|
||||
</function>
|
||||
|
||||
<!--
|
||||
boost::hash_range
|
||||
-->
|
||||
|
||||
<overloaded-function name="hash_range">
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="It"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="first"><paramtype>It</paramtype></parameter>
|
||||
<parameter name="last"><paramtype>It</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="It"/>
|
||||
</template>
|
||||
<type>void</type>
|
||||
<parameter name="seed"><paramtype>std::size_t&</paramtype></parameter>
|
||||
<parameter name="first"><paramtype>It</paramtype></parameter>
|
||||
<parameter name="last"><paramtype>It</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<purpose><simpara>
|
||||
Calculate the combined hash value of the elements of an iterator
|
||||
range.
|
||||
</simpara></purpose>
|
||||
<effects>
|
||||
<para>For the two argument overload:
|
||||
<programlisting>
|
||||
size_t seed = 0;
|
||||
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
<functionname>hash_combine</functionname>(seed, *first);
|
||||
}
|
||||
|
||||
return seed;
|
||||
</programlisting>
|
||||
</para>For the three arguments overload:
|
||||
<programlisting>
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
<functionname>hash_combine</functionname>(seed, *first);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
</para>
|
||||
</effects>
|
||||
<notes>
|
||||
<para>
|
||||
<code>hash_range</code> is sensitive to the order of the elements
|
||||
so it wouldn't be appropriate to use this with an unordered
|
||||
container.
|
||||
</para>
|
||||
<para>This is an extension to TR1</para>
|
||||
</notes>
|
||||
<throws><para>
|
||||
Only throws if <code><functionname>hash_value</functionname>(std::iterator_traits<It>::value_type)</code>
|
||||
throws. <code>hash_range(std::size_t&, It, It)</code> has basic exception safety as long as
|
||||
<code><functionname>hash_value</functionname>(std::iterator_traits<It>::value_type)</code>
|
||||
has basic exception safety.
|
||||
</para></throws>
|
||||
</overloaded-function>
|
||||
|
||||
</free-function-group>
|
||||
|
||||
<free-function-group name="Overloadable hash implementation (Boost extension).">
|
||||
|
||||
<!--
|
||||
boost::hash_value - integers
|
||||
-->
|
||||
|
||||
<overloaded-function name="hash_value">
|
||||
<purpose><simpara>
|
||||
Implementation of the hash function.
|
||||
</simpara></purpose>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>bool</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>char</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>signed char</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>unsigned char</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>wchar_t</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>short</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>unsigned short</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>int</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>unsigned int</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>long</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>unsigned long</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>long long</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>unsigned long long</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>float</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>double</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>long double</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template><template-type-parameter name="T"/></template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>T* const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-nontype-parameter name="N"><type>unsigned</type></template-nontype-parameter>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter><paramtype>T (&val)[N]</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-nontype-parameter name="N"><type>unsigned</type></template-nontype-parameter>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter><paramtype>const T (&val)[N]</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="Ch"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val">
|
||||
<paramtype>std::basic_string<Ch, std::char_traits<Ch>, A> const&</paramtype>
|
||||
</parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="A"/>
|
||||
<template-type-parameter name="B"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::pair<A, B> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::vector<T, A> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::list<T, A> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::deque<T, A> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="K"/>
|
||||
<template-type-parameter name="C"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::set<K, C, A> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="K"/>
|
||||
<template-type-parameter name="C"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::multiset<K, C, A> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="K"/>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-type-parameter name="C"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::map<K, T, C, A> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="K"/>
|
||||
<template-type-parameter name="T"/>
|
||||
<template-type-parameter name="C"/>
|
||||
<template-type-parameter name="A"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::multimap<K, T, C, A> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<template>
|
||||
<template-type-parameter name="T"/>
|
||||
</template>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::complex<T> const&</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<signature>
|
||||
<type>std::size_t</type>
|
||||
<parameter name="val"><paramtype>std::type_index</paramtype></parameter>
|
||||
</signature>
|
||||
|
||||
<description><para>
|
||||
Generally shouldn't be called directly by users, instead they should use
|
||||
<classname>boost::hash</classname>, <functionname>boost::hash_range</functionname>
|
||||
or <functionname>boost::hash_combine</functionname> which
|
||||
call <code>hash_value</code> without namespace qualification so that overloads
|
||||
for custom types are found via ADL.
|
||||
</para></description>
|
||||
|
||||
<notes>
|
||||
<para>This is an extension to TR1</para>
|
||||
</notes>
|
||||
|
||||
<throws>
|
||||
Only throws if a user supplied version of
|
||||
<code><functionname>hash_value</functionname></code>
|
||||
throws for an element of a container, or
|
||||
one of the types stored in a pair.
|
||||
</throws>
|
||||
|
||||
<returns>
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Types</entry>
|
||||
<entry>Returns</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><code>bool</code>,
|
||||
<code>char</code>, <code>signed char</code>, <code>unsigned char</code>, <code>wchar_t</code>,
|
||||
<code>short</code>, <code>unsigned short</code>,
|
||||
<code>int</code>, <code>unsigned int</code>, <code>long</code>, <code>unsigned long</code>
|
||||
</entry>
|
||||
<entry><code>val</code></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><code>long long</code>, <code>unsigned long long</code></entry>
|
||||
<entry><code>val</code> when <code>abs(val) <= std::numeric_limits<std::size_t>::max()</code>.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><code>float</code>, <code>double</code>, <code>long double</code></entry>
|
||||
<entry>An unspecified value, except that equal arguments shall yield the same result.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><code>T*</code></entry>
|
||||
<entry>An unspecified value, except that equal arguments shall yield the same result.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>T val[N]</code>,
|
||||
<code>const T val[N]</code>
|
||||
</entry>
|
||||
<entry><code>hash_range(val, val+N)</code></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>std:basic_string<Ch, std::char_traits<Ch>, A></code>,
|
||||
<code>std::vector<T, A></code>,
|
||||
<code>std::list<T, A></code>,
|
||||
<code>std::deque<T, A></code>,
|
||||
<code>std::set<K, C, A></code>,
|
||||
<code>std::multiset<K, C, A></code>,
|
||||
<code>std::map<K, T, C, A></code>,
|
||||
<code>std::multimap<K, T, C, A></code>
|
||||
</entry>
|
||||
<entry><code>hash_range(val.begin(), val.end())</code></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><code>std::pair<A, B></code></entry>
|
||||
<entry><programlisting>size_t seed = 0;
|
||||
<functionname>hash_combine</functionname>(seed, val.first);
|
||||
<functionname>hash_combine</functionname>(seed, val.second);
|
||||
return seed;</programlisting></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>std::complex<T></code>
|
||||
</entry>
|
||||
<entry>When <code>T</code> is a built in type and <code>val.imag() == 0</code>, the result is equal to <code>hash_value(val.real())</code>. Otherwise an unspecified value, except that equal arguments shall yield the same result.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>std::type_index</code>
|
||||
</entry>
|
||||
<entry><code>val.hash_code()</code></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</returns>
|
||||
</overloaded-function>
|
||||
</free-function-group>
|
||||
</namespace>
|
||||
</header>
|
||||
</library-reference>
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
[/ Copyright 2005-2008 Daniel James.
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[section:acknowledgements Acknowledgements]
|
||||
|
||||
This library is based on the design by Peter Dimov. During the initial
|
||||
development
|
||||
Joaquín M López Muñoz made many useful suggestions and contributed fixes.
|
||||
|
||||
The formal review was managed by Thorsten Ottosen, and the library reviewed by:
|
||||
David Abrahams, Alberto Barbati, Topher Cooper, Caleb Epstein, Dave Harris,
|
||||
Chris Jefferson, Bronek Kozicki, John Maddock, Tobias Swinger, Jaap Suter,
|
||||
Rob Stewart and Pavel Vozenilek. Since then, further constructive criticism has
|
||||
been made by Daniel Krügler, Alexander Nasonov and 沈慧峰.
|
||||
|
||||
The implementation of the hash function for pointers is based on suggestions
|
||||
made by Alberto Barbati and Dave Harris. Dave Harris also suggested an
|
||||
important improvement to [funcref boost::hash_combine] that was taken up.
|
||||
|
||||
Some useful improvements to the floating point hash algorithm were suggested
|
||||
by Daniel Krügler.
|
||||
|
||||
The original implementation came from Jeremy B. Maitin-Shepard's hash table
|
||||
library, although this is a complete rewrite.
|
||||
|
||||
[endsect]
|
||||
202
doc/tutorial.qbk
202
doc/tutorial.qbk
@@ -1,202 +0,0 @@
|
||||
|
||||
[/ Copyright 2005-2008 Daniel James.
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[def __multi-index-short__ [@boost:/libs/multi_index/doc/index.html
|
||||
Boost.MultiIndex]]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
When using a hash index with __multi-index-short__, you don't need to do
|
||||
anything to use [classref boost::hash] as it uses it by default.
|
||||
To find out how to use a user-defined type, read the
|
||||
[link hash.custom section on extending boost::hash for a custom data type].
|
||||
|
||||
If your standard library supplies its own implementation of the unordered
|
||||
associative containers and you wish to use
|
||||
[classref boost::hash], just use an extra template parameter:
|
||||
|
||||
std::unordered_multiset<int, ``[classref boost::hash]``<int> >
|
||||
set_of_ints;
|
||||
|
||||
std::unordered_set<std::pair<int, int>, ``[classref boost::hash]``<std::pair<int, int> >
|
||||
set_of_pairs;
|
||||
|
||||
std::unordered_map<int, std::string, ``[classref boost::hash]``<int> > map_int_to_string;
|
||||
|
||||
To use [classref boost::hash] directly, create an instance and call it as a function:
|
||||
|
||||
#include <``[headerref boost/functional/hash.hpp]``>
|
||||
|
||||
int main()
|
||||
{
|
||||
``[classref boost::hash]``<std::string> string_hash;
|
||||
|
||||
std::size_t h = string_hash("Hash me");
|
||||
}
|
||||
|
||||
For an example of generic use, here is a function to generate a vector
|
||||
containing the hashes of the elements of a container:
|
||||
|
||||
template <class Container>
|
||||
std::vector<std::size_t> get_hashes(Container const& x)
|
||||
{
|
||||
std::vector<std::size_t> hashes;
|
||||
std::transform(x.begin(), x.end(), std::insert_iterator(hashes),
|
||||
``[classref boost::hash]``<typename Container::value_type>());
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:custom Extending boost::hash for a custom data type]
|
||||
|
||||
[classref boost::hash] is implemented by calling the function
|
||||
[funcref boost::hash_value hash_value].
|
||||
The namespace isn't specified so that it can detect overloads via argument
|
||||
dependant lookup. So if there is a free function `hash_value` in the same
|
||||
namespace as a custom type, it will get called.
|
||||
|
||||
If you have a structure `library::book`, where each `book` is uniquely
|
||||
defined by it's member `id`:
|
||||
|
||||
namespace library
|
||||
{
|
||||
struct book
|
||||
{
|
||||
int id;
|
||||
std::string author;
|
||||
std::string title;
|
||||
|
||||
// ....
|
||||
};
|
||||
|
||||
bool operator==(book const& a, book const& b)
|
||||
{
|
||||
return a.id == b.id;
|
||||
}
|
||||
}
|
||||
|
||||
Then all you would need to do is write the function `library::hash_value`:
|
||||
|
||||
namespace library
|
||||
{
|
||||
std::size_t hash_value(book const& b)
|
||||
{
|
||||
``[classref boost::hash]``<int> hasher;
|
||||
return hasher(b.id);
|
||||
}
|
||||
}
|
||||
|
||||
And you can now use [classref boost::hash] with book:
|
||||
|
||||
library::book knife(3458, "Zane Grey", "The Hash Knife Outfit");
|
||||
library::book dandelion(1354, "Paul J. Shanley",
|
||||
"Hash & Dandelion Greens");
|
||||
|
||||
``[classref boost::hash]``<library::book> book_hasher;
|
||||
std::size_t knife_hash_value = book_hasher(knife);
|
||||
|
||||
// If std::unordered_set is available:
|
||||
std::unordered_set<library::book, ``[classref boost::hash]``<library::book> > books;
|
||||
books.insert(knife);
|
||||
books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
|
||||
books.insert(library::book(1953, "Snyder, Bernadette M.",
|
||||
"Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
|
||||
|
||||
assert(books.find(knife) != books.end());
|
||||
assert(books.find(dandelion) == books.end());
|
||||
|
||||
The full example can be found in:
|
||||
[@boost:/libs/functional/hash/examples/books.hpp /libs/functional/hash/examples/books.hpp]
|
||||
and
|
||||
[@boost:/libs/functional/hash/examples/books.cpp /libs/functional/hash/examples/books.cpp].
|
||||
|
||||
[tip
|
||||
When writing a hash function, first look at how the equality function works.
|
||||
Objects that are equal must generate the same hash value.
|
||||
When objects are not equal they should generate different hash values.
|
||||
In this object equality was based just on the id so the hash function
|
||||
only hashes the id. If it was based on the object's name and author
|
||||
then the hash function should take them into account
|
||||
(how to do this is discussed in the next section).
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:combine Combining hash values]
|
||||
|
||||
Say you have a point class, representing a two dimensional location:
|
||||
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
public:
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
|
||||
bool operator==(point const& other) const
|
||||
{
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
};
|
||||
|
||||
and you wish to use it as the key for an `unordered_map`. You need to
|
||||
customise the hash for this structure. To do this we need to combine
|
||||
the hash values for `x` and `y`. The function
|
||||
[funcref boost::hash_combine] is supplied for this purpose:
|
||||
|
||||
class point
|
||||
{
|
||||
...
|
||||
|
||||
friend std::size_t hash_value(point const& p)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
``[funcref boost::hash_combine]``(seed, p.x);
|
||||
``[funcref boost::hash_combine]``(seed, p.y);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
...
|
||||
};
|
||||
|
||||
Calls to hash_combine incrementally build the hash from the different members
|
||||
of point, it can be repeatedly called for any number of elements. It calls
|
||||
[funcref boost::hash_value hash_value] on the supplied element, and combines it with the seed.
|
||||
|
||||
Full code for this example is at
|
||||
[@boost:/libs/functional/hash/examples/point.cpp /libs/functional/hash/examples/point.cpp].
|
||||
|
||||
[note
|
||||
When using [funcref boost::hash_combine] the order of the
|
||||
calls matters.
|
||||
'''
|
||||
<programlisting>
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, 1);
|
||||
boost::hash_combine(seed, 2);
|
||||
</programlisting>
|
||||
results in a different seed to:
|
||||
<programlisting>
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, 2);
|
||||
boost::hash_combine(seed, 1);
|
||||
</programlisting>
|
||||
'''
|
||||
If you are calculating a hash value for data where the order of the data
|
||||
doesn't matter in comparisons (e.g. a set) you will have to ensure that the
|
||||
data is always supplied in the same order.
|
||||
]
|
||||
|
||||
To calculate the hash of an iterator range you can use [funcref boost::hash_range]:
|
||||
|
||||
std::vector<std::string> some_strings;
|
||||
std::size_t hash = ``[funcref boost::hash_range]``(some_strings.begin(), some_strings.end());
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import testing ;
|
||||
|
||||
project : requirements <library>/boost/container_hash//boost_container_hash ;
|
||||
|
||||
run books.cpp ;
|
||||
run point.cpp ;
|
||||
run portable.cpp ;
|
||||
run template.cpp /boost/unordered//boost_unordered : : : <toolset>msvc-8.0:<build>no ;
|
||||
run point2.cpp ;
|
||||
|
||||
@@ -3,12 +3,20 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Force use of assert.
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include "./books.hpp"
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <cassert>
|
||||
|
||||
// If std::unordered_set was available:
|
||||
//#include <unordered_set>
|
||||
// If std::unordered_set is available:
|
||||
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
// This example illustrates how to use boost::hash with a custom hash function.
|
||||
// For full details, see the tutorial.
|
||||
@@ -22,18 +30,19 @@ int main()
|
||||
std::size_t knife_hash_value = book_hasher(knife);
|
||||
(void)knife_hash_value; // suppress unused variable warning
|
||||
|
||||
// If std::unordered_set was available:
|
||||
//
|
||||
//std::unordered_set<library::book, boost::hash<library::book> > books;
|
||||
//books.insert(knife);
|
||||
//books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
|
||||
//books.insert(library::book(1953, "Snyder, Bernadette M.",
|
||||
// "Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
|
||||
// If std::unordered_set is available:
|
||||
#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET)
|
||||
|
||||
//assert(books.find(knife) != books.end());
|
||||
//assert(books.find(dandelion) == books.end());
|
||||
std::unordered_set<library::book, boost::hash<library::book> > books;
|
||||
books.insert(knife);
|
||||
books.insert(library::book(2443, "Lindgren, Torgny", "Hash"));
|
||||
books.insert(library::book(1953, "Snyder, Bernadette M.",
|
||||
"Heavenly Hash: A Tasty Mix of a Mother's Meditations"));
|
||||
|
||||
return 0;
|
||||
assert(books.find(knife) != books.end());
|
||||
assert(books.find(dandelion) == books.end());
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace library
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
// Force use of assert.
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <cassert>
|
||||
|
||||
// This example illustrates how to use boost::hash_combine to generate a hash
|
||||
@@ -14,7 +19,9 @@ class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
|
||||
@@ -26,6 +33,7 @@ public:
|
||||
friend std::size_t hash_value(point const& p)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine(seed, p.x);
|
||||
boost::hash_combine(seed, p.y);
|
||||
|
||||
|
||||
65
examples/point2.cpp
Normal file
65
examples/point2.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
// Copyright 2005 Daniel James.
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// Force use of assert.
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/describe/operators.hpp>
|
||||
#include <cassert>
|
||||
|
||||
// This example illustrates how to use Boost.Describe to obtain
|
||||
// automatic boost::hash support. For full details see the hash
|
||||
// tutorial.
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
class point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
|
||||
BOOST_DESCRIBE_CLASS(point, (), (), (), (x, y))
|
||||
|
||||
public:
|
||||
|
||||
point() : x(0), y(0) {}
|
||||
point(int x, int y) : x(x), y(y) {}
|
||||
};
|
||||
|
||||
using boost::describe::operators::operator==;
|
||||
using boost::describe::operators::operator!=;
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::hash<point> point_hasher;
|
||||
|
||||
point p1(0, 0);
|
||||
point p2(1, 2);
|
||||
point p3(4, 1);
|
||||
point p4 = p1;
|
||||
|
||||
assert(point_hasher(p1) == point_hasher(p4));
|
||||
|
||||
// These tests could legally fail, but if they did it'd be a pretty bad
|
||||
// hash function.
|
||||
assert(point_hasher(p1) != point_hasher(p2));
|
||||
assert(point_hasher(p1) != point_hasher(p3));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::puts( "This example requires C++14." );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,12 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
// Force use of assert.
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <cassert>
|
||||
|
||||
// This example illustrates how to customise boost::hash portably, so that
|
||||
|
||||
23
examples/template.cpp
Normal file
23
examples/template.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
// Copyright 2012 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Force use of assert.
|
||||
#if defined(NDEBUG)
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include "template.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <cassert>
|
||||
|
||||
int main()
|
||||
{
|
||||
typedef my_pair<int, float> pair;
|
||||
boost::unordered_set<pair> pair_set;
|
||||
pair_set.emplace(10, 0.5f);
|
||||
|
||||
assert(pair_set.find(pair(10, 0.5f)) != pair_set.end());
|
||||
assert(pair_set.find(pair(10, 0.6f)) == pair_set.end());
|
||||
}
|
||||
38
examples/template.hpp
Normal file
38
examples/template.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
// Copyright 2012 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// This is an example of how to write a hash function for a template
|
||||
// class.
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
template <typename A, typename B>
|
||||
class my_pair
|
||||
{
|
||||
A value1;
|
||||
B value2;
|
||||
|
||||
public:
|
||||
|
||||
my_pair(A const& v1, B const& v2)
|
||||
: value1(v1), value2(v2)
|
||||
{}
|
||||
|
||||
bool operator==(my_pair const& other) const
|
||||
{
|
||||
return value1 == other.value1 &&
|
||||
value2 == other.value2;
|
||||
}
|
||||
|
||||
friend std::size_t hash_value(my_pair const& p)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine(seed, p.value1);
|
||||
boost::hash_combine(seed, p.value2);
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
146
include/boost/container_hash/detail/hash_integral.hpp
Normal file
146
include/boost/container_hash/detail/hash_integral.hpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2021-2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP
|
||||
|
||||
#include <boost/container_hash/detail/hash_mix.hpp>
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
// libstdc++ doesn't provide support for __int128 in the standard traits
|
||||
|
||||
template<class T> struct is_integral: public std::is_integral<T>
|
||||
{
|
||||
};
|
||||
|
||||
template<class T> struct is_unsigned: public std::is_unsigned<T>
|
||||
{
|
||||
};
|
||||
|
||||
template<class T> struct make_unsigned: public std::make_unsigned<T>
|
||||
{
|
||||
};
|
||||
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
|
||||
template<> struct is_integral<__int128_t>: public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct is_integral<__uint128_t>: public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct is_unsigned<__int128_t>: public std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct is_unsigned<__uint128_t>: public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct make_unsigned<__int128_t>
|
||||
{
|
||||
typedef __uint128_t type;
|
||||
};
|
||||
|
||||
template<> struct make_unsigned<__uint128_t>
|
||||
{
|
||||
typedef __uint128_t type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template<class T,
|
||||
bool bigger_than_size_t = (sizeof(T) > sizeof(std::size_t)),
|
||||
bool is_unsigned = is_unsigned<T>::value,
|
||||
std::size_t size_t_bits = sizeof(std::size_t) * CHAR_BIT,
|
||||
std::size_t type_bits = sizeof(T) * CHAR_BIT>
|
||||
struct hash_integral_impl;
|
||||
|
||||
template<class T, bool is_unsigned, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, false, is_unsigned, size_t_bits, type_bits>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
return static_cast<std::size_t>( v );
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, std::size_t size_t_bits, std::size_t type_bits> struct hash_integral_impl<T, true, false, size_t_bits, type_bits>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
typedef typename make_unsigned<T>::type U;
|
||||
|
||||
if( v >= 0 )
|
||||
{
|
||||
return hash_integral_impl<U>::fn( static_cast<U>( v ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ~hash_integral_impl<U>::fn( static_cast<U>( ~static_cast<U>( v ) ) );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct hash_integral_impl<T, true, true, 32, 64>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
|
||||
seed = static_cast<std::size_t>( v & 0xFFFFFFFF ) + hash_detail::hash_mix( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct hash_integral_impl<T, true, true, 32, 128>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
seed = static_cast<std::size_t>( v >> 96 ) + hash_detail::hash_mix( seed );
|
||||
seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
|
||||
seed = static_cast<std::size_t>( v >> 32 ) + hash_detail::hash_mix( seed );
|
||||
seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct hash_integral_impl<T, true, true, 64, 128>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
seed = static_cast<std::size_t>( v >> 64 ) + hash_detail::hash_mix( seed );
|
||||
seed = static_cast<std::size_t>( v ) + hash_detail::hash_mix( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<hash_detail::is_integral<T>::value, std::size_t>::type
|
||||
hash_value( T v )
|
||||
{
|
||||
return hash_detail::hash_integral_impl<T>::fn( v );
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_INTEGRAL_HPP
|
||||
113
include/boost/container_hash/detail/hash_mix.hpp
Normal file
113
include/boost/container_hash/detail/hash_mix.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2022 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_MIX_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<std::size_t Bits> struct hash_mix_impl;
|
||||
|
||||
// hash_mix for 64 bit size_t
|
||||
//
|
||||
// The general "xmxmx" form of state of the art 64 bit mixers originates
|
||||
// from Murmur3 by Austin Appleby, which uses the following function as
|
||||
// its "final mix":
|
||||
//
|
||||
// k ^= k >> 33;
|
||||
// k *= 0xff51afd7ed558ccd;
|
||||
// k ^= k >> 33;
|
||||
// k *= 0xc4ceb9fe1a85ec53;
|
||||
// k ^= k >> 33;
|
||||
//
|
||||
// (https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp)
|
||||
//
|
||||
// It has subsequently been improved multiple times by different authors
|
||||
// by changing the constants. The most well known improvement is the
|
||||
// so-called "variant 13" function by David Stafford:
|
||||
//
|
||||
// k ^= k >> 30;
|
||||
// k *= 0xbf58476d1ce4e5b9;
|
||||
// k ^= k >> 27;
|
||||
// k *= 0x94d049bb133111eb;
|
||||
// k ^= k >> 31;
|
||||
//
|
||||
// (https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
|
||||
//
|
||||
// This mixing function is used in the splitmix64 RNG:
|
||||
// http://xorshift.di.unimi.it/splitmix64.c
|
||||
//
|
||||
// We use Jon Maiga's implementation from
|
||||
// http://jonkagstrom.com/mx3/mx3_rev2.html
|
||||
//
|
||||
// x ^= x >> 32;
|
||||
// x *= 0xe9846af9b1a615d;
|
||||
// x ^= x >> 32;
|
||||
// x *= 0xe9846af9b1a615d;
|
||||
// x ^= x >> 28;
|
||||
//
|
||||
// An equally good alternative is Pelle Evensen's Moremur:
|
||||
//
|
||||
// x ^= x >> 27;
|
||||
// x *= 0x3C79AC492BA7B653;
|
||||
// x ^= x >> 33;
|
||||
// x *= 0x1C69B3F74AC4AE35;
|
||||
// x ^= x >> 27;
|
||||
//
|
||||
// (https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html)
|
||||
|
||||
template<> struct hash_mix_impl<64>
|
||||
{
|
||||
inline static std::uint64_t fn( std::uint64_t x )
|
||||
{
|
||||
std::uint64_t const m = 0xe9846af9b1a615d;
|
||||
|
||||
x ^= x >> 32;
|
||||
x *= m;
|
||||
x ^= x >> 32;
|
||||
x *= m;
|
||||
x ^= x >> 28;
|
||||
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
// hash_mix for 32 bit size_t
|
||||
//
|
||||
// We use the "best xmxmx" implementation from
|
||||
// https://github.com/skeeto/hash-prospector/issues/19
|
||||
|
||||
template<> struct hash_mix_impl<32>
|
||||
{
|
||||
inline static std::uint32_t fn( std::uint32_t x )
|
||||
{
|
||||
std::uint32_t const m1 = 0x21f0aaad;
|
||||
std::uint32_t const m2 = 0x735a2d97;
|
||||
|
||||
x ^= x >> 16;
|
||||
x *= m1;
|
||||
x ^= x >> 15;
|
||||
x *= m2;
|
||||
x ^= x >> 15;
|
||||
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::size_t hash_mix( std::size_t v )
|
||||
{
|
||||
return hash_mix_impl<sizeof(std::size_t) * CHAR_BIT>::fn( v );
|
||||
}
|
||||
|
||||
} // namespace hash_detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
|
||||
408
include/boost/container_hash/detail/hash_range.hpp
Normal file
408
include/boost/container_hash/detail/hash_range.hpp
Normal file
@@ -0,0 +1,408 @@
|
||||
// Copyright 2022 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_RANGE_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
#include <boost/container_hash/detail/mulx.hpp>
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<class T> struct is_char_type: public std::false_type {};
|
||||
|
||||
#if CHAR_BIT == 8
|
||||
|
||||
template<> struct is_char_type<char>: public std::true_type {};
|
||||
template<> struct is_char_type<signed char>: public std::true_type {};
|
||||
template<> struct is_char_type<unsigned char>: public std::true_type {};
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
template<> struct is_char_type<char8_t>: public std::true_type {};
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||
template<> struct is_char_type<std::byte>: public std::true_type {};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// generic version
|
||||
|
||||
template<class It>
|
||||
inline typename std::enable_if<
|
||||
!is_char_type<typename std::iterator_traits<It>::value_type>::value,
|
||||
std::size_t >::type
|
||||
hash_range( std::size_t seed, It first, It last )
|
||||
{
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
hash_combine<typename std::iterator_traits<It>::value_type>( seed, *first );
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
// specialized char[] version, 32 bit
|
||||
|
||||
template<class It> inline std::uint32_t read32le( It p )
|
||||
{
|
||||
// clang 5+, gcc 5+ figure out this pattern and use a single mov on x86
|
||||
// gcc on s390x and power BE even knows how to use load-reverse
|
||||
|
||||
std::uint32_t w =
|
||||
static_cast<std::uint32_t>( static_cast<unsigned char>( p[0] ) ) |
|
||||
static_cast<std::uint32_t>( static_cast<unsigned char>( p[1] ) ) << 8 |
|
||||
static_cast<std::uint32_t>( static_cast<unsigned char>( p[2] ) ) << 16 |
|
||||
static_cast<std::uint32_t>( static_cast<unsigned char>( p[3] ) ) << 24;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
template<class T> inline std::uint32_t read32le( T* p )
|
||||
{
|
||||
std::uint32_t w;
|
||||
|
||||
std::memcpy( &w, p, 4 );
|
||||
return w;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline std::uint64_t mul32( std::uint32_t x, std::uint32_t y )
|
||||
{
|
||||
return static_cast<std::uint64_t>( x ) * y;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
inline typename std::enable_if<
|
||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
||||
std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
|
||||
std::numeric_limits<std::size_t>::digits <= 32,
|
||||
std::size_t>::type
|
||||
hash_range( std::size_t seed, It first, It last )
|
||||
{
|
||||
It p = first;
|
||||
std::size_t n = static_cast<std::size_t>( last - first );
|
||||
|
||||
std::uint32_t const q = 0x9e3779b9U;
|
||||
std::uint32_t const k = 0xe35e67b1U; // q * q
|
||||
|
||||
std::uint64_t h = mul32( static_cast<std::uint32_t>( seed ) + q, k );
|
||||
std::uint32_t w = static_cast<std::uint32_t>( h & 0xFFFFFFFF );
|
||||
|
||||
h ^= n;
|
||||
|
||||
while( n >= 4 )
|
||||
{
|
||||
std::uint32_t v1 = read32le( p );
|
||||
|
||||
w += q;
|
||||
h ^= mul32( v1 + w, k );
|
||||
|
||||
p += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
{
|
||||
std::uint32_t v1 = 0;
|
||||
|
||||
if( n >= 1 )
|
||||
{
|
||||
std::size_t const x1 = ( n - 1 ) & 2; // 1: 0, 2: 0, 3: 2
|
||||
std::size_t const x2 = n >> 1; // 1: 0, 2: 1, 3: 1
|
||||
|
||||
v1 =
|
||||
static_cast<std::uint32_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x1 ) ] ) ) << x1 * 8 |
|
||||
static_cast<std::uint32_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x2 ) ] ) ) << x2 * 8 |
|
||||
static_cast<std::uint32_t>( static_cast<unsigned char>( p[ 0 ] ) );
|
||||
}
|
||||
|
||||
w += q;
|
||||
h ^= mul32( v1 + w, k );
|
||||
}
|
||||
|
||||
w += q;
|
||||
h ^= mul32( static_cast<std::uint32_t>( h & 0xFFFFFFFF ) + w, static_cast<std::uint32_t>( h >> 32 ) + w + k );
|
||||
|
||||
return static_cast<std::uint32_t>( h & 0xFFFFFFFF ) ^ static_cast<std::uint32_t>( h >> 32 );
|
||||
}
|
||||
|
||||
template<class It>
|
||||
inline typename std::enable_if<
|
||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
||||
!std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
|
||||
std::numeric_limits<std::size_t>::digits <= 32,
|
||||
std::size_t>::type
|
||||
hash_range( std::size_t seed, It first, It last )
|
||||
{
|
||||
std::size_t n = 0;
|
||||
|
||||
std::uint32_t const q = 0x9e3779b9U;
|
||||
std::uint32_t const k = 0xe35e67b1U; // q * q
|
||||
|
||||
std::uint64_t h = mul32( static_cast<std::uint32_t>( seed ) + q, k );
|
||||
std::uint32_t w = static_cast<std::uint32_t>( h & 0xFFFFFFFF );
|
||||
|
||||
std::uint32_t v1 = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
v1 = 0;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) );
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 8;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 16;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint32_t>( static_cast<unsigned char>( *first ) ) << 24;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
w += q;
|
||||
h ^= mul32( v1 + w, k );
|
||||
}
|
||||
|
||||
h ^= n;
|
||||
|
||||
w += q;
|
||||
h ^= mul32( v1 + w, k );
|
||||
|
||||
w += q;
|
||||
h ^= mul32( static_cast<std::uint32_t>( h & 0xFFFFFFFF ) + w, static_cast<std::uint32_t>( h >> 32 ) + w + k );
|
||||
|
||||
return static_cast<std::uint32_t>( h & 0xFFFFFFFF ) ^ static_cast<std::uint32_t>( h >> 32 );
|
||||
}
|
||||
|
||||
// specialized char[] version, 64 bit
|
||||
|
||||
template<class It> inline std::uint64_t read64le( It p )
|
||||
{
|
||||
std::uint64_t w =
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[0] ) ) |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[1] ) ) << 8 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[2] ) ) << 16 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[3] ) ) << 24 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[4] ) ) << 32 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[5] ) ) << 40 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[6] ) ) << 48 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[7] ) ) << 56;
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
template<class T> inline std::uint64_t read64le( T* p )
|
||||
{
|
||||
std::uint64_t w;
|
||||
|
||||
std::memcpy( &w, p, 8 );
|
||||
return w;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<class It>
|
||||
inline typename std::enable_if<
|
||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
||||
std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
|
||||
(std::numeric_limits<std::size_t>::digits > 32),
|
||||
std::size_t>::type
|
||||
hash_range( std::size_t seed, It first, It last )
|
||||
{
|
||||
It p = first;
|
||||
std::size_t n = static_cast<std::size_t>( last - first );
|
||||
|
||||
std::uint64_t const q = 0x9e3779b97f4a7c15;
|
||||
std::uint64_t const k = 0xdf442d22ce4859b9; // q * q
|
||||
|
||||
std::uint64_t w = mulx( seed + q, k );
|
||||
std::uint64_t h = w ^ n;
|
||||
|
||||
while( n >= 8 )
|
||||
{
|
||||
std::uint64_t v1 = read64le( p );
|
||||
|
||||
w += q;
|
||||
h ^= mulx( v1 + w, k );
|
||||
|
||||
p += 8;
|
||||
n -= 8;
|
||||
}
|
||||
|
||||
{
|
||||
std::uint64_t v1 = 0;
|
||||
|
||||
if( n >= 4 )
|
||||
{
|
||||
v1 = static_cast<std::uint64_t>( read32le( p + static_cast<std::ptrdiff_t>( n - 4 ) ) ) << ( n - 4 ) * 8 | read32le( p );
|
||||
}
|
||||
else if( n >= 1 )
|
||||
{
|
||||
std::size_t const x1 = ( n - 1 ) & 2; // 1: 0, 2: 0, 3: 2
|
||||
std::size_t const x2 = n >> 1; // 1: 0, 2: 1, 3: 1
|
||||
|
||||
v1 =
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x1 ) ] ) ) << x1 * 8 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[ static_cast<std::ptrdiff_t>( x2 ) ] ) ) << x2 * 8 |
|
||||
static_cast<std::uint64_t>( static_cast<unsigned char>( p[ 0 ] ) );
|
||||
}
|
||||
|
||||
w += q;
|
||||
h ^= mulx( v1 + w, k );
|
||||
}
|
||||
|
||||
return mulx( h + w, k );
|
||||
}
|
||||
|
||||
template<class It>
|
||||
inline typename std::enable_if<
|
||||
is_char_type<typename std::iterator_traits<It>::value_type>::value &&
|
||||
!std::is_same<typename std::iterator_traits<It>::iterator_category, std::random_access_iterator_tag>::value &&
|
||||
(std::numeric_limits<std::size_t>::digits > 32),
|
||||
std::size_t>::type
|
||||
hash_range( std::size_t seed, It first, It last )
|
||||
{
|
||||
std::size_t n = 0;
|
||||
|
||||
std::uint64_t const q = 0x9e3779b97f4a7c15;
|
||||
std::uint64_t const k = 0xdf442d22ce4859b9; // q * q
|
||||
|
||||
std::uint64_t w = mulx( seed + q, k );
|
||||
std::uint64_t h = w;
|
||||
|
||||
std::uint64_t v1 = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
v1 = 0;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) );
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 8;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 16;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 24;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 32;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 40;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 48;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
if( first == last )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
v1 |= static_cast<std::uint64_t>( static_cast<unsigned char>( *first ) ) << 56;
|
||||
++first;
|
||||
++n;
|
||||
|
||||
w += q;
|
||||
h ^= mulx( v1 + w, k );
|
||||
}
|
||||
|
||||
h ^= n;
|
||||
|
||||
w += q;
|
||||
h ^= mulx( v1 + w, k );
|
||||
|
||||
return mulx( h + w, k );
|
||||
}
|
||||
|
||||
} // namespace hash_detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_RANGE_HPP
|
||||
62
include/boost/container_hash/detail/hash_tuple_like.hpp
Normal file
62
include/boost/container_hash/detail/hash_tuple_like.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
||||
#define BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
#include <boost/container_hash/is_tuple_like.hpp>
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
inline
|
||||
typename std::enable_if<(I == std::tuple_size<T>::value), void>::type
|
||||
hash_combine_tuple_like( std::size_t&, T const& )
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
inline
|
||||
typename std::enable_if<(I < std::tuple_size<T>::value), void>::type
|
||||
hash_combine_tuple_like( std::size_t& seed, T const& v )
|
||||
{
|
||||
using std::get;
|
||||
boost::hash_combine( seed, get<I>( v ) );
|
||||
|
||||
boost::hash_detail::hash_combine_tuple_like<I + 1>( seed, v );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::size_t hash_tuple_like( T const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_detail::hash_combine_tuple_like<0>( seed, v );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
typename std::enable_if<
|
||||
container_hash::is_tuple_like<T>::value && !container_hash::is_range<T>::value,
|
||||
std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
return boost::hash_detail::hash_tuple_like( v );
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_HASH_TUPLE_LIKE_HPP
|
||||
19
include/boost/container_hash/detail/limits.hpp
Normal file
19
include/boost/container_hash/detail/limits.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
|
||||
#define BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
struct limits : std::numeric_limits<T> {};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
|
||||
79
include/boost/container_hash/detail/mulx.hpp
Normal file
79
include/boost/container_hash/detail/mulx.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright 2022, 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_DETAIL_MULX_HPP
|
||||
#define BOOST_HASH_DETAIL_MULX_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#if defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)
|
||||
|
||||
__forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
|
||||
{
|
||||
std::uint64_t r2;
|
||||
std::uint64_t r = _umul128( x, y, &r2 );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
|
||||
|
||||
__forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
|
||||
{
|
||||
std::uint64_t r = x * y;
|
||||
std::uint64_t r2 = __umulh( x, y );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(__SIZEOF_INT128__)
|
||||
|
||||
inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
|
||||
{
|
||||
__uint128_t r = static_cast<__uint128_t>( x ) * y;
|
||||
return static_cast<std::uint64_t>( r ) ^ static_cast<std::uint64_t>( r >> 64 );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
|
||||
{
|
||||
std::uint64_t x1 = static_cast<std::uint32_t>( x );
|
||||
std::uint64_t x2 = x >> 32;
|
||||
|
||||
std::uint64_t y1 = static_cast<std::uint32_t>( y );
|
||||
std::uint64_t y2 = y >> 32;
|
||||
|
||||
std::uint64_t r3 = x2 * y2;
|
||||
|
||||
std::uint64_t r2a = x1 * y2;
|
||||
|
||||
r3 += r2a >> 32;
|
||||
|
||||
std::uint64_t r2b = x2 * y1;
|
||||
|
||||
r3 += r2b >> 32;
|
||||
|
||||
std::uint64_t r1 = x1 * y1;
|
||||
|
||||
std::uint64_t r2 = (r1 >> 32) + static_cast<std::uint32_t>( r2a ) + static_cast<std::uint32_t>( r2b );
|
||||
|
||||
r1 = (r2 << 32) + static_cast<std::uint32_t>( r1 );
|
||||
r3 += r2 >> 32;
|
||||
|
||||
return r1 ^ r3;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace hash_detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_DETAIL_MULX_HPP
|
||||
10
include/boost/container_hash/extensions.hpp
Normal file
10
include/boost/container_hash/extensions.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
|
||||
#define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
|
||||
573
include/boost/container_hash/hash.hpp
Normal file
573
include/boost/container_hash/hash.hpp
Normal file
@@ -0,0 +1,573 @@
|
||||
// Copyright 2005-2014 Daniel James.
|
||||
// Copyright 2021, 2022, 2025 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// Based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
|
||||
#ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
#include <boost/container_hash/hash_is_avalanching.hpp>
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#include <boost/container_hash/is_contiguous_range.hpp>
|
||||
#include <boost/container_hash/is_unordered_range.hpp>
|
||||
#include <boost/container_hash/is_described_class.hpp>
|
||||
#include <boost/container_hash/detail/hash_integral.hpp>
|
||||
#include <boost/container_hash/detail/hash_tuple_like.hpp>
|
||||
#include <boost/container_hash/detail/hash_mix.hpp>
|
||||
#include <boost/container_hash/detail/hash_range.hpp>
|
||||
#include <boost/describe/bases.hpp>
|
||||
#include <boost/describe/members.hpp>
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX14)
|
||||
# include <boost/mp11/algorithm.hpp>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <complex>
|
||||
#include <utility>
|
||||
#include <limits>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_SMART_PTR)
|
||||
# include <memory>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
|
||||
#include <typeindex>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
|
||||
#include <system_error>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
|
||||
# include <string_view>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
//
|
||||
// boost::hash_value
|
||||
//
|
||||
|
||||
// integral types
|
||||
// in detail/hash_integral.hpp
|
||||
|
||||
// enumeration types
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_enum<T>::value, std::size_t>::type
|
||||
hash_value( T v )
|
||||
{
|
||||
// This should in principle return the equivalent of
|
||||
//
|
||||
// boost::hash_value( to_underlying(v) );
|
||||
//
|
||||
// However, the C++03 implementation of underlying_type,
|
||||
//
|
||||
// conditional<is_signed<T>, make_signed<T>, make_unsigned<T>>::type::type
|
||||
//
|
||||
// generates a legitimate -Wconversion warning in is_signed,
|
||||
// because -1 is not a valid enum value when all the enumerators
|
||||
// are nonnegative.
|
||||
//
|
||||
// So the legacy implementation will have to do for now.
|
||||
|
||||
return static_cast<std::size_t>( v );
|
||||
}
|
||||
|
||||
// floating point types
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template<class T,
|
||||
std::size_t Bits = sizeof(T) * CHAR_BIT,
|
||||
int Digits = std::numeric_limits<T>::digits>
|
||||
struct hash_float_impl;
|
||||
|
||||
// float
|
||||
template<class T, int Digits> struct hash_float_impl<T, 32, Digits>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::uint32_t w;
|
||||
std::memcpy( &w, &v, sizeof( v ) );
|
||||
|
||||
return w;
|
||||
}
|
||||
};
|
||||
|
||||
// double
|
||||
template<class T, int Digits> struct hash_float_impl<T, 64, Digits>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::uint64_t w;
|
||||
std::memcpy( &w, &v, sizeof( v ) );
|
||||
|
||||
return hash_value( w );
|
||||
}
|
||||
};
|
||||
|
||||
// 80 bit long double in 12 bytes
|
||||
template<class T> struct hash_float_impl<T, 96, 64>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::uint64_t w[ 2 ] = {};
|
||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
||||
|
||||
std::size_t seed = 0;
|
||||
|
||||
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
// 80 bit long double in 16 bytes
|
||||
template<class T> struct hash_float_impl<T, 128, 64>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::uint64_t w[ 2 ] = {};
|
||||
std::memcpy( &w, &v, 80 / CHAR_BIT );
|
||||
|
||||
std::size_t seed = 0;
|
||||
|
||||
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
// 128 bit long double
|
||||
template<class T, int Digits> struct hash_float_impl<T, 128, Digits>
|
||||
{
|
||||
static std::size_t fn( T v )
|
||||
{
|
||||
std::uint64_t w[ 2 ];
|
||||
std::memcpy( &w, &v, sizeof( v ) );
|
||||
|
||||
std::size_t seed = 0;
|
||||
|
||||
#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
|
||||
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||
|
||||
#else
|
||||
|
||||
seed = hash_value( w[0] ) + hash_detail::hash_mix( seed );
|
||||
seed = hash_value( w[1] ) + hash_detail::hash_mix( seed );
|
||||
|
||||
#endif
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, std::size_t>::type
|
||||
hash_value( T v )
|
||||
{
|
||||
return boost::hash_detail::hash_float_impl<T>::fn( v + 0 );
|
||||
}
|
||||
|
||||
// pointer types
|
||||
|
||||
// `x + (x >> 3)` adjustment by Alberto Barbati and Dave Harris.
|
||||
template <class T> std::size_t hash_value( T* const& v )
|
||||
{
|
||||
std::uintptr_t x = reinterpret_cast<std::uintptr_t>( v );
|
||||
return boost::hash_value( x + (x >> 3) );
|
||||
}
|
||||
|
||||
// array types
|
||||
|
||||
template<class T, std::size_t N>
|
||||
inline std::size_t hash_value( T const (&x)[ N ] )
|
||||
{
|
||||
return boost::hash_range( x, x + N );
|
||||
}
|
||||
|
||||
template<class T, std::size_t N>
|
||||
inline std::size_t hash_value( T (&x)[ N ] )
|
||||
{
|
||||
return boost::hash_range( x, x + N );
|
||||
}
|
||||
|
||||
// complex
|
||||
|
||||
template <class T>
|
||||
std::size_t hash_value( std::complex<T> const& v )
|
||||
{
|
||||
std::size_t re = boost::hash<T>()( v.real() );
|
||||
std::size_t im = boost::hash<T>()( v.imag() );
|
||||
|
||||
return re + hash_detail::hash_mix( im );
|
||||
}
|
||||
|
||||
// pair
|
||||
|
||||
template <class A, class B>
|
||||
std::size_t hash_value( std::pair<A, B> const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.first );
|
||||
boost::hash_combine( seed, v.second );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
// ranges (list, set, deque...)
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<container_hash::is_range<T>::value && !container_hash::is_contiguous_range<T>::value && !container_hash::is_unordered_range<T>::value, std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
return boost::hash_range( v.begin(), v.end() );
|
||||
}
|
||||
|
||||
// contiguous ranges (string, vector, array)
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<container_hash::is_contiguous_range<T>::value, std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
return boost::hash_range( v.data(), v.data() + v.size() );
|
||||
}
|
||||
|
||||
// unordered ranges (unordered_set, unordered_map)
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<container_hash::is_unordered_range<T>::value, std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
return boost::hash_unordered_range( v.begin(), v.end() );
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
|
||||
( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
|
||||
( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
|
||||
|
||||
// resolve ambiguity with unconstrained stdext::hash_value in <xhash> :-/
|
||||
|
||||
template<template<class...> class L, class... T>
|
||||
typename std::enable_if<container_hash::is_range<L<T...>>::value && !container_hash::is_contiguous_range<L<T...>>::value && !container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
|
||||
hash_value( L<T...> const& v )
|
||||
{
|
||||
return boost::hash_range( v.begin(), v.end() );
|
||||
}
|
||||
|
||||
// contiguous ranges (string, vector, array)
|
||||
|
||||
template<template<class...> class L, class... T>
|
||||
typename std::enable_if<container_hash::is_contiguous_range<L<T...>>::value, std::size_t>::type
|
||||
hash_value( L<T...> const& v )
|
||||
{
|
||||
return boost::hash_range( v.data(), v.data() + v.size() );
|
||||
}
|
||||
|
||||
template<template<class, std::size_t> class L, class T, std::size_t N>
|
||||
typename std::enable_if<container_hash::is_contiguous_range<L<T, N>>::value, std::size_t>::type
|
||||
hash_value( L<T, N> const& v )
|
||||
{
|
||||
return boost::hash_range( v.data(), v.data() + v.size() );
|
||||
}
|
||||
|
||||
// unordered ranges (unordered_set, unordered_map)
|
||||
|
||||
template<template<class...> class L, class... T>
|
||||
typename std::enable_if<container_hash::is_unordered_range<L<T...>>::value, std::size_t>::type
|
||||
hash_value( L<T...> const& v )
|
||||
{
|
||||
return boost::hash_unordered_range( v.begin(), v.end() );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// described classes
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1900
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<container_hash::is_described_class<T>::value, std::size_t>::type
|
||||
hash_value( T const& v )
|
||||
{
|
||||
static_assert( !std::is_union<T>::value, "described unions are not supported" );
|
||||
|
||||
std::size_t r = 0;
|
||||
|
||||
using Bd = describe::describe_bases<T, describe::mod_any_access>;
|
||||
|
||||
mp11::mp_for_each<Bd>([&](auto D){
|
||||
|
||||
using B = typename decltype(D)::type;
|
||||
boost::hash_combine( r, (B const&)v );
|
||||
|
||||
});
|
||||
|
||||
using Md = describe::describe_members<T, describe::mod_any_access>;
|
||||
|
||||
mp11::mp_for_each<Md>([&](auto D){
|
||||
|
||||
boost::hash_combine( r, v.*D.pointer );
|
||||
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1900
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// std::unique_ptr, std::shared_ptr
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_SMART_PTR)
|
||||
|
||||
template <typename T>
|
||||
std::size_t hash_value( std::shared_ptr<T> const& x )
|
||||
{
|
||||
return boost::hash_value( x.get() );
|
||||
}
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
std::size_t hash_value( std::unique_ptr<T, Deleter> const& x )
|
||||
{
|
||||
return boost::hash_value( x.get() );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// std::type_index
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
|
||||
|
||||
inline std::size_t hash_value( std::type_index const& v )
|
||||
{
|
||||
return v.hash_code();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// std::error_code, std::error_condition
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
|
||||
|
||||
inline std::size_t hash_value( std::error_code const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.value() );
|
||||
boost::hash_combine( seed, &v.category() );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
inline std::size_t hash_value( std::error_condition const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
boost::hash_combine( seed, v.value() );
|
||||
boost::hash_combine( seed, &v.category() );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// std::nullptr_t
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_NULLPTR)
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_same<T, std::nullptr_t>::value, std::size_t>::type
|
||||
hash_value( T const& /*v*/ )
|
||||
{
|
||||
return boost::hash_value( static_cast<void*>( nullptr ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// std::optional
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL)
|
||||
|
||||
template <typename T>
|
||||
std::size_t hash_value( std::optional<T> const& v )
|
||||
{
|
||||
if( !v )
|
||||
{
|
||||
// Arbitrary value for empty optional.
|
||||
return 0x12345678;
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::hash<T>()(*v);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// std::variant
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||
|
||||
inline std::size_t hash_value( std::monostate )
|
||||
{
|
||||
return 0x87654321;
|
||||
}
|
||||
|
||||
template <typename... Types>
|
||||
std::size_t hash_value( std::variant<Types...> const& v )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
hash_combine( seed, v.index() );
|
||||
std::visit( [&seed](auto&& x) { hash_combine(seed, x); }, v );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost::hash_combine
|
||||
//
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine( std::size_t& seed, T const& v )
|
||||
{
|
||||
seed = boost::hash_detail::hash_mix( seed + 0x9e3779b9 + boost::hash<T>()( v ) );
|
||||
}
|
||||
|
||||
//
|
||||
// boost::hash_range
|
||||
//
|
||||
|
||||
template <class It>
|
||||
inline void hash_range( std::size_t& seed, It first, It last )
|
||||
{
|
||||
seed = hash_detail::hash_range( seed, first, last );
|
||||
}
|
||||
|
||||
template <class It>
|
||||
inline std::size_t hash_range( It first, It last )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
hash_range( seed, first, last );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
//
|
||||
// boost::hash_unordered_range
|
||||
//
|
||||
|
||||
template <class It>
|
||||
inline void hash_unordered_range( std::size_t& seed, It first, It last )
|
||||
{
|
||||
std::size_t r = 0;
|
||||
std::size_t const s2( seed );
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
std::size_t s3( s2 );
|
||||
|
||||
hash_combine<typename std::iterator_traits<It>::value_type>( s3, *first );
|
||||
|
||||
r += s3;
|
||||
}
|
||||
|
||||
seed += r;
|
||||
}
|
||||
|
||||
template <class It>
|
||||
inline std::size_t hash_unordered_range( It first, It last )
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
hash_unordered_range( seed, first, last );
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
//
|
||||
// boost::hash
|
||||
//
|
||||
|
||||
template <class T> struct hash
|
||||
{
|
||||
typedef T argument_type;
|
||||
typedef std::size_t result_type;
|
||||
|
||||
std::size_t operator()( T const& val ) const
|
||||
{
|
||||
return hash_value( val );
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ( \
|
||||
( defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142 ) || \
|
||||
( !defined(_MSVC_STL_VERSION) && defined(_CPPLIB_VER) && _CPPLIB_VER >= 520 ) )
|
||||
|
||||
// Dinkumware has stdext::hash_value for basic_string in <xhash> :-/
|
||||
|
||||
template<class E, class T, class A> struct hash< std::basic_string<E, T, A> >
|
||||
{
|
||||
typedef std::basic_string<E, T, A> argument_type;
|
||||
typedef std::size_t result_type;
|
||||
|
||||
std::size_t operator()( std::basic_string<E, T, A> const& val ) const
|
||||
{
|
||||
return boost::hash_value( val );
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// hash_is_avalanching
|
||||
|
||||
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string<Ch> > >: std::is_integral<Ch> {};
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
|
||||
|
||||
template<class Ch> struct hash_is_avalanching< boost::hash< std::basic_string_view<Ch> > >: std::is_integral<Ch> {};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||
39
include/boost/container_hash/hash_fwd.hpp
Normal file
39
include/boost/container_hash/hash_fwd.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2021, 2022, 2025 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP
|
||||
#define BOOST_FUNCTIONAL_HASH_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_range;
|
||||
template<class T> struct is_contiguous_range;
|
||||
template<class T> struct is_unordered_range;
|
||||
template<class T> struct is_described_class;
|
||||
template<class T> struct is_tuple_like;
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
template<class T> struct hash;
|
||||
|
||||
template<class T> void hash_combine( std::size_t& seed, T const& v );
|
||||
|
||||
template<class It> void hash_range( std::size_t&, It, It );
|
||||
template<class It> std::size_t hash_range( It, It );
|
||||
|
||||
template<class It> void hash_unordered_range( std::size_t&, It, It );
|
||||
template<class It> std::size_t hash_unordered_range( It, It );
|
||||
|
||||
template<class Hash> struct hash_is_avalanching;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_FUNCTIONAL_HASH_FWD_HPP
|
||||
57
include/boost/container_hash/hash_is_avalanching.hpp
Normal file
57
include/boost/container_hash/hash_is_avalanching.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2025 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
|
||||
#define BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<class... Ts> struct make_void
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template<class... Ts> using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
template<class IsAvalanching> struct avalanching_value
|
||||
{
|
||||
static constexpr bool value = IsAvalanching::value;
|
||||
};
|
||||
|
||||
// may be explicitly marked as BOOST_DEPRECATED in the future
|
||||
template<> struct avalanching_value<void>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class Hash, class = void> struct hash_is_avalanching_impl: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class Hash> struct hash_is_avalanching_impl<Hash, void_t<typename Hash::is_avalanching> >:
|
||||
std::integral_constant<bool, avalanching_value<typename Hash::is_avalanching>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template<class Hash>
|
||||
struct hash_is_avalanching_impl<Hash, typename std::enable_if< ((void)Hash::is_avalanching, true) >::type>
|
||||
{
|
||||
// Hash::is_avalanching is not a type: we don't define value to produce
|
||||
// a compile error downstream
|
||||
};
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
template<class Hash> struct hash_is_avalanching: hash_detail::hash_is_avalanching_impl<Hash>::type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_HASH_IS_AVALANCHING_HPP_INCLUDED
|
||||
98
include/boost/container_hash/is_contiguous_range.hpp
Normal file
98
include/boost/container_hash/is_contiguous_range.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2017, 2018 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
||||
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<class It, class T, class S>
|
||||
std::integral_constant< bool, std::is_same<typename std::iterator_traits<It>::value_type, T>::value && std::is_integral<S>::value >
|
||||
is_contiguous_range_check( It first, It last, T const*, T const*, S );
|
||||
|
||||
template<class T> decltype( is_contiguous_range_check( std::declval<T const&>().begin(), std::declval<T const&>().end(), std::declval<T const&>().data(), std::declval<T const&>().data() + std::declval<T const&>().size(), std::declval<T const&>().size() ) ) is_contiguous_range_( int );
|
||||
template<class T> std::false_type is_contiguous_range_( ... );
|
||||
|
||||
template<class T> struct is_contiguous_range: decltype( hash_detail::is_contiguous_range_<T>( 0 ) )
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_contiguous_range: std::integral_constant< bool, is_range<T>::value && hash_detail::is_contiguous_range<T>::value >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#else // !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_contiguous_range: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class E, class T, class A> struct is_contiguous_range< std::basic_string<E, T, A> >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class E, class T, class A> struct is_contiguous_range< std::basic_string<E, T, A> const >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T, class A> struct is_contiguous_range< std::vector<T, A> >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T, class A> struct is_contiguous_range< std::vector<T, A> const >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class A> struct is_contiguous_range< std::vector<bool, A> >: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class A> struct is_contiguous_range< std::vector<bool, A> const >: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T, std::size_t N> struct is_contiguous_range< std::array<T, N> >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T, std::size_t N> struct is_contiguous_range< std::array<T, N> const >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif // !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||
|
||||
#endif // #ifndef BOOST_HASH_IS_CONTIGUOUS_RANGE_HPP_INCLUDED
|
||||
37
include/boost/container_hash/is_described_class.hpp
Normal file
37
include/boost/container_hash/is_described_class.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
|
||||
|
||||
#include <boost/describe/bases.hpp>
|
||||
#include <boost/describe/members.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
#if defined(BOOST_DESCRIBE_CXX11)
|
||||
|
||||
template<class T> struct is_described_class: std::integral_constant<bool,
|
||||
describe::has_describe_bases<T>::value &&
|
||||
describe::has_describe_members<T>::value &&
|
||||
!std::is_union<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<class T> struct is_described_class: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_IS_DESCRIBED_CLASS_HPP_INCLUDED
|
||||
41
include/boost/container_hash/is_range.hpp
Normal file
41
include/boost/container_hash/is_range.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2017 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<class T> struct iterator_traits: std::iterator_traits<T> {};
|
||||
template<> struct iterator_traits< void* > {};
|
||||
template<> struct iterator_traits< void const* > {};
|
||||
|
||||
template<class T, class It>
|
||||
std::integral_constant< bool, !std::is_same<typename std::remove_cv<T>::type, typename iterator_traits<It>::value_type>::value >
|
||||
is_range_check( It first, It last );
|
||||
|
||||
template<class T> decltype( is_range_check<T>( std::declval<T const&>().begin(), std::declval<T const&>().end() ) ) is_range_( int );
|
||||
template<class T> std::false_type is_range_( ... );
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_range: decltype( hash_detail::is_range_<T>( 0 ) )
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace container_hash
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_IS_RANGE_HPP_INCLUDED
|
||||
36
include/boost/container_hash/is_tuple_like.hpp
Normal file
36
include/boost/container_hash/is_tuple_like.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED
|
||||
|
||||
// Copyright 2017, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<class T, class E = std::true_type> struct is_tuple_like_: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T> struct is_tuple_like_<T, std::integral_constant<bool, std::tuple_size<T>::value == std::tuple_size<T>::value> >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_tuple_like: hash_detail::is_tuple_like_< typename std::remove_cv<T>::type >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_IS_TUPLE_LIKE_HPP_INCLUDED
|
||||
38
include/boost/container_hash/is_unordered_range.hpp
Normal file
38
include/boost/container_hash/is_unordered_range.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2017 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED
|
||||
#define BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED
|
||||
|
||||
#include <boost/container_hash/is_range.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
|
||||
template<class T, class E = std::true_type> struct has_hasher_: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<class T> struct has_hasher_< T, std::integral_constant< bool,
|
||||
std::is_same<typename T::hasher, typename T::hasher>::value
|
||||
> >: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace hash_detail
|
||||
|
||||
namespace container_hash
|
||||
{
|
||||
|
||||
template<class T> struct is_unordered_range: std::integral_constant< bool, is_range<T>::value && hash_detail::has_hasher_<T>::value >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace container_hash
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_HASH_IS_UNORDERED_RANGE_HPP_INCLUDED
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
// Copyright 2005-2008 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Forwarding header for container_fwd.hpp's new location.
|
||||
// This header is deprecated, I'll be adding a warning in a future release,
|
||||
// then converting it to an error and finally removing this header completely.
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_DETAIL_CONTAINER_FWD_HPP)
|
||||
#define BOOST_FUNCTIONAL_DETAIL_CONTAINER_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/detail/container_fwd.hpp>
|
||||
|
||||
#endif
|
||||
@@ -3,5 +3,4 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP)
|
||||
#define BOOST_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
// The C++ standard requires that the C float functions are overloarded
|
||||
// for float, double and long double in the std namespace, but some of the older
|
||||
// library implementations don't support this. On some that don't, the C99
|
||||
// float functions (frexpf, frexpl, etc.) are available.
|
||||
//
|
||||
// The following tries to automatically detect which are available.
|
||||
|
||||
namespace boost {
|
||||
namespace hash_detail {
|
||||
|
||||
// Returned by dummy versions of the float functions.
|
||||
|
||||
struct not_found {
|
||||
// Implicitly convertible to float and long double in order to avoid
|
||||
// a compile error when the dummy float functions are used.
|
||||
|
||||
inline operator float() const { return 0; }
|
||||
inline operator long double() const { return 0; }
|
||||
};
|
||||
|
||||
// A type for detecting the return type of functions.
|
||||
|
||||
template <typename T> struct is;
|
||||
template <> struct is<float> { char x[10]; };
|
||||
template <> struct is<double> { char x[20]; };
|
||||
template <> struct is<long double> { char x[30]; };
|
||||
template <> struct is<boost::hash_detail::not_found> { char x[40]; };
|
||||
|
||||
// Used to convert the return type of a function to a type for sizeof.
|
||||
|
||||
template <typename T> is<T> float_type(T);
|
||||
|
||||
// call_ldexp
|
||||
//
|
||||
// This will get specialized for float and long double
|
||||
|
||||
template <typename Float> struct call_ldexp
|
||||
{
|
||||
typedef double float_type;
|
||||
|
||||
inline double operator()(double a, int b) const
|
||||
{
|
||||
using namespace std;
|
||||
return ldexp(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
// call_frexp
|
||||
//
|
||||
// This will get specialized for float and long double
|
||||
|
||||
template <typename Float> struct call_frexp
|
||||
{
|
||||
typedef double float_type;
|
||||
|
||||
inline double operator()(double a, int* b) const
|
||||
{
|
||||
using namespace std;
|
||||
return frexp(a, b);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// A namespace for dummy functions to detect when the actual function we want
|
||||
// isn't available. ldexpl, ldexpf etc. might be added tby the macros below.
|
||||
//
|
||||
// AFAICT these have to be outside of the boost namespace, as if they're in
|
||||
// the boost namespace they'll always be preferable to any other function
|
||||
// (since the arguments are built in types, ADL can't be used).
|
||||
|
||||
namespace boost_hash_detect_float_functions {
|
||||
template <class Float> boost::hash_detail::not_found ldexp(Float, int);
|
||||
template <class Float> boost::hash_detail::not_found frexp(Float, int*);
|
||||
}
|
||||
|
||||
// Macros for generating specializations of call_ldexp and call_frexp.
|
||||
//
|
||||
// check_cpp and check_c99 check if the C++ or C99 functions are available.
|
||||
//
|
||||
// Then the call_* functions select an appropriate implementation.
|
||||
//
|
||||
// I used c99_func in a few places just to get a unique name.
|
||||
//
|
||||
// Important: when using 'using namespace' at namespace level, include as
|
||||
// little as possible in that namespace, as Visual C++ has an odd bug which
|
||||
// can cause the namespace to be imported at the global level. This seems to
|
||||
// happen mainly when there's a template in the same namesapce.
|
||||
|
||||
#define BOOST_HASH_CALL_FLOAT_FUNC(cpp_func, c99_func, type1, type2) \
|
||||
namespace boost_hash_detect_float_functions { \
|
||||
template <class Float> \
|
||||
boost::hash_detail::not_found c99_func(Float, type2); \
|
||||
} \
|
||||
\
|
||||
namespace boost { \
|
||||
namespace hash_detail { \
|
||||
namespace c99_func##_detect { \
|
||||
using namespace std; \
|
||||
using namespace boost_hash_detect_float_functions; \
|
||||
\
|
||||
struct check { \
|
||||
static type1 x; \
|
||||
static type2 y; \
|
||||
BOOST_STATIC_CONSTANT(bool, cpp = \
|
||||
sizeof(float_type(cpp_func(x,y))) \
|
||||
== sizeof(is<type1>)); \
|
||||
BOOST_STATIC_CONSTANT(bool, c99 = \
|
||||
sizeof(float_type(c99_func(x,y))) \
|
||||
== sizeof(is<type1>)); \
|
||||
}; \
|
||||
} \
|
||||
\
|
||||
template <bool x> \
|
||||
struct call_c99_##c99_func : \
|
||||
boost::hash_detail::call_##cpp_func<double> {}; \
|
||||
\
|
||||
template <> \
|
||||
struct call_c99_##c99_func<true> { \
|
||||
typedef type1 float_type; \
|
||||
\
|
||||
template <typename T> \
|
||||
inline type1 operator()(type1 a, T b) const \
|
||||
{ \
|
||||
using namespace std; \
|
||||
return c99_func(a, b); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <bool x> \
|
||||
struct call_cpp_##c99_func : \
|
||||
call_c99_##c99_func< \
|
||||
::boost::hash_detail::c99_func##_detect::check::c99 \
|
||||
> {}; \
|
||||
\
|
||||
template <> \
|
||||
struct call_cpp_##c99_func<true> { \
|
||||
typedef type1 float_type; \
|
||||
\
|
||||
template <typename T> \
|
||||
inline type1 operator()(type1 a, T b) const \
|
||||
{ \
|
||||
using namespace std; \
|
||||
return cpp_func(a, b); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct call_##cpp_func<type1> : \
|
||||
call_cpp_##c99_func< \
|
||||
::boost::hash_detail::c99_func##_detect::check::cpp \
|
||||
> {}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2) \
|
||||
namespace boost { \
|
||||
namespace hash_detail { \
|
||||
\
|
||||
template <> \
|
||||
struct call_##cpp_func<type1> { \
|
||||
typedef type1 float_type; \
|
||||
inline type1 operator()(type1 x, type2 y) const { \
|
||||
return c99_func(x, y); \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(ldexpf)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
|
||||
#endif
|
||||
|
||||
#if defined(ldexpl)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
|
||||
#endif
|
||||
|
||||
#if defined(frexpf)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
|
||||
#endif
|
||||
|
||||
#if defined(frexpl)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpl, long double, int*)
|
||||
#endif
|
||||
|
||||
#undef BOOST_HASH_CALL_FLOAT_MACRO
|
||||
#undef BOOST_HASH_CALL_FLOAT_FUNC
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <typename Float1, typename Float2>
|
||||
struct select_hash_type_impl {
|
||||
typedef double type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct select_hash_type_impl<float, float> {
|
||||
typedef float type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct select_hash_type_impl<long double, long double> {
|
||||
typedef long double type;
|
||||
};
|
||||
|
||||
|
||||
// select_hash_type
|
||||
//
|
||||
// If there is support for a particular floating point type, use that
|
||||
// otherwise use double (there's always support for double).
|
||||
|
||||
template <typename Float>
|
||||
struct select_hash_type : select_hash_type_impl<
|
||||
BOOST_DEDUCED_TYPENAME call_ldexp<Float>::float_type,
|
||||
BOOST_DEDUCED_TYPENAME call_frexp<Float>::float_type
|
||||
> {};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,101 +0,0 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER)
|
||||
#define BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/functional/hash/detail/float_functions.hpp>
|
||||
#include <boost/functional/hash/detail/limits.hpp>
|
||||
#include <boost/integer/static_log2.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Include hash implementation for the current platform.
|
||||
|
||||
// Cygwn
|
||||
#if defined(__CYGWIN__)
|
||||
# if defined(__i386__) || defined(_M_IX86)
|
||||
# include <boost/functional/hash/detail/hash_float_x86.hpp>
|
||||
# else
|
||||
# include <boost/functional/hash/detail/hash_float_generic.hpp>
|
||||
# endif
|
||||
#else
|
||||
# include <boost/functional/hash/detail/hash_float_generic.hpp>
|
||||
#endif
|
||||
|
||||
// Can we use fpclassify?
|
||||
|
||||
// STLport
|
||||
#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
||||
#define BOOST_HASH_USE_FPCLASSIFY 0
|
||||
|
||||
// GNU libstdc++ 3
|
||||
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
||||
# if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \
|
||||
!(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
|
||||
# define BOOST_HASH_USE_FPCLASSIFY 1
|
||||
# else
|
||||
# define BOOST_HASH_USE_FPCLASSIFY 0
|
||||
# endif
|
||||
|
||||
// Everything else
|
||||
#else
|
||||
# define BOOST_HASH_USE_FPCLASSIFY 0
|
||||
#endif
|
||||
|
||||
#if BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
inline std::size_t float_hash_value(T v)
|
||||
{
|
||||
using namespace std;
|
||||
switch (fpclassify(v)) {
|
||||
case FP_ZERO:
|
||||
return 0;
|
||||
case FP_INFINITE:
|
||||
return (std::size_t)(v > 0 ? -1 : -2);
|
||||
case FP_NAN:
|
||||
return (std::size_t)(-3);
|
||||
case FP_NORMAL:
|
||||
case FP_SUBNORMAL:
|
||||
return float_hash_impl(v);
|
||||
default:
|
||||
BOOST_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // !BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
inline std::size_t float_hash_value(T v)
|
||||
{
|
||||
return v == 0 ? 0 : float_hash_impl(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
#undef BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
#endif
|
||||
@@ -1,91 +0,0 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// A general purpose hash function for non-zero floating point values.
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_GENERIC_HEADER)
|
||||
#define BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_GENERIC_HEADER
|
||||
|
||||
#include <boost/functional/hash/detail/float_functions.hpp>
|
||||
#include <boost/integer/static_log2.hpp>
|
||||
#include <boost/functional/hash/detail/limits.hpp>
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#if BOOST_MSVC >= 1400
|
||||
#pragma warning(disable:6294) // Ill-defined for-loop: initial condition does
|
||||
// not satisfy test. Loop body not executed
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
inline void hash_float_combine(std::size_t& seed, std::size_t value)
|
||||
{
|
||||
seed ^= value + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline std::size_t float_hash_impl2(T v)
|
||||
{
|
||||
boost::hash_detail::call_frexp<T> frexp;
|
||||
boost::hash_detail::call_ldexp<T> ldexp;
|
||||
|
||||
int exp = 0;
|
||||
|
||||
v = frexp(v, &exp);
|
||||
|
||||
// A postive value is easier to hash, so combine the
|
||||
// sign with the exponent and use the absolute value.
|
||||
if(v < 0) {
|
||||
v = -v;
|
||||
exp += limits<T>::max_exponent -
|
||||
limits<T>::min_exponent;
|
||||
}
|
||||
|
||||
v = ldexp(v, limits<std::size_t>::digits);
|
||||
std::size_t seed = static_cast<std::size_t>(v);
|
||||
v -= static_cast<T>(seed);
|
||||
|
||||
// ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1;
|
||||
std::size_t const length
|
||||
= (limits<T>::digits *
|
||||
boost::static_log2<limits<T>::radix>::value
|
||||
+ limits<std::size_t>::digits - 1)
|
||||
/ limits<std::size_t>::digits;
|
||||
|
||||
for(std::size_t i = 0; i != length; ++i)
|
||||
{
|
||||
v = ldexp(v, limits<std::size_t>::digits);
|
||||
std::size_t part = static_cast<std::size_t>(v);
|
||||
v -= static_cast<T>(part);
|
||||
hash_float_combine(seed, part);
|
||||
}
|
||||
|
||||
hash_float_combine(seed, exp);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline std::size_t float_hash_impl(T v)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME select_hash_type<T>::type type;
|
||||
return float_hash_impl2(static_cast<type>(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// A non-portable hash function form non-zero floats on x86.
|
||||
//
|
||||
// Even if you're on an x86 platform, this might not work if their floating
|
||||
// point isn't set up as this expects. So this should only be used if it's
|
||||
// absolutely certain that it will work.
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_X86_HEADER)
|
||||
#define BOOST_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_X86_HEADER
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
inline void hash_float_combine(std::size_t& seed, std::size_t value)
|
||||
{
|
||||
seed ^= value + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
inline std::size_t float_hash_impl(float v)
|
||||
{
|
||||
boost::uint32_t* ptr = (boost::uint32_t*)&v;
|
||||
std::size_t seed = *ptr;
|
||||
return seed;
|
||||
}
|
||||
|
||||
inline std::size_t float_hash_impl(double v)
|
||||
{
|
||||
boost::uint32_t* ptr = (boost::uint32_t*)&v;
|
||||
std::size_t seed = *ptr++;
|
||||
hash_float_combine(seed, *ptr);
|
||||
return seed;
|
||||
}
|
||||
|
||||
inline std::size_t float_hash_impl(long double v)
|
||||
{
|
||||
boost::uint32_t* ptr = (boost::uint32_t*)&v;
|
||||
std::size_t seed = *ptr++;
|
||||
hash_float_combine(seed, *ptr++);
|
||||
hash_float_combine(seed, *(boost::uint16_t*)ptr);
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// On some platforms std::limits gives incorrect values for long double.
|
||||
// This tries to work around them.
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER)
|
||||
#define BOOST_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/limits.hpp>
|
||||
|
||||
// On OpenBSD, numeric_limits is not reliable for long doubles, but
|
||||
// the macros defined in <float.h> are and support long double when STLport
|
||||
// doesn't.
|
||||
|
||||
#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
struct limits : std::numeric_limits<T> {};
|
||||
|
||||
#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
|
||||
template <>
|
||||
struct limits<long double>
|
||||
: std::numeric_limits<long double>
|
||||
{
|
||||
static long double epsilon() {
|
||||
return LDBL_EPSILON;
|
||||
}
|
||||
|
||||
static long double (max)() {
|
||||
return LDBL_MAX;
|
||||
}
|
||||
|
||||
static long double (min)() {
|
||||
return LDBL_MIN;
|
||||
}
|
||||
|
||||
BOOST_STATIC_CONSTANT(int, digits = LDBL_MANT_DIG);
|
||||
BOOST_STATIC_CONSTANT(int, max_exponent = LDBL_MAX_EXP);
|
||||
BOOST_STATIC_CONSTANT(int, min_exponent = LDBL_MIN_EXP);
|
||||
#if defined(_STLP_NO_LONG_DOUBLE)
|
||||
BOOST_STATIC_CONSTANT(int, radix = FLT_RADIX);
|
||||
#endif
|
||||
};
|
||||
#endif // __OpenBSD__
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,286 +1,6 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2017 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
|
||||
// This implements the extensions to the standard.
|
||||
// It's undocumented, so you shouldn't use it....
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
|
||||
#define BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP
|
||||
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
#include <boost/detail/container_fwd.hpp>
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
#include <boost/type_traits/is_array.hpp>
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class A, class B>
|
||||
std::size_t hash_value(std::pair<A, B> const&);
|
||||
template <class T, class A>
|
||||
std::size_t hash_value(std::vector<T, A> const&);
|
||||
template <class T, class A>
|
||||
std::size_t hash_value(std::list<T, A> const& v);
|
||||
template <class T, class A>
|
||||
std::size_t hash_value(std::deque<T, A> const& v);
|
||||
template <class K, class C, class A>
|
||||
std::size_t hash_value(std::set<K, C, A> const& v);
|
||||
template <class K, class C, class A>
|
||||
std::size_t hash_value(std::multiset<K, C, A> const& v);
|
||||
template <class K, class T, class C, class A>
|
||||
std::size_t hash_value(std::map<K, T, C, A> const& v);
|
||||
template <class K, class T, class C, class A>
|
||||
std::size_t hash_value(std::multimap<K, T, C, A> const& v);
|
||||
|
||||
template <class T>
|
||||
std::size_t hash_value(std::complex<T> const&);
|
||||
|
||||
template <class A, class B>
|
||||
std::size_t hash_value(std::pair<A, B> const& v)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
hash_combine(seed, v.first);
|
||||
hash_combine(seed, v.second);
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
std::size_t hash_value(std::vector<T, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
std::size_t hash_value(std::list<T, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
std::size_t hash_value(std::deque<T, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class C, class A>
|
||||
std::size_t hash_value(std::set<K, C, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class C, class A>
|
||||
std::size_t hash_value(std::multiset<K, C, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class T, class C, class A>
|
||||
std::size_t hash_value(std::map<K, T, C, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class T, class C, class A>
|
||||
std::size_t hash_value(std::multimap<K, T, C, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::size_t hash_value(std::complex<T> const& v)
|
||||
{
|
||||
boost::hash<T> hasher;
|
||||
std::size_t seed = hasher(v.imag());
|
||||
seed ^= hasher(v.real()) + (seed<<6) + (seed>>2);
|
||||
return seed;
|
||||
}
|
||||
|
||||
//
|
||||
// call_hash_impl
|
||||
//
|
||||
|
||||
// On compilers without function template ordering, this deals with arrays.
|
||||
|
||||
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
namespace hash_detail
|
||||
{
|
||||
template <bool IsArray>
|
||||
struct call_hash_impl
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
{
|
||||
static std::size_t call(T const& v)
|
||||
{
|
||||
using namespace boost;
|
||||
return hash_value(v);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct call_hash_impl<true>
|
||||
{
|
||||
template <class Array>
|
||||
struct inner
|
||||
{
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
static std::size_t call(Array const& v)
|
||||
#else
|
||||
static std::size_t call(Array& v)
|
||||
#endif
|
||||
{
|
||||
const int size = sizeof(v) / sizeof(*v);
|
||||
return boost::hash_range(v, v + size);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct call_hash
|
||||
: public call_hash_impl<boost::is_array<T>::value>
|
||||
::BOOST_NESTED_TEMPLATE inner<T>
|
||||
{
|
||||
};
|
||||
}
|
||||
#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
|
||||
|
||||
//
|
||||
// boost::hash
|
||||
//
|
||||
|
||||
|
||||
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
|
||||
template <class T> struct hash
|
||||
: std::unary_function<T, std::size_t>
|
||||
{
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
std::size_t operator()(T const& val) const
|
||||
{
|
||||
return hash_value(val);
|
||||
}
|
||||
#else
|
||||
std::size_t operator()(T const& val) const
|
||||
{
|
||||
return hash_detail::call_hash<T>::call(val);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(__DMC__, <= 0x848)
|
||||
template <class T, unsigned int n> struct hash<T[n]>
|
||||
: std::unary_function<T[n], std::size_t>
|
||||
{
|
||||
std::size_t operator()(const T* val) const
|
||||
{
|
||||
return boost::hash_range(val, val+n);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
|
||||
// On compilers without partial specialization, boost::hash<T>
|
||||
// has already been declared to deal with pointers, so just
|
||||
// need to supply the non-pointer version of hash_impl.
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template <bool IsPointer>
|
||||
struct hash_impl;
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
|
||||
template <>
|
||||
struct hash_impl<false>
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
: std::unary_function<T, std::size_t>
|
||||
{
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
std::size_t operator()(T const& val) const
|
||||
{
|
||||
return hash_value(val);
|
||||
}
|
||||
#else
|
||||
std::size_t operator()(T const& val) const
|
||||
{
|
||||
return hash_detail::call_hash<T>::call(val);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
#else // Visual C++ 6.5
|
||||
|
||||
// Visual C++ 6.5 has problems with nested member functions and
|
||||
// applying const to const types in templates. So we get this:
|
||||
|
||||
template <bool IsConst>
|
||||
struct hash_impl_msvc
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
: public std::unary_function<T, std::size_t>
|
||||
{
|
||||
std::size_t operator()(T const& val) const
|
||||
{
|
||||
return hash_detail::call_hash<T const>::call(val);
|
||||
}
|
||||
|
||||
std::size_t operator()(T& val) const
|
||||
{
|
||||
return hash_detail::call_hash<T>::call(val);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash_impl_msvc<true>
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
: public std::unary_function<T, std::size_t>
|
||||
{
|
||||
std::size_t operator()(T& val) const
|
||||
{
|
||||
return hash_detail::call_hash<T>::call(val);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct hash_impl_msvc2
|
||||
: public hash_impl_msvc<boost::is_const<T>::value>
|
||||
::BOOST_NESTED_TEMPLATE inner<T> {};
|
||||
|
||||
template <>
|
||||
struct hash_impl<false>
|
||||
{
|
||||
template <class T>
|
||||
struct inner : public hash_impl_msvc2<T> {};
|
||||
};
|
||||
|
||||
#endif // Visual C++ 6.5
|
||||
}
|
||||
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
}
|
||||
|
||||
#endif
|
||||
#include <boost/container_hash/extensions.hpp>
|
||||
|
||||
@@ -3,534 +3,4 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_HASH_HPP)
|
||||
#define BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||
|
||||
#include <boost/functional/hash/hash_fwd.hpp>
|
||||
#include <functional>
|
||||
#include <boost/functional/hash/detail/hash_float.hpp>
|
||||
#include <string>
|
||||
#include <boost/limits.hpp>
|
||||
|
||||
#if defined(BOOST_HASH_NO_IMPLICIT_CASTS)
|
||||
#include <boost/static_assert.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_TYPEINDEX)
|
||||
#include <typeindex>
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__GNUC__, < 3) \
|
||||
&& !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
|
||||
#define BOOST_HASH_CHAR_TRAITS string_char_traits
|
||||
#else
|
||||
#define BOOST_HASH_CHAR_TRAITS char_traits
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
#if defined(BOOST_HASH_NO_IMPLICIT_CASTS)
|
||||
|
||||
// If you get a static assertion here, it's because hash_value
|
||||
// isn't declared for your type.
|
||||
template <typename T>
|
||||
std::size_t hash_value(T const&) {
|
||||
BOOST_STATIC_ASSERT((T*) 0 && false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::size_t hash_value(bool);
|
||||
std::size_t hash_value(char);
|
||||
std::size_t hash_value(unsigned char);
|
||||
std::size_t hash_value(signed char);
|
||||
std::size_t hash_value(short);
|
||||
std::size_t hash_value(unsigned short);
|
||||
std::size_t hash_value(int);
|
||||
std::size_t hash_value(unsigned int);
|
||||
std::size_t hash_value(long);
|
||||
std::size_t hash_value(unsigned long);
|
||||
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
std::size_t hash_value(wchar_t);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_LONG_LONG)
|
||||
std::size_t hash_value(boost::long_long_type);
|
||||
std::size_t hash_value(boost::ulong_long_type);
|
||||
#endif
|
||||
|
||||
#if !BOOST_WORKAROUND(__DMC__, <= 0x848)
|
||||
template <class T> std::size_t hash_value(T* const&);
|
||||
#else
|
||||
template <class T> std::size_t hash_value(T*);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
template< class T, unsigned N >
|
||||
std::size_t hash_value(const T (&x)[N]);
|
||||
|
||||
template< class T, unsigned N >
|
||||
std::size_t hash_value(T (&x)[N]);
|
||||
#endif
|
||||
|
||||
std::size_t hash_value(float v);
|
||||
std::size_t hash_value(double v);
|
||||
std::size_t hash_value(long double v);
|
||||
|
||||
template <class Ch, class A>
|
||||
std::size_t hash_value(
|
||||
std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const&);
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_TYPEINDEX)
|
||||
std::size_t hash_value(std::type_index);
|
||||
#endif
|
||||
|
||||
// Implementation
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
inline std::size_t hash_value_signed(T val)
|
||||
{
|
||||
const int size_t_bits = std::numeric_limits<std::size_t>::digits;
|
||||
// ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
|
||||
const int length = (std::numeric_limits<T>::digits - 1)
|
||||
/ size_t_bits;
|
||||
|
||||
std::size_t seed = 0;
|
||||
T positive = val < 0 ? -1 - val : val;
|
||||
|
||||
// Hopefully, this loop can be unrolled.
|
||||
for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
|
||||
{
|
||||
seed ^= (std::size_t) (positive >> i) + (seed<<6) + (seed>>2);
|
||||
}
|
||||
seed ^= (std::size_t) val + (seed<<6) + (seed>>2);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline std::size_t hash_value_unsigned(T val)
|
||||
{
|
||||
const int size_t_bits = std::numeric_limits<std::size_t>::digits;
|
||||
// ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
|
||||
const int length = (std::numeric_limits<T>::digits - 1)
|
||||
/ size_t_bits;
|
||||
|
||||
std::size_t seed = 0;
|
||||
|
||||
// Hopefully, this loop can be unrolled.
|
||||
for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
|
||||
{
|
||||
seed ^= (std::size_t) (val >> i) + (seed<<6) + (seed>>2);
|
||||
}
|
||||
seed ^= (std::size_t) val + (seed<<6) + (seed>>2);
|
||||
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(bool v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(char v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(unsigned char v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(signed char v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(short v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(unsigned short v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(int v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(unsigned int v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(long v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(unsigned long v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
inline std::size_t hash_value(wchar_t v)
|
||||
{
|
||||
return static_cast<std::size_t>(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_LONG_LONG)
|
||||
inline std::size_t hash_value(boost::long_long_type v)
|
||||
{
|
||||
return hash_detail::hash_value_signed(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(boost::ulong_long_type v)
|
||||
{
|
||||
return hash_detail::hash_value_unsigned(v);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Implementation by Alberto Barbati and Dave Harris.
|
||||
#if !BOOST_WORKAROUND(__DMC__, <= 0x848)
|
||||
template <class T> std::size_t hash_value(T* const& v)
|
||||
#else
|
||||
template <class T> std::size_t hash_value(T* v)
|
||||
#endif
|
||||
{
|
||||
#if defined(__VMS) && __INITIAL_POINTER_SIZE == 64
|
||||
// for some reason ptrdiff_t on OpenVMS compiler with
|
||||
// 64 bit is not 64 bit !!!
|
||||
std::size_t x = static_cast<std::size_t>(
|
||||
reinterpret_cast<long long int>(v));
|
||||
#else
|
||||
std::size_t x = static_cast<std::size_t>(
|
||||
reinterpret_cast<std::ptrdiff_t>(v));
|
||||
#endif
|
||||
return x + (x >> 3);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#if BOOST_MSVC <= 1400
|
||||
#pragma warning(disable:4267) // 'argument' : conversion from 'size_t' to
|
||||
// 'unsigned int', possible loss of data
|
||||
// A misguided attempt to detect 64-bit
|
||||
// incompatability.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t& seed, T& v)
|
||||
#else
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t& seed, T const& v)
|
||||
#endif
|
||||
{
|
||||
boost::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class It>
|
||||
inline std::size_t hash_range(It first, It last)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
hash_combine(seed, *first);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class It>
|
||||
inline void hash_range(std::size_t& seed, It first, It last)
|
||||
{
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
hash_combine(seed, *first);
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
|
||||
template <class T>
|
||||
inline std::size_t hash_range(T* first, T* last)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
boost::hash<T> hasher;
|
||||
seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_range(std::size_t& seed, T* first, T* last)
|
||||
{
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
boost::hash<T> hasher;
|
||||
seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
template< class T, unsigned N >
|
||||
inline std::size_t hash_value(const T (&x)[N])
|
||||
{
|
||||
return hash_range(x, x + N);
|
||||
}
|
||||
|
||||
template< class T, unsigned N >
|
||||
inline std::size_t hash_value(T (&x)[N])
|
||||
{
|
||||
return hash_range(x, x + N);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Ch, class A>
|
||||
inline std::size_t hash_value(
|
||||
std::basic_string<Ch, std::BOOST_HASH_CHAR_TRAITS<Ch>, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(float v)
|
||||
{
|
||||
return boost::hash_detail::float_hash_value(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(double v)
|
||||
{
|
||||
return boost::hash_detail::float_hash_value(v);
|
||||
}
|
||||
|
||||
inline std::size_t hash_value(long double v)
|
||||
{
|
||||
return boost::hash_detail::float_hash_value(v);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_TYPEINDEX)
|
||||
inline std::size_t hash_value(std::type_index v)
|
||||
{
|
||||
return v.hash_code();
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// boost::hash
|
||||
//
|
||||
|
||||
// Define the specializations required by the standard. The general purpose
|
||||
// boost::hash is defined later in extensions.hpp if
|
||||
// BOOST_HASH_NO_EXTENSIONS is not defined.
|
||||
|
||||
// BOOST_HASH_SPECIALIZE - define a specialization for a type which is
|
||||
// passed by copy.
|
||||
//
|
||||
// BOOST_HASH_SPECIALIZE_REF - define a specialization for a type which is
|
||||
// passed by copy.
|
||||
//
|
||||
// These are undefined later.
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
#define BOOST_HASH_SPECIALIZE(type) \
|
||||
template <> struct hash<type> \
|
||||
: public std::unary_function<type, std::size_t> \
|
||||
{ \
|
||||
std::size_t operator()(type v) const \
|
||||
{ \
|
||||
return boost::hash_value(v); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define BOOST_HASH_SPECIALIZE_REF(type) \
|
||||
template <> struct hash<type> \
|
||||
: public std::unary_function<type, std::size_t> \
|
||||
{ \
|
||||
std::size_t operator()(type const& v) const \
|
||||
{ \
|
||||
return boost::hash_value(v); \
|
||||
} \
|
||||
};
|
||||
#else
|
||||
#define BOOST_HASH_SPECIALIZE(type) \
|
||||
template <> struct hash<type> \
|
||||
: public std::unary_function<type, std::size_t> \
|
||||
{ \
|
||||
std::size_t operator()(type v) const \
|
||||
{ \
|
||||
return boost::hash_value(v); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> struct hash<const type> \
|
||||
: public std::unary_function<const type, std::size_t> \
|
||||
{ \
|
||||
std::size_t operator()(const type v) const \
|
||||
{ \
|
||||
return boost::hash_value(v); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define BOOST_HASH_SPECIALIZE_REF(type) \
|
||||
template <> struct hash<type> \
|
||||
: public std::unary_function<type, std::size_t> \
|
||||
{ \
|
||||
std::size_t operator()(type const& v) const \
|
||||
{ \
|
||||
return boost::hash_value(v); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> struct hash<const type> \
|
||||
: public std::unary_function<const type, std::size_t> \
|
||||
{ \
|
||||
std::size_t operator()(type const& v) const \
|
||||
{ \
|
||||
return boost::hash_value(v); \
|
||||
} \
|
||||
};
|
||||
#endif
|
||||
|
||||
BOOST_HASH_SPECIALIZE(bool)
|
||||
BOOST_HASH_SPECIALIZE(char)
|
||||
BOOST_HASH_SPECIALIZE(signed char)
|
||||
BOOST_HASH_SPECIALIZE(unsigned char)
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
BOOST_HASH_SPECIALIZE(wchar_t)
|
||||
#endif
|
||||
BOOST_HASH_SPECIALIZE(short)
|
||||
BOOST_HASH_SPECIALIZE(unsigned short)
|
||||
BOOST_HASH_SPECIALIZE(int)
|
||||
BOOST_HASH_SPECIALIZE(unsigned int)
|
||||
BOOST_HASH_SPECIALIZE(long)
|
||||
BOOST_HASH_SPECIALIZE(unsigned long)
|
||||
|
||||
BOOST_HASH_SPECIALIZE(float)
|
||||
BOOST_HASH_SPECIALIZE(double)
|
||||
BOOST_HASH_SPECIALIZE(long double)
|
||||
|
||||
BOOST_HASH_SPECIALIZE_REF(std::string)
|
||||
#if !defined(BOOST_NO_STD_WSTRING)
|
||||
BOOST_HASH_SPECIALIZE_REF(std::wstring)
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_LONG_LONG)
|
||||
BOOST_HASH_SPECIALIZE(boost::long_long_type)
|
||||
BOOST_HASH_SPECIALIZE(boost::ulong_long_type)
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_TYPEINDEX)
|
||||
BOOST_HASH_SPECIALIZE(std::type_index)
|
||||
#endif
|
||||
|
||||
#undef BOOST_HASH_SPECIALIZE
|
||||
#undef BOOST_HASH_SPECIALIZE_REF
|
||||
|
||||
// Specializing boost::hash for pointers.
|
||||
|
||||
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
|
||||
template <class T>
|
||||
struct hash<T*>
|
||||
: public std::unary_function<T*, std::size_t>
|
||||
{
|
||||
std::size_t operator()(T* v) const
|
||||
{
|
||||
#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)
|
||||
return boost::hash_value(v);
|
||||
#else
|
||||
std::size_t x = static_cast<std::size_t>(
|
||||
reinterpret_cast<std::ptrdiff_t>(v));
|
||||
|
||||
return x + (x >> 3);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// For compilers without partial specialization, we define a
|
||||
// boost::hash for all remaining types. But hash_impl is only defined
|
||||
// for pointers in 'extensions.hpp' - so when BOOST_HASH_NO_EXTENSIONS
|
||||
// is defined there will still be a compile error for types not supported
|
||||
// in the standard.
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template <bool IsPointer>
|
||||
struct hash_impl;
|
||||
|
||||
template <>
|
||||
struct hash_impl<true>
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
: public std::unary_function<T, std::size_t>
|
||||
{
|
||||
std::size_t operator()(T val) const
|
||||
{
|
||||
#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 590)
|
||||
return boost::hash_value(val);
|
||||
#else
|
||||
std::size_t x = static_cast<std::size_t>(
|
||||
reinterpret_cast<std::ptrdiff_t>(val));
|
||||
|
||||
return x + (x >> 3);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
template <class T> struct hash
|
||||
: public boost::hash_detail::hash_impl<boost::is_pointer<T>::value>
|
||||
::BOOST_NESTED_TEMPLATE inner<T>
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef BOOST_HASH_CHAR_TRAITS
|
||||
|
||||
#endif // BOOST_FUNCTIONAL_HASH_HASH_HPP
|
||||
|
||||
// Include this outside of the include guards in case the file is included
|
||||
// twice - once with BOOST_HASH_NO_EXTENSIONS defined, and then with it
|
||||
// undefined.
|
||||
|
||||
#if !defined(BOOST_HASH_NO_EXTENSIONS) \
|
||||
&& !defined(BOOST_FUNCTIONAL_HASH_EXTENSIONS_HPP)
|
||||
#include <boost/functional/hash/extensions.hpp>
|
||||
#endif
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
@@ -3,38 +3,4 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
|
||||
#if !defined(BOOST_FUNCTIONAL_HASH_FWD_HPP)
|
||||
#define BOOST_FUNCTIONAL_HASH_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <cstddef>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class T> struct hash;
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
template <class T> void hash_combine(std::size_t& seed, T& v);
|
||||
#else
|
||||
template <class T> void hash_combine(std::size_t& seed, T const& v);
|
||||
#endif
|
||||
|
||||
template <class It> std::size_t hash_range(It, It);
|
||||
template <class It> void hash_range(std::size_t&, It, It);
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
|
||||
template <class T> inline std::size_t hash_range(T*, T*);
|
||||
template <class T> inline void hash_range(std::size_t&, T*, T*);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
@@ -3,5 +3,4 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/functional/hash/hash_fwd.hpp>
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
@@ -7,10 +7,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=../../doc/html/hash.html">
|
||||
<meta http-equiv="refresh" content="0; URL=doc/html/hash.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="../../doc/html/hash.html">../../doc/html/hash.html</a>
|
||||
<a href="doc/html/hash.html">doc/html/hash.html</a>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
96
meta/explicit-failures-markup.xml
Normal file
96
meta/explicit-failures-markup.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2018 Daniel James
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
<explicit-failures-markup>
|
||||
<!-- container_hash -->
|
||||
<library name="container_hash">
|
||||
<mark-expected-failures>
|
||||
<test name="hash_value_array_test"/>
|
||||
<toolset name="msvc-6.5*"/>
|
||||
<toolset name="msvc-7.0*"/>
|
||||
<note author="Daniel James">
|
||||
hash_value is not overloaded for arrays for older versions
|
||||
of Visual C++. There is a work around so that
|
||||
boost::hash<T[N]>, boost::hash_combine and boost::hash_range
|
||||
work.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="hash_function_pointer_test"/>
|
||||
<toolset name="msvc-6.5*"/>
|
||||
<toolset name="msvc-7.0*"/>
|
||||
<note refid="2" author="Daniel James"/>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="hash_function_pointer_test"/>
|
||||
<toolset name="sun-5.7"/>
|
||||
<toolset name="sun-5.8"/>
|
||||
<toolset name="sun-5.9"/>
|
||||
<note author="Daniel James">
|
||||
On these compilers the wrong overload of hash_value is called
|
||||
when the argument is a hash function pointer. So calling
|
||||
hash_value doesn't work but boost::hash does work (and it's
|
||||
recommended that user never call hash_value directly so this
|
||||
shouldn't be a problem).
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="hash_long_double_test"/>
|
||||
<toolset name="gcc-3.4.3_sunos"/>
|
||||
<toolset name="*pa_risc"/>
|
||||
<note author="Daniel James">
|
||||
This platform has poor support for <code>long double</code> so
|
||||
the hash function perform poorly for values out of the range
|
||||
of <code>double</code> or if they differ at a greater precision
|
||||
that <code>double</code> is capable of representing.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="point" />
|
||||
<test name="books" />
|
||||
<toolset name="msvc-6.5*"/>
|
||||
<toolset name="msvc-7.0*"/>
|
||||
<note author="Daniel James">
|
||||
These examples only work on compilers with support for ADL.
|
||||
It is possible to work around this, but I wanted to keep the
|
||||
example code as clean as possible.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="point" />
|
||||
<toolset name="borland-*"/>
|
||||
<note author="Daniel James">
|
||||
It appears that Borland doesn't find friend functions defined
|
||||
in a class by ADL. This is easily fixed but this example is
|
||||
meant to show the typical way of customising boost::hash, not
|
||||
the portable way.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="hash_global_namespace_test" />
|
||||
<toolset name="borland-*"/>
|
||||
<note author="Daniel James">
|
||||
The test demonstrates a Borland bug - functions that aren't
|
||||
in a namespace don't appear to be found by ADL.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="container_fwd_gcc_debug"/>
|
||||
<toolset name="darwin-4.2"/>
|
||||
<note author="Daniel James">
|
||||
Debug containers aren't supported on Apple's version of gcc 4.2.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
</library>
|
||||
</explicit-failures-markup>
|
||||
21
meta/libraries.json
Normal file
21
meta/libraries.json
Normal file
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"key": "container_hash",
|
||||
"boost-version": "1.33.0",
|
||||
"name": "Container Hash",
|
||||
"authors": [
|
||||
"Daniel James"
|
||||
],
|
||||
"maintainers": [
|
||||
"Peter Dimov <pdimov -at- gmail.com>"
|
||||
],
|
||||
"description": "An STL-compatible hash function object that can be extended to hash user defined types.",
|
||||
"std": [
|
||||
"tr1"
|
||||
],
|
||||
"category": [
|
||||
"Function-objects"
|
||||
],
|
||||
"cxxstd": "11"
|
||||
}
|
||||
]
|
||||
12
test/CMakeLists.txt
Normal file
12
test/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright 2018, 2019, 2021, 2022, 2025 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
|
||||
|
||||
if(HAVE_BOOST_TEST)
|
||||
|
||||
boost_test_jamfile(FILE Jamfile.v2
|
||||
LINK_LIBRARIES Boost::container_hash Boost::core Boost::utility)
|
||||
|
||||
endif()
|
||||
193
test/Jamfile.v2
193
test/Jamfile.v2
@@ -1,78 +1,137 @@
|
||||
|
||||
# Copyright 2005-2011 Daniel James.
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2005-2012 Daniel James.
|
||||
# Copyright 2022, 2025 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
import testing ;
|
||||
|
||||
local gcc-flags = -Wunused-parameter -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wno-variadic-macros ;
|
||||
local clang-flags = $(gcc-flags) -Wno-c99-extensions ;
|
||||
|
||||
project hash-tests
|
||||
: requirements
|
||||
<warnings>all
|
||||
<library>/boost/container_hash//boost_container_hash
|
||||
<library>/boost/core//boost_core
|
||||
<library>/boost/type_traits//boost_type_traits
|
||||
|
||||
<warnings>pedantic
|
||||
<toolset>intel:<warnings>on
|
||||
<toolset>intel:<cxxflags>-strict-ansi
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion"
|
||||
<toolset>gcc:<cxxflags>$(gcc-flags)
|
||||
<toolset>darwin:<cxxflags>$(gcc-flags)
|
||||
<toolset>clang:<cxxflags>$(clang-flags)
|
||||
<toolset>msvc:<warnings-as-errors>on
|
||||
#<toolset>gcc:<warnings-as-errors>on
|
||||
#<toolset>darwin:<warnings-as-errors>on
|
||||
<toolset>gcc:<warnings-as-errors>on
|
||||
<toolset>clang:<warnings-as-errors>on
|
||||
;
|
||||
|
||||
test-suite functional/hash
|
||||
:
|
||||
[ run hash_fwd_test_1.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_fwd_test_2.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_number_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_pointer_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_function_pointer_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_float_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_long_double_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_string_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_range_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_custom_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_global_namespace_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_friend_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_built_in_array_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_value_array_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_vector_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_list_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_deque_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_set_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_map_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_complex_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_type_index_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run link_test.cpp link_test_2.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run link_ext_test.cpp link_no_ext_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run extensions_hpp_test.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ compile-fail hash_no_ext_fail_test.cpp : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ compile-fail namespace_fail_test.cpp : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ compile-fail implicit_fail_test.cpp : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_no_ext_macro_1.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
[ run hash_no_ext_macro_2.cpp : : : <define>BOOST_HASH_NO_IMPLICIT_CASTS ]
|
||||
;
|
||||
|
||||
test-suite functional/hash_implicit_casts
|
||||
:
|
||||
[ run hash_number_test.cpp : : : : implicit_number ]
|
||||
[ run hash_pointer_test.cpp : : : : implicit_pointer ]
|
||||
[ run hash_function_pointer_test.cpp : : : : implicit_function_pointer ]
|
||||
[ run hash_float_test.cpp : : : : implicit_float ]
|
||||
[ run hash_string_test.cpp : : : : implicit_string ]
|
||||
[ run hash_range_test.cpp : : : : implicit_range ]
|
||||
[ run hash_custom_test.cpp : : : : implicit_custom ]
|
||||
[ run hash_built_in_array_test.cpp : : : : implicit_built_in_array ]
|
||||
[ run link_test.cpp link_test_2.cpp : : : : implicit_link ]
|
||||
[ run implicit_fail_test.cpp : : : : implicit_test ]
|
||||
;
|
||||
|
||||
test-suite functional/hash_no_ext
|
||||
:
|
||||
[ run hash_number_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_number_test ]
|
||||
[ run hash_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_pointer_test ]
|
||||
[ run hash_function_pointer_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_function_pointer_test ]
|
||||
[ run hash_float_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_float_test ]
|
||||
[ run hash_long_double_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_long_double_test ]
|
||||
[ run hash_string_test.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_string_test ]
|
||||
[ run link_test.cpp link_test_2.cpp : : : <define>BOOST_HASH_NO_EXTENSIONS : no_ext_link_test ]
|
||||
;
|
||||
run hash_info.cpp : : : <test-info>always_show_run_output ;
|
||||
compile check_float_funcs.cpp ;
|
||||
run hash_fwd_test_1.cpp ;
|
||||
run hash_fwd_test_2.cpp ;
|
||||
run hash_number_test.cpp ;
|
||||
run hash_enum_test.cpp ;
|
||||
run hash_pointer_test.cpp ;
|
||||
run hash_function_pointer_test.cpp ;
|
||||
run hash_float_test.cpp ;
|
||||
run hash_long_double_test.cpp ;
|
||||
run hash_string_test.cpp ;
|
||||
run hash_range_test.cpp ;
|
||||
run hash_custom_test.cpp ;
|
||||
run hash_global_namespace_test.cpp ;
|
||||
run hash_friend_test.cpp ;
|
||||
run hash_built_in_array_test.cpp ;
|
||||
run hash_value_array_test.cpp ;
|
||||
run hash_vector_test.cpp ;
|
||||
run hash_list_test.cpp ;
|
||||
run hash_deque_test.cpp ;
|
||||
run hash_set_test.cpp ;
|
||||
run hash_map_test.cpp ;
|
||||
run hash_complex_test.cpp ;
|
||||
run hash_optional_test.cpp ;
|
||||
run hash_variant_test.cpp ;
|
||||
run hash_type_index_test.cpp ;
|
||||
run hash_system_error_test.cpp ;
|
||||
run hash_std_array_test.cpp ;
|
||||
run hash_std_tuple_test.cpp ;
|
||||
run hash_std_smart_ptr_test.cpp ;
|
||||
run link_test.cpp link_test_2.cpp ;
|
||||
run link_ext_test.cpp link_no_ext_test.cpp ;
|
||||
run extensions_hpp_test.cpp ;
|
||||
compile-fail namespace_fail_test.cpp ;
|
||||
run implicit_test.cpp ;
|
||||
run hash_no_ext_macro_1.cpp ;
|
||||
run hash_no_ext_macro_2.cpp ;
|
||||
|
||||
build-project ../examples ;
|
||||
|
||||
run hash_reference_values.cpp ;
|
||||
|
||||
run is_range_test.cpp ;
|
||||
run is_contiguous_range_test.cpp ;
|
||||
run is_unordered_range_test.cpp ;
|
||||
|
||||
run hash_forward_list_test.cpp ;
|
||||
|
||||
run quick.cpp ;
|
||||
|
||||
run hash_number_test2.cpp ;
|
||||
run hash_integral_test.cpp ;
|
||||
run hash_string_test2.cpp
|
||||
/boost/utility//boost_utility ;
|
||||
|
||||
# for gcc-4.8
|
||||
local fs-path-req = <library>/boost/filesystem//boost_filesystem/<warnings>off "-<toolset>gcc:<cxxflags>-Wshadow" "-<toolset>gcc:<cxxflags>-Wconversion" <toolset>gcc-4.7:<build>no <undefined-sanitizer>norecover:<link>static ;
|
||||
|
||||
run hash_fs_path_test.cpp : : : $(fs-path-req) <toolset>msvc-14.0,<cxxstd>latest:<build>no ;
|
||||
|
||||
run is_range_test2.cpp : : : $(fs-path-req) ;
|
||||
|
||||
run hash_container_test.cpp ;
|
||||
|
||||
run hash_vector_test2.cpp ;
|
||||
|
||||
run hash_string_test3.cpp ;
|
||||
run hash_string_test4.cpp ;
|
||||
|
||||
run hash_multiset_test.cpp ;
|
||||
run hash_multimap_test.cpp ;
|
||||
|
||||
run hash_unordered_range_test.cpp ;
|
||||
|
||||
run hash_unordered_multiset_test.cpp ;
|
||||
run hash_unordered_multimap_test.cpp ;
|
||||
|
||||
run hash_unordered_set_test.cpp ;
|
||||
run hash_unordered_map_test.cpp ;
|
||||
|
||||
run is_range_test3.cpp ;
|
||||
run is_contiguous_range_test2.cpp ;
|
||||
run is_unordered_range_test2.cpp ;
|
||||
run is_contiguous_range_test3.cpp ;
|
||||
|
||||
run is_described_class_test.cpp
|
||||
: : : <warnings>extra ;
|
||||
run is_described_class_test2.cpp
|
||||
: : : <warnings>extra ;
|
||||
run is_described_class_test3.cpp
|
||||
: : : <warnings>extra ;
|
||||
|
||||
run described_class_test.cpp
|
||||
: : : <warnings>extra ;
|
||||
|
||||
run hash_is_avalanching_test.cpp ;
|
||||
run hash_is_avalanching_test2.cpp ;
|
||||
run hash_is_avalanching_test3.cpp ;
|
||||
|
||||
run hash_integral_test2.cpp ;
|
||||
|
||||
run hash_nullptr_test.cpp ;
|
||||
|
||||
run is_tuple_like_test.cpp ;
|
||||
|
||||
run hash_tuple_like_test.cpp ;
|
||||
run hash_tuple_like_test2.cpp
|
||||
: : : <warnings>extra ;
|
||||
|
||||
run is_range_test4.cpp ;
|
||||
run hash_container_test2.cpp ;
|
||||
|
||||
63
test/check_float_funcs.cpp
Normal file
63
test/check_float_funcs.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
// Copyright 2012 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// in type_traits/is_complete.hpp:47
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class T1>
|
||||
struct check_return_type
|
||||
{
|
||||
template <class T2>
|
||||
static void equals(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
static void equals_ref(T2&)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
static void convertible(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int main() {
|
||||
float f = 0;
|
||||
double d = 0;
|
||||
long double l = 0;
|
||||
|
||||
test::check_return_type<float>::equals(std::ldexp(f, 0));
|
||||
test::check_return_type<double>::equals(std::ldexp(d, 0));
|
||||
test::check_return_type<long double>::equals(std::ldexp(l, 0));
|
||||
|
||||
int dummy = 0;
|
||||
|
||||
test::check_return_type<float>::equals(std::frexp(f, &dummy));
|
||||
test::check_return_type<double>::equals(std::frexp(d, &dummy));
|
||||
test::check_return_type<long double>::equals(std::frexp(l, &dummy));
|
||||
|
||||
#if BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
int (*fpc1)(float) = std::fpclassify;
|
||||
int (*fpc2)(double) = std::fpclassify;
|
||||
int (*fpc3)(long double) = std::fpclassify;
|
||||
|
||||
#endif
|
||||
}
|
||||
17
test/cmake_install_test/CMakeLists.txt
Normal file
17
test/cmake_install_test/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2018, 2019, 2021 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.20)
|
||||
|
||||
project(cmake_install_test LANGUAGES CXX)
|
||||
|
||||
find_package(boost_container_hash REQUIRED)
|
||||
|
||||
add_executable(quick ../quick.cpp)
|
||||
target_link_libraries(quick Boost::container_hash)
|
||||
|
||||
enable_testing()
|
||||
add_test(quick quick)
|
||||
|
||||
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
|
||||
21
test/cmake_subdir_test/CMakeLists.txt
Normal file
21
test/cmake_subdir_test/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright 2018, 2019, 2021 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.20)
|
||||
|
||||
project(cmake_subdir_test LANGUAGES CXX)
|
||||
|
||||
add_subdirectory(../.. boostorg/container_hash)
|
||||
|
||||
add_subdirectory(../../../config boostorg/config)
|
||||
add_subdirectory(../../../describe boostorg/describe)
|
||||
add_subdirectory(../../../mp11 boostorg/mp11)
|
||||
|
||||
add_executable(quick ../quick.cpp)
|
||||
target_link_libraries(quick Boost::container_hash)
|
||||
|
||||
enable_testing()
|
||||
add_test(quick quick)
|
||||
|
||||
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
|
||||
@@ -5,12 +5,16 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_base_and_derived.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
template <class T>
|
||||
void compile_time_tests(T*)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_base_and_derived<
|
||||
std::unary_function<T, std::size_t>, HASH_NAMESPACE::hash<T> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T,
|
||||
typename BOOST_HASH_TEST_NAMESPACE::hash<T>::argument_type
|
||||
>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<std::size_t,
|
||||
typename BOOST_HASH_TEST_NAMESPACE::hash<T>::result_type
|
||||
>::value));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if defined(TEST_STD)
|
||||
# define TEST_STD_INCLUDES
|
||||
# define HASH_NAMESPACE std
|
||||
#if defined(BOOST_HASH_TEST_STD)
|
||||
# define BOOST_HASH_TEST_STD_INCLUDES
|
||||
# define BOOST_HASH_TEST_NAMESPACE std
|
||||
#else
|
||||
# define HASH_NAMESPACE boost
|
||||
# define BOOST_HASH_TEST_NAMESPACE boost
|
||||
# if !defined(BOOST_HASH_NO_EXTENSIONS)
|
||||
# define TEST_EXTENSIONS
|
||||
# define BOOST_HASH_TEST_EXTENSIONS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -18,4 +18,8 @@
|
||||
// before doing anything else.
|
||||
#pragma warning(disable:4201) // nonstandard extension used :
|
||||
// nameless struct/union
|
||||
|
||||
#endif
|
||||
|
||||
#define HASH_TEST_CAT(x, y) HASH_TEST_CAT2(x, y)
|
||||
#define HASH_TEST_CAT2(x, y) x##y
|
||||
|
||||
159
test/described_class_test.cpp
Normal file
159
test/described_class_test.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wunused-private-field"
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/describe/class.hpp>
|
||||
#include <boost/describe/operators.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
|
||||
#if !defined(BOOST_DESCRIBE_CXX14)
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Skipping test because BOOST_DESCRIBE_CXX14 is not defined" )
|
||||
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
struct X1
|
||||
{
|
||||
int m;
|
||||
explicit X1( int m_ ): m( m_ ) {}
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( X1, (), (m) )
|
||||
|
||||
struct X2
|
||||
{
|
||||
int m;
|
||||
explicit X2( int m_ ): m( m_ ) {}
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( X2, (), (m) )
|
||||
|
||||
struct X3
|
||||
{
|
||||
int m;
|
||||
explicit X3( int m_ ): m( m_ ) {}
|
||||
};
|
||||
|
||||
BOOST_DESCRIBE_STRUCT( X3, (), (m) )
|
||||
|
||||
class Y: public X1, protected X2, private X3
|
||||
{
|
||||
public:
|
||||
|
||||
int m1;
|
||||
|
||||
protected:
|
||||
|
||||
int m2;
|
||||
|
||||
private:
|
||||
|
||||
int m3;
|
||||
|
||||
public:
|
||||
|
||||
Y( int x1, int x2, int x3, int m1_, int m2_, int m3_ ):
|
||||
X1( x1 ), X2( x2 ), X3( x3 ), m1( m1_ ), m2( m2_ ), m3( m3_ ) {}
|
||||
|
||||
BOOST_DESCRIBE_CLASS( Y, (X1, X2, X3), (m1), (m2), (m3) )
|
||||
};
|
||||
|
||||
using boost::describe::operators::operator==;
|
||||
using boost::describe::operators::operator!=;
|
||||
using boost::describe::operators::operator<<;
|
||||
|
||||
int main()
|
||||
{
|
||||
Y y1( 0, 0, 0, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_EQ( y1, y1 );
|
||||
BOOST_TEST_EQ( boost::hash<Y>()(y1), boost::hash<Y>()(y1) );
|
||||
|
||||
Y y2( 1, 0, 0, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y2 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y2) );
|
||||
|
||||
Y y3( 0, 1, 0, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y3 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y3) );
|
||||
|
||||
BOOST_TEST_NE( y2, y3 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y3) );
|
||||
|
||||
Y y4( 0, 0, 1, 0, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y4 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y4) );
|
||||
|
||||
BOOST_TEST_NE( y2, y4 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y4) );
|
||||
|
||||
BOOST_TEST_NE( y3, y4 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y4) );
|
||||
|
||||
Y y5( 0, 0, 0, 1, 0, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y5) );
|
||||
|
||||
BOOST_TEST_NE( y2, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y5) );
|
||||
|
||||
BOOST_TEST_NE( y3, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y5) );
|
||||
|
||||
BOOST_TEST_NE( y4, y5 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y5) );
|
||||
|
||||
Y y6( 0, 0, 0, 0, 1, 0 );
|
||||
|
||||
BOOST_TEST_NE( y1, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y2, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y3, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y4, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y6) );
|
||||
|
||||
BOOST_TEST_NE( y5, y6 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y5), boost::hash<Y>()(y6) );
|
||||
|
||||
Y y7( 0, 0, 0, 0, 0, 1 );
|
||||
|
||||
BOOST_TEST_NE( y1, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y1), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y2, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y2), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y3, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y3), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y4, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y4), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y5, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y5), boost::hash<Y>()(y7) );
|
||||
|
||||
BOOST_TEST_NE( y6, y7 );
|
||||
BOOST_TEST_NE( boost::hash<Y>()(y6), boost::hash<Y>()(y7) );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,14 +3,14 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Check that boost/functional/hash/extensions.hpp works okay.
|
||||
// Check that boost/container_hash/extensions.hpp works okay.
|
||||
//
|
||||
// It probably should be in boost/functional/hash/detail, but since it isn't it
|
||||
// It probably should be in boost/container_hash/detail, but since it isn't it
|
||||
// should work.
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#include <boost/functional/hash/extensions.hpp>
|
||||
#include <boost/container_hash/extensions.hpp>
|
||||
|
||||
int main() {
|
||||
int x[2] = { 2, 3 };
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
# ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
# ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
# else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
void array_int_test()
|
||||
{
|
||||
@@ -27,47 +27,47 @@ void array_int_test()
|
||||
8, -12, 23, 65, 45,
|
||||
-1, 93, -54, 987, 3
|
||||
};
|
||||
HASH_NAMESPACE::hash<int[25]> hasher1;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<int[25]> hasher1;
|
||||
|
||||
const int length2 = 1;
|
||||
int array2[1] = {3};
|
||||
HASH_NAMESPACE::hash<int[1]> hasher2;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<int[1]> hasher2;
|
||||
|
||||
const int length3 = 2;
|
||||
int array3[2] = {2, 3};
|
||||
HASH_NAMESPACE::hash<int[2]> hasher3;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<int[2]> hasher3;
|
||||
|
||||
BOOST_TEST(hasher1(array1)
|
||||
== HASH_NAMESPACE::hash_range(array1, array1 + length1));
|
||||
== BOOST_HASH_TEST_NAMESPACE::hash_range(array1, array1 + length1));
|
||||
BOOST_TEST(hasher2(array2)
|
||||
== HASH_NAMESPACE::hash_range(array2, array2 + length2));
|
||||
== BOOST_HASH_TEST_NAMESPACE::hash_range(array2, array2 + length2));
|
||||
BOOST_TEST(hasher3(array3)
|
||||
== HASH_NAMESPACE::hash_range(array3, array3 + length3));
|
||||
== BOOST_HASH_TEST_NAMESPACE::hash_range(array3, array3 + length3));
|
||||
}
|
||||
|
||||
void two_dimensional_array_test()
|
||||
{
|
||||
int array[3][2] = {{-5, 6}, {7, -3}, {26, 1}};
|
||||
HASH_NAMESPACE::hash<int[3][2]> hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<int[3][2]> hasher;
|
||||
|
||||
std::size_t seed1 = 0;
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
std::size_t seed2 = 0;
|
||||
for(int j = 0; j < 2; ++j)
|
||||
HASH_NAMESPACE::hash_combine(seed2, array[i][j]);
|
||||
HASH_NAMESPACE::hash_combine(seed1, seed2);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, array[i][j]);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, seed2);
|
||||
}
|
||||
|
||||
BOOST_TEST(hasher(array) == seed1);
|
||||
BOOST_TEST(hasher(array) == HASH_NAMESPACE::hash_range(array, array + 3));
|
||||
BOOST_TEST(hasher(array) == BOOST_HASH_TEST_NAMESPACE::hash_range(array, array + 3));
|
||||
}
|
||||
|
||||
#endif // TEST_EXTENSIONS
|
||||
#endif // BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
array_int_test();
|
||||
two_dimensional_array_test();
|
||||
#endif
|
||||
|
||||
@@ -3,21 +3,23 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#if !defined(TEST_EXTENSIONS)
|
||||
#if !defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
#else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4244) // conversion from 'unsigned long' to
|
||||
@@ -29,24 +31,30 @@ int main() {}
|
||||
// 'const std::complex<float>::_Ty'
|
||||
#pragma warning(disable:4309) // truncation of constant value
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
#pragma warning(disable:4996) // std::complex<Integer> is deprecated
|
||||
#if BOOST_MSVC < 1400
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ( defined(__GNUC__) || defined(__clang__) ) && !defined(BOOST_INTEL_CXX_VERSION)
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#include <boost/limits.hpp>
|
||||
#include <complex>
|
||||
#include <sstream>
|
||||
#include <boost/limits.hpp>
|
||||
#include <set>
|
||||
|
||||
template <class T>
|
||||
void generic_complex_tests(std::complex<T> v)
|
||||
{
|
||||
HASH_NAMESPACE::hash<std::complex<T> > complex_hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<std::complex<T> > complex_hasher;
|
||||
|
||||
BOOST_TEST(complex_hasher(v) == complex_hasher(v));
|
||||
|
||||
HASH_NAMESPACE::hash<T> real_hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<T> real_hasher;
|
||||
T real = v.real();
|
||||
T imag = v.imag();
|
||||
|
||||
@@ -80,8 +88,23 @@ void complex_integral_tests(Integer*)
|
||||
generic_complex_tests(complex(15342,124));
|
||||
generic_complex_tests(complex(25,54356));
|
||||
generic_complex_tests(complex(5325,2346));
|
||||
generic_complex_tests(complex(-243897,-49923874));
|
||||
generic_complex_tests(complex(-543,763));
|
||||
generic_complex_tests(complex(Integer(-243897),Integer(-49923874)));
|
||||
generic_complex_tests(complex(Integer(-543),Integer(763)));
|
||||
}
|
||||
|
||||
template<class T> void complex_grid_test( short N )
|
||||
{
|
||||
std::set<std::size_t> hashes;
|
||||
|
||||
for( short i = 0; i < N; ++i )
|
||||
{
|
||||
for( short j = 0; j < N; ++j )
|
||||
{
|
||||
hashes.insert( boost::hash< std::complex<T> >()( std::complex<T>( i, j ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ( hashes.size(), static_cast<std::size_t>( N * N ) );
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -100,7 +123,12 @@ int main()
|
||||
complex_integral_tests((unsigned int*) 0);
|
||||
complex_integral_tests((unsigned long*) 0);
|
||||
|
||||
complex_grid_test<int>( 16 );
|
||||
complex_grid_test<float>( 16 );
|
||||
complex_grid_test<double>( 16 );
|
||||
complex_grid_test<long double>( 16 );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif // TEST_EXTENSIONS
|
||||
#endif // BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
60
test/hash_container_test.cpp
Normal file
60
test/hash_container_test.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
|
||||
# include <forward_list>
|
||||
#endif
|
||||
|
||||
template<class T> std::size_t hv( T const& t )
|
||||
{
|
||||
return boost::hash<T>()( t );
|
||||
}
|
||||
|
||||
template<class T> void test()
|
||||
{
|
||||
for( std::size_t i = 0; i < 8; ++i )
|
||||
{
|
||||
std::vector<T> v( i );
|
||||
std::size_t h0 = hv( v );
|
||||
|
||||
std::deque<T> d( v.begin(), v.end() );
|
||||
BOOST_TEST_EQ( h0, hv( d ) );
|
||||
|
||||
std::list<T> l( v.begin(), v.end() );
|
||||
BOOST_TEST_EQ( h0, hv( l ) );
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
|
||||
|
||||
std::forward_list<T> f( v.begin(), v.end() );
|
||||
BOOST_TEST_EQ( h0, hv( f ) );
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test<char>();
|
||||
test<unsigned char>();
|
||||
test<signed char>();
|
||||
test<int>();
|
||||
test<float>();
|
||||
test<double>();
|
||||
|
||||
#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
|
||||
test<char8_t>();
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L
|
||||
test<std::byte>();
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
39
test/hash_container_test2.cpp
Normal file
39
test/hash_container_test2.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2024 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct X1
|
||||
{
|
||||
void* begin() const { return nullptr; }
|
||||
void* end() const { return nullptr; }
|
||||
};
|
||||
|
||||
std::size_t hash_value( X1 const& )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct X2
|
||||
{
|
||||
void const* begin() const { return nullptr; }
|
||||
void const* end() const { return nullptr; }
|
||||
};
|
||||
|
||||
std::size_t hash_value( X2 const& )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
X1 x1;
|
||||
BOOST_TEST_EQ( boost::hash<X1>()( x1 ), 1u );
|
||||
|
||||
X2 x2;
|
||||
BOOST_TEST_EQ( boost::hash<X2>()( x2 ), 2u );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace test
|
||||
|
||||
std::size_t hash() const
|
||||
{
|
||||
return value_ * 10;
|
||||
return static_cast<std::size_t>(value_ * 10);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
@@ -41,17 +41,17 @@ namespace boost
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
# ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
# ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
# else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -59,13 +59,13 @@ namespace boost
|
||||
|
||||
void custom_tests()
|
||||
{
|
||||
HASH_NAMESPACE::hash<test::custom> custom_hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::custom> custom_hasher;
|
||||
BOOST_TEST(custom_hasher(10) == 100u);
|
||||
test::custom x(55);
|
||||
BOOST_TEST(custom_hasher(x) == 550u);
|
||||
|
||||
{
|
||||
using namespace HASH_NAMESPACE;
|
||||
using namespace BOOST_HASH_TEST_NAMESPACE;
|
||||
BOOST_TEST(custom_hasher(x) == hash_value(x));
|
||||
}
|
||||
|
||||
@@ -75,25 +75,25 @@ void custom_tests()
|
||||
custom_vector.push_back(35);
|
||||
|
||||
std::size_t seed = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed, test::custom(5));
|
||||
HASH_NAMESPACE::hash_combine(seed, test::custom(25));
|
||||
HASH_NAMESPACE::hash_combine(seed, test::custom(35));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(5));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(25));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom(35));
|
||||
|
||||
std::size_t seed2 = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed2, 50u);
|
||||
HASH_NAMESPACE::hash_combine(seed2, 250u);
|
||||
HASH_NAMESPACE::hash_combine(seed2, 350u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
|
||||
|
||||
BOOST_TEST(seed == HASH_NAMESPACE::hash_range(
|
||||
BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
|
||||
custom_vector.begin(), custom_vector.end()));
|
||||
BOOST_TEST(seed == seed2);
|
||||
}
|
||||
|
||||
#endif // TEST_EXTENSIONS
|
||||
#endif // BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
custom_tests();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
# ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
# ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
# else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
#include <deque>
|
||||
|
||||
@@ -23,11 +23,11 @@ using std::deque;
|
||||
#define CONTAINER_TYPE deque
|
||||
#include "./hash_sequence_test.hpp"
|
||||
|
||||
#endif // TEST_EXTENSIONS
|
||||
#endif // BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
deque_tests::deque_hash_integer_tests();
|
||||
#endif
|
||||
|
||||
|
||||
63
test/hash_enum_test.cpp
Normal file
63
test/hash_enum_test.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
// Copyright 2012 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
#else
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "./compile_time.hpp"
|
||||
|
||||
namespace test {
|
||||
enum enum_override { enum_override1, enum_override2 };
|
||||
std::size_t hash_value(enum_override) { return 896532; }
|
||||
|
||||
enum enum1 { enum1a };
|
||||
enum enum2 { enum2a, enum2b };
|
||||
enum enum3 { enum3a = 574, enum3b };
|
||||
enum enum4 { enum4a = -12574, enum4b };
|
||||
}
|
||||
|
||||
int main() {
|
||||
compile_time_tests((test::enum1*) 0);
|
||||
compile_time_tests((test::enum2*) 0);
|
||||
compile_time_tests((test::enum3*) 0);
|
||||
compile_time_tests((test::enum4*) 0);
|
||||
compile_time_tests((test::enum_override*) 0);
|
||||
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::enum1> hash1;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::enum2> hash2;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::enum3> hash3;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::enum4> hash4;
|
||||
|
||||
BOOST_TEST(hash1(test::enum1a) == hash1(test::enum1a));
|
||||
|
||||
BOOST_TEST(hash2(test::enum2a) == hash2(test::enum2a));
|
||||
BOOST_TEST(hash2(test::enum2a) != hash2(test::enum2b));
|
||||
BOOST_TEST(hash2(test::enum2b) == hash2(test::enum2b));
|
||||
|
||||
BOOST_TEST(hash3(test::enum3a) == hash3(test::enum3a));
|
||||
BOOST_TEST(hash3(test::enum3a) != hash3(test::enum3b));
|
||||
BOOST_TEST(hash3(test::enum3b) == hash3(test::enum3b));
|
||||
|
||||
BOOST_TEST(hash4(test::enum4a) == hash4(test::enum4a));
|
||||
BOOST_TEST(hash4(test::enum4a) != hash4(test::enum4b));
|
||||
BOOST_TEST(hash4(test::enum4b) == hash4(test::enum4b));
|
||||
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::enum_override> hash_override;
|
||||
|
||||
BOOST_TEST(hash_override(test::enum_override1) ==
|
||||
hash_override(test::enum_override1));
|
||||
BOOST_TEST(hash_override(test::enum_override1) ==
|
||||
hash_override(test::enum_override2));
|
||||
BOOST_TEST(hash_override(test::enum_override1) ==
|
||||
hash_override(test::enum_override1));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define _SILENCE_CXX23_DENORM_DEPRECATION_WARNING
|
||||
|
||||
#include "hash_float_test.hpp"
|
||||
|
||||
int main()
|
||||
|
||||
@@ -5,18 +5,17 @@
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
#else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <boost/functional/hash/detail/limits.hpp>
|
||||
#include <boost/functional/hash/detail/float_functions.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/container_hash/detail/limits.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -30,6 +29,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ( defined(__GNUC__) || defined(__clang__) ) && !defined(BOOST_INTEL_CXX_VERSION)
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
// P2614 deprecates has_denorm in C++23
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
char const* float_type(float*) { return "float"; }
|
||||
char const* float_type(double*) { return "double"; }
|
||||
char const* float_type(long double*) { return "long double"; }
|
||||
@@ -39,7 +47,7 @@ void float_tests(char const* name, T* = 0)
|
||||
{
|
||||
std::cerr
|
||||
<< "\n"
|
||||
<< "Testing " BOOST_STRINGIZE(HASH_NAMESPACE) "::hash<"
|
||||
<< "Testing " BOOST_STRINGIZE(BOOST_HASH_TEST_NAMESPACE) "::hash<"
|
||||
<< name
|
||||
<< ">\n"
|
||||
<< "\n"
|
||||
@@ -51,22 +59,9 @@ void float_tests(char const* name, T* = 0)
|
||||
<< boost::hash_detail::limits<std::size_t>::digits
|
||||
<< "\n"
|
||||
<< "\n"
|
||||
<< "boost::hash_detail::call_ldexp<T>::float_type = "
|
||||
<< float_type(static_cast<BOOST_DEDUCED_TYPENAME
|
||||
boost::hash_detail::call_ldexp<T>::float_type*>(0))
|
||||
<< "\n"
|
||||
<< "boost::hash_detail::call_frexp<T>::float_type = "
|
||||
<< float_type(static_cast<BOOST_DEDUCED_TYPENAME
|
||||
boost::hash_detail::call_frexp<T>::float_type*>(0))
|
||||
<< "\n"
|
||||
<< "boost::hash_detail::select_hash_type<T>::type = "
|
||||
<< float_type(static_cast<BOOST_DEDUCED_TYPENAME
|
||||
boost::hash_detail::select_hash_type<T>::type*>(0))
|
||||
<< "\n"
|
||||
<< "\n"
|
||||
;
|
||||
|
||||
HASH_NAMESPACE::hash<T> x1;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<T> x1;
|
||||
|
||||
T zero = 0;
|
||||
T minus_zero = (T) -1 * zero;
|
||||
@@ -74,9 +69,9 @@ void float_tests(char const* name, T* = 0)
|
||||
BOOST_TEST(zero == minus_zero);
|
||||
BOOST_TEST(x1(zero) == x1(minus_zero));
|
||||
|
||||
#if defined(TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(zero) == HASH_NAMESPACE::hash_value(zero));
|
||||
BOOST_TEST(x1(minus_zero) == HASH_NAMESPACE::hash_value(minus_zero));
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(zero));
|
||||
BOOST_TEST(x1(minus_zero) == BOOST_HASH_TEST_NAMESPACE::hash_value(minus_zero));
|
||||
#endif
|
||||
|
||||
BOOST_TEST(x1(zero) != x1(0.5));
|
||||
@@ -87,7 +82,7 @@ void float_tests(char const* name, T* = 0)
|
||||
using namespace std;
|
||||
|
||||
// Doing anything with infinity causes borland to crash.
|
||||
#if defined(__BORLANDC__)
|
||||
#if defined(BOOST_BORLANDC)
|
||||
std::cerr
|
||||
<< "Not running infinity checks on Borland, as it causes it to crash."
|
||||
"\n";
|
||||
@@ -102,10 +97,10 @@ void float_tests(char const* name, T* = 0)
|
||||
T minus_infinity2 = (T) -1. / zero;
|
||||
T minus_infinity3 = (T) 1. / minus_zero;
|
||||
|
||||
#if defined(TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(infinity) == HASH_NAMESPACE::hash_value(infinity));
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(infinity) == BOOST_HASH_TEST_NAMESPACE::hash_value(infinity));
|
||||
BOOST_TEST(x1(minus_infinity)
|
||||
== HASH_NAMESPACE::hash_value(minus_infinity));
|
||||
== BOOST_HASH_TEST_NAMESPACE::hash_value(minus_infinity));
|
||||
#endif
|
||||
|
||||
if(infinity == infinity2)
|
||||
@@ -187,12 +182,12 @@ void float_tests(char const* name, T* = 0)
|
||||
BOOST_TEST(three_quarter_max != -three_quarter_max);
|
||||
|
||||
|
||||
#if defined(TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(max) == HASH_NAMESPACE::hash_value(max));
|
||||
BOOST_TEST(x1(half_max) == HASH_NAMESPACE::hash_value(half_max));
|
||||
BOOST_TEST(x1(quarter_max) == HASH_NAMESPACE::hash_value(quarter_max));
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(max) == BOOST_HASH_TEST_NAMESPACE::hash_value(max));
|
||||
BOOST_TEST(x1(half_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(half_max));
|
||||
BOOST_TEST(x1(quarter_max) == BOOST_HASH_TEST_NAMESPACE::hash_value(quarter_max));
|
||||
BOOST_TEST(x1(three_quarter_max) ==
|
||||
HASH_NAMESPACE::hash_value(three_quarter_max));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_value(three_quarter_max));
|
||||
#endif
|
||||
|
||||
// The '!=' tests could legitimately fail, but with my hash it indicates a
|
||||
@@ -223,16 +218,16 @@ void float_tests(char const* name, T* = 0)
|
||||
if(v1 == v2)
|
||||
BOOST_TEST(x1(v1) == x1(v2));
|
||||
|
||||
#if defined(TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(v1) == HASH_NAMESPACE::hash_value(v1));
|
||||
BOOST_TEST(x1(v2) == HASH_NAMESPACE::hash_value(v2));
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(v1) == BOOST_HASH_TEST_NAMESPACE::hash_value(v1));
|
||||
BOOST_TEST(x1(v2) == BOOST_HASH_TEST_NAMESPACE::hash_value(v2));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(TEST_EXTENSIONS)
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
BOOST_TEST(x1(boost::hash_detail::limits<T>::epsilon()) ==
|
||||
HASH_NAMESPACE::hash_value(
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_value(
|
||||
boost::hash_detail::limits<T>::epsilon()));
|
||||
#endif
|
||||
|
||||
@@ -265,12 +260,12 @@ void float_tests(char const* name, T* = 0)
|
||||
if(x1(boost::hash_detail::limits<T>::denorm_min()) == x1(zero)) {
|
||||
std::cerr<<"x1(denorm_min) == x1(zero) == "<<x1(zero)<<"\n";
|
||||
}
|
||||
#if !BOOST_WORKAROUND(__DECCXX_VER,<70190006) && defined(TEST_EXTENSIONS)
|
||||
#if !BOOST_WORKAROUND(__DECCXX_VER,<70190006) && defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
// The Tru64/CXX standard library prior to 7.1 contains a bug in the
|
||||
// specialization of boost::hash_detail::limits::denorm_min() for long
|
||||
// doubles which causes this test to fail.
|
||||
if(x1(boost::hash_detail::limits<T>::denorm_min()) !=
|
||||
HASH_NAMESPACE::hash_value(
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_value(
|
||||
boost::hash_detail::limits<T>::denorm_min()))
|
||||
{
|
||||
std::cerr
|
||||
@@ -278,7 +273,7 @@ void float_tests(char const* name, T* = 0)
|
||||
<< x1(boost::hash_detail::limits<T>::denorm_min())
|
||||
<< "\nhash_value(boost::hash_detail::limits<T>::denorm_min())"
|
||||
" = "
|
||||
<< HASH_NAMESPACE::hash_value(
|
||||
<< BOOST_HASH_TEST_NAMESPACE::hash_value(
|
||||
boost::hash_detail::limits<T>::denorm_min())
|
||||
<< "\nx1(0) = "
|
||||
<< x1(0)
|
||||
@@ -288,13 +283,13 @@ void float_tests(char const* name, T* = 0)
|
||||
}
|
||||
|
||||
// NaN also causes borland to crash.
|
||||
#if !defined(__BORLANDC__) && defined(TEST_EXTENSIONS)
|
||||
#if !defined(BOOST_BORLANDC) && defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
if(boost::hash_detail::limits<T>::has_quiet_NaN) {
|
||||
if(x1(boost::hash_detail::limits<T>::quiet_NaN()) == x1(1.0)) {
|
||||
std::cerr<<"x1(quiet_NaN) == x1(1.0) == "<<x1(1.0)<<"\n";
|
||||
}
|
||||
BOOST_TEST(x1(boost::hash_detail::limits<T>::quiet_NaN()) ==
|
||||
HASH_NAMESPACE::hash_value(
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_value(
|
||||
boost::hash_detail::limits<T>::quiet_NaN()));
|
||||
}
|
||||
#endif
|
||||
|
||||
59
test/hash_forward_list_test.cpp
Normal file
59
test/hash_forward_list_test.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 8
|
||||
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_HDR_FORWARD_LIST)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE( "Test skipped, BOOST_NO_CXX11_HDR_FORWARD_LIST is defined" )
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include <forward_list>
|
||||
|
||||
template<class T> void test()
|
||||
{
|
||||
typedef std::forward_list<T> list;
|
||||
typedef boost::hash<list> hash;
|
||||
|
||||
int const N = 32;
|
||||
|
||||
std::size_t h[ N ];
|
||||
|
||||
list v;
|
||||
|
||||
for( int i = 0; i < N; ++i )
|
||||
{
|
||||
h[ i ] = hash()( v );
|
||||
|
||||
BOOST_TEST_EQ( h[ i ], hash()( v ) );
|
||||
|
||||
for( int j = 0; j < i; ++j )
|
||||
{
|
||||
BOOST_TEST_NE( h[ j ], h[ i ] );
|
||||
}
|
||||
|
||||
v.push_front( T() );
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test<int>();
|
||||
test<float>();
|
||||
test<double>();
|
||||
test< std::forward_list<int> >();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,7 +17,7 @@ namespace test
|
||||
|
||||
std::size_t hash() const
|
||||
{
|
||||
return value_ * 10;
|
||||
return static_cast<std::size_t>(value_ * 10);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
@@ -44,17 +44,17 @@ namespace boost
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
# ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
# ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
# else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -62,13 +62,13 @@ namespace boost
|
||||
|
||||
void custom_tests()
|
||||
{
|
||||
HASH_NAMESPACE::hash<test::custom<int> > custom_hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::custom<int> > custom_hasher;
|
||||
BOOST_TEST(custom_hasher(10) == 100u);
|
||||
test::custom<int> x(55);
|
||||
BOOST_TEST(custom_hasher(x) == 550u);
|
||||
|
||||
{
|
||||
using namespace HASH_NAMESPACE;
|
||||
using namespace BOOST_HASH_TEST_NAMESPACE;
|
||||
BOOST_TEST(custom_hasher(x) == hash_value(x));
|
||||
}
|
||||
|
||||
@@ -78,25 +78,25 @@ void custom_tests()
|
||||
custom_vector.push_back(35);
|
||||
|
||||
std::size_t seed = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed, test::custom<int>(5));
|
||||
HASH_NAMESPACE::hash_combine(seed, test::custom<int>(25));
|
||||
HASH_NAMESPACE::hash_combine(seed, test::custom<int>(35));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(5));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(25));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, test::custom<int>(35));
|
||||
|
||||
std::size_t seed2 = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed2, 50u);
|
||||
HASH_NAMESPACE::hash_combine(seed2, 250u);
|
||||
HASH_NAMESPACE::hash_combine(seed2, 350u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
|
||||
|
||||
BOOST_TEST(seed == HASH_NAMESPACE::hash_range(
|
||||
BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
|
||||
custom_vector.begin(), custom_vector.end()));
|
||||
BOOST_TEST(seed == seed2);
|
||||
}
|
||||
|
||||
#endif // TEST_EXTENSIONS
|
||||
#endif // BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
custom_tests();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
|
||||
30
test/hash_fs_path_test.cpp
Normal file
30
test/hash_fs_path_test.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(disable: 4714) // forceinline not inlined
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
template<class T> std::size_t hv( T const& t )
|
||||
{
|
||||
return boost::hash<T>()( t );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::filesystem::path p1( "/foo/bar" );
|
||||
boost::filesystem::path p2( "/foo/baz" );
|
||||
|
||||
BOOST_TEST_NE( hv( p1 ), hv( p2 ) );
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -5,21 +5,17 @@
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
#else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
#include <boost/mpl/assert.hpp>
|
||||
#include <boost/type_traits/is_base_and_derived.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "./compile_time.hpp"
|
||||
|
||||
void void_func1() { static int x = 1; ++x; }
|
||||
void void_func2() { static int x = 2; --x; }
|
||||
void void_func1() { static int x = 1; ++x; (void)x; }
|
||||
void void_func2() { static int x = 2; --x; (void)x; }
|
||||
int int_func1(int) { return 0; }
|
||||
int int_func2(int) { return 1; }
|
||||
|
||||
@@ -28,8 +24,8 @@ void function_pointer_tests()
|
||||
compile_time_tests((void(**)()) 0);
|
||||
compile_time_tests((int(**)(int)) 0);
|
||||
|
||||
HASH_NAMESPACE::hash<void(*)()> hasher_void;
|
||||
HASH_NAMESPACE::hash<int(*)(int)> hasher_int;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<void(*)()> hasher_void;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<int(*)(int)> hasher_int;
|
||||
|
||||
BOOST_TEST(&void_func1 != &void_func2);
|
||||
BOOST_TEST(&int_func1 != &int_func2);
|
||||
@@ -42,11 +38,11 @@ void function_pointer_tests()
|
||||
BOOST_TEST(hasher_int(&int_func1) == hasher_int(&int_func1));
|
||||
BOOST_TEST(hasher_int(&int_func1) != hasher_int(&int_func2));
|
||||
BOOST_TEST(hasher_int(&int_func1) != hasher_int(0));
|
||||
#if defined(TEST_EXTENSIONS)
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS)
|
||||
BOOST_TEST(hasher_void(&void_func1)
|
||||
== HASH_NAMESPACE::hash_value(&void_func1));
|
||||
== BOOST_HASH_TEST_NAMESPACE::hash_value(&void_func1));
|
||||
BOOST_TEST(hasher_int(&int_func1)
|
||||
== HASH_NAMESPACE::hash_value(&int_func1));
|
||||
== BOOST_HASH_TEST_NAMESPACE::hash_value(&int_func1));
|
||||
|
||||
// This isn't specified in Peter's proposal:
|
||||
BOOST_TEST(hasher_void(0) == 0);
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#if defined(TEST_EXTENSIONS) && !defined(TEST_STD_INCLUDES)
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <cstddef>
|
||||
@@ -25,7 +25,7 @@ namespace test {
|
||||
template <class T>
|
||||
std::size_t hash_value(test_type1<T> const& x)
|
||||
{
|
||||
HASH_NAMESPACE::hash<T> hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
|
||||
return hasher(x.value);
|
||||
}
|
||||
#endif
|
||||
@@ -42,8 +42,8 @@ namespace test {
|
||||
std::size_t hash_value(test_type2<T> const& x)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed, x.value1);
|
||||
HASH_NAMESPACE::hash_combine(seed, x.value2);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value1);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value2);
|
||||
return seed;
|
||||
}
|
||||
#endif
|
||||
@@ -61,8 +61,8 @@ namespace test {
|
||||
std::size_t hash_value(test_type3<T> const& x)
|
||||
{
|
||||
std::size_t seed =
|
||||
HASH_NAMESPACE::hash_range(x.values.begin(), x.values.end());
|
||||
HASH_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(x.values.begin(), x.values.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
|
||||
return seed;
|
||||
}
|
||||
#endif
|
||||
@@ -76,7 +76,7 @@ namespace boost
|
||||
template <class T>
|
||||
std::size_t hash_value(test::test_type1<T> const& x)
|
||||
{
|
||||
HASH_NAMESPACE::hash<T> hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<T> hasher;
|
||||
return hasher(x.value);
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ namespace boost
|
||||
std::size_t hash_value(test::test_type2<T> const& x)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed, x.value1);
|
||||
HASH_NAMESPACE::hash_combine(seed, x.value2);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value1);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, x.value2);
|
||||
return seed;
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ namespace boost
|
||||
std::size_t hash_value(test::test_type3<T> const& x)
|
||||
{
|
||||
std::size_t seed =
|
||||
HASH_NAMESPACE::hash_range(x.values.begin(), x.values.end());
|
||||
HASH_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(x.values.begin(), x.values.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
#include "./hash_fwd_test.hpp"
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#if defined(TEST_EXTENSIONS) && !defined(TEST_STD_INCLUDES)
|
||||
#if defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <string>
|
||||
|
||||
void fwd_test1()
|
||||
@@ -21,10 +21,10 @@ void fwd_test1()
|
||||
test::test_type1<int> x(5);
|
||||
test::test_type1<std::string> y("Test");
|
||||
|
||||
HASH_NAMESPACE::hash<int> hasher_int;
|
||||
HASH_NAMESPACE::hash<std::string> hasher_string;
|
||||
HASH_NAMESPACE::hash<test::test_type1<int> > hasher_test_int;
|
||||
HASH_NAMESPACE::hash<test::test_type1<std::string> > hasher_test_string;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<int> hasher_int;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<std::string> hasher_string;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type1<int> > hasher_test_int;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type1<std::string> > hasher_test_string;
|
||||
|
||||
BOOST_TEST(hasher_int(5) == hasher_test_int(x));
|
||||
BOOST_TEST(hasher_string("Test") == hasher_test_string(y));
|
||||
@@ -36,15 +36,15 @@ void fwd_test2()
|
||||
test::test_type2<std::string> y("Test1", "Test2");
|
||||
|
||||
std::size_t seed1 = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed1, 5);
|
||||
HASH_NAMESPACE::hash_combine(seed1, 10);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, 5);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed1, 10);
|
||||
|
||||
std::size_t seed2 = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed2, std::string("Test1"));
|
||||
HASH_NAMESPACE::hash_combine(seed2, std::string("Test2"));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, std::string("Test1"));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, std::string("Test2"));
|
||||
|
||||
HASH_NAMESPACE::hash<test::test_type2<int> > hasher_test_int;
|
||||
HASH_NAMESPACE::hash<test::test_type2<std::string> > hasher_test_string;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type2<int> > hasher_test_int;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type2<std::string> > hasher_test_string;
|
||||
|
||||
BOOST_TEST(seed1 == hasher_test_int(x));
|
||||
BOOST_TEST(seed2 == hasher_test_string(y));
|
||||
@@ -69,15 +69,15 @@ void fwd_test3()
|
||||
test::test_type3<std::string> y(values2.begin(), values2.end());
|
||||
|
||||
std::size_t seed1 =
|
||||
HASH_NAMESPACE::hash_range(values1.begin(), values1.end());
|
||||
HASH_NAMESPACE::hash_range(seed1, values1.begin(), values1.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(values1.begin(), values1.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(seed1, values1.begin(), values1.end());
|
||||
|
||||
std::size_t seed2 =
|
||||
HASH_NAMESPACE::hash_range(values2.begin(), values2.end());
|
||||
HASH_NAMESPACE::hash_range(seed2, values2.begin(), values2.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(values2.begin(), values2.end());
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_range(seed2, values2.begin(), values2.end());
|
||||
|
||||
HASH_NAMESPACE::hash<test::test_type3<int> > hasher_test_int;
|
||||
HASH_NAMESPACE::hash<test::test_type3<std::string> > hasher_test_string;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type3<int> > hasher_test_int;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<test::test_type3<std::string> > hasher_test_string;
|
||||
|
||||
BOOST_TEST(seed1 == hasher_test_int(x));
|
||||
BOOST_TEST(seed2 == hasher_test_string(y));
|
||||
@@ -87,7 +87,7 @@ void fwd_test3()
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
fwd_test1();
|
||||
fwd_test2();
|
||||
fwd_test3();
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#if !defined(TEST_EXTENSIONS) || defined(TEST_STD_INCLUDES)
|
||||
#if !defined(BOOST_HASH_TEST_EXTENSIONS) || defined(BOOST_HASH_TEST_STD_INCLUDES)
|
||||
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
|
||||
#include "./hash_fwd_test.hpp"
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
template <class T> void unused(T const&) {}
|
||||
|
||||
@@ -44,4 +44,4 @@ int main()
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif // defined(TEST_EXTENSIONS) && !defined(TEST_STD_INCLUDES)
|
||||
#endif // defined(BOOST_HASH_TEST_EXTENSIONS) && !defined(BOOST_HASH_TEST_STD_INCLUDES)
|
||||
|
||||
@@ -17,7 +17,7 @@ struct custom
|
||||
|
||||
std::size_t hash() const
|
||||
{
|
||||
return value_ * 10;
|
||||
return static_cast<std::size_t>(value_ * 10);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
@@ -42,17 +42,17 @@ namespace boost
|
||||
|
||||
#include "./config.hpp"
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
# ifdef TEST_STD_INCLUDES
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
# ifdef BOOST_HASH_TEST_STD_INCLUDES
|
||||
# include <functional>
|
||||
# else
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <boost/container_hash/hash.hpp>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -60,13 +60,13 @@ namespace boost
|
||||
|
||||
void custom_tests()
|
||||
{
|
||||
HASH_NAMESPACE::hash<custom> custom_hasher;
|
||||
BOOST_HASH_TEST_NAMESPACE::hash<custom> custom_hasher;
|
||||
BOOST_TEST(custom_hasher(10) == 100u);
|
||||
custom x(55);
|
||||
BOOST_TEST(custom_hasher(x) == 550u);
|
||||
|
||||
{
|
||||
using namespace HASH_NAMESPACE;
|
||||
using namespace BOOST_HASH_TEST_NAMESPACE;
|
||||
BOOST_TEST(custom_hasher(x) == hash_value(x));
|
||||
}
|
||||
|
||||
@@ -76,26 +76,26 @@ void custom_tests()
|
||||
custom_vector.push_back(35);
|
||||
|
||||
std::size_t seed = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed, custom(5));
|
||||
HASH_NAMESPACE::hash_combine(seed, custom(25));
|
||||
HASH_NAMESPACE::hash_combine(seed, custom(35));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(5));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(25));
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed, custom(35));
|
||||
|
||||
std::size_t seed2 = 0;
|
||||
HASH_NAMESPACE::hash_combine(seed2, 50u);
|
||||
HASH_NAMESPACE::hash_combine(seed2, 250u);
|
||||
HASH_NAMESPACE::hash_combine(seed2, 350u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 50u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 250u);
|
||||
BOOST_HASH_TEST_NAMESPACE::hash_combine(seed2, 350u);
|
||||
|
||||
BOOST_TEST(seed == HASH_NAMESPACE::hash_range(
|
||||
BOOST_TEST(seed == BOOST_HASH_TEST_NAMESPACE::hash_range(
|
||||
custom_vector.begin(), custom_vector.end()));
|
||||
BOOST_TEST(seed == seed2);
|
||||
}
|
||||
|
||||
#endif // TEST_EXTENSIONS
|
||||
#endif // BOOST_HASH_TEST_EXTENSIONS
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef TEST_EXTENSIONS
|
||||
#ifdef BOOST_HASH_TEST_EXTENSIONS
|
||||
custom_tests();
|
||||
#endif
|
||||
return boost::report_errors();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user