forked from boostorg/unordered
Compare commits
972 Commits
boost-1.42
...
boost-1.75
Author | SHA1 | Date | |
---|---|---|---|
0960f885d5 | |||
33b28a514e | |||
2497d663b7 | |||
887f1dc07c | |||
9abce00f24 | |||
f3649e4ae0 | |||
6cf0342322 | |||
3252ad1f4b | |||
741a10f5a8 | |||
c39dd284d2 | |||
4e5c97f3a3 | |||
e10fc0f93b | |||
8207ebe381 | |||
6491f6c10a | |||
cfd4bacc2c | |||
09be9bae04 | |||
c01a8c4629 | |||
cdb0229cf2 | |||
ddf302fcc2 | |||
ca9e9584ba | |||
0d34053870 | |||
66533ace80 | |||
ea599a66b7 | |||
1cc3f680e8 | |||
f7665a2743 | |||
dc9faddf22 | |||
e64c5b34df | |||
57492c1a94 | |||
df8fbca007 | |||
72fb9c7c96 | |||
ce0f16f328 | |||
a477d70f32 | |||
f3476de893 | |||
dea525b2b7 | |||
d55c9565ab | |||
00a4185cf1 | |||
ea28a3f98e | |||
c8facc99a7 | |||
d7ec41f4c6 | |||
9f2063846b | |||
c05c541216 | |||
34e54b35e8 | |||
f12009fc61 | |||
5854090dc7 | |||
7e28fdd45a | |||
daeaf5e98b | |||
4bffd7a85d | |||
7615fabc80 | |||
be0acc575f | |||
9d558b010d | |||
32773fb023 | |||
64441d2b64 | |||
07758b7af8 | |||
92ce66be64 | |||
15befe998e | |||
b50e0d610f | |||
f99dee1917 | |||
6327d174d2 | |||
c2b9b22f67 | |||
311e126ac4 | |||
c037169e1a | |||
9bb861accc | |||
ecd5b239a4 | |||
a600ef6cbb | |||
b90da4a802 | |||
c50ba694a5 | |||
8f7b7ca7b3 | |||
adfc7f4d5d | |||
9e18dc1401 | |||
cf76763ab7 | |||
fb7ef4cf63 | |||
04a0909105 | |||
613f154d47 | |||
978944fab2 | |||
705e69aefd | |||
e58081f6dc | |||
4ac8a45a34 | |||
6b5b968b97 | |||
2ab82ad653 | |||
86df284ad4 | |||
3521c87e17 | |||
32533f7325 | |||
0e19bdf50a | |||
f72b0353d4 | |||
0676b4f4ca | |||
929982357a | |||
5190a5d7f8 | |||
7775aa83df | |||
fc1604f2c8 | |||
5b97fbc292 | |||
4f5a2dabe9 | |||
e0227618bb | |||
ee9a5a2c77 | |||
6fffc738f7 | |||
dc611fc828 | |||
12ee29579d | |||
a897843f6c | |||
80de85f217 | |||
242e91a9fd | |||
ca80237191 | |||
b95ef6de04 | |||
76e7322262 | |||
3c42138e45 | |||
1b0b38a519 | |||
9119a42b7d | |||
8af4b37d14 | |||
31c5b5bfa1 | |||
b6c6bfbe7f | |||
6e074d7165 | |||
0489069419 | |||
597eb5a3fd | |||
3fe259a79e | |||
6ef17a0f0e | |||
47a8c3fc67 | |||
d49d0e90a8 | |||
77bd45b1fa | |||
622dff50df | |||
41f6a051ef | |||
d05619095c | |||
2f8492d720 | |||
7911f491f6 | |||
d84a57441b | |||
b8c754d230 | |||
338a94e577 | |||
2e14c340a8 | |||
35522d3ee0 | |||
8c139940e7 | |||
7b5f73f6c2 | |||
e7a3487df4 | |||
c243895fc0 | |||
451d0f2fc5 | |||
c75b332240 | |||
899248acbf | |||
cae6b121b2 | |||
5f6ee3da9c | |||
bfcdd51b4a | |||
10b736d407 | |||
0b61e6defb | |||
28f529100d | |||
6466ce0b51 | |||
03baef8b28 | |||
f1435d53d4 | |||
20b0c0a6d8 | |||
a1b1df84a0 | |||
408ebd0a0a | |||
e9c4696544 | |||
ea64f2e46e | |||
94a3a9baf9 | |||
da27ae4de6 | |||
ed326e2c87 | |||
bea4c6e29b | |||
61df9479e5 | |||
e3ab7b5d2e | |||
679b73098e | |||
cba643fc51 | |||
1c8edf0298 | |||
07b9a7d60e | |||
9c8980e6a1 | |||
60127d86e0 | |||
0c3c738614 | |||
c8bacbcb00 | |||
b070bb5e49 | |||
e518120104 | |||
84f1ef6d2d | |||
77bf2b5e33 | |||
8229aa6b3c | |||
fc08f62d6a | |||
1254520438 | |||
7941771d61 | |||
4f1c6e1ebf | |||
13ff1e7fb1 | |||
25b0b66e52 | |||
da835e88b8 | |||
b6c229e2bb | |||
19a45e028a | |||
435b7450d4 | |||
a41a0f3a06 | |||
814926ef31 | |||
f6f5ecdc00 | |||
42b6b13943 | |||
cfe4c26f99 | |||
3117611a55 | |||
1e491533fa | |||
a119caaa1b | |||
96f8f85eef | |||
2add451d63 | |||
3effedb728 | |||
b067e65731 | |||
f3b179d451 | |||
de5373413b | |||
fedf533699 | |||
9cd673c71d | |||
85a834cf62 | |||
5167c970af | |||
bf7a65010c | |||
461ac96a2c | |||
5eb10fd0b2 | |||
e2e9959389 | |||
d8969c71fc | |||
ab76814aa6 | |||
1a18cd2196 | |||
e4a00980f8 | |||
af94e6a40e | |||
ee73a53497 | |||
6bdf1ba244 | |||
d47754acac | |||
cee94e9fcb | |||
3ae9930979 | |||
2effcfa195 | |||
8c9080f11f | |||
ef05493c83 | |||
7a0a598649 | |||
cafd236a18 | |||
e0054c7dd0 | |||
3414e6628a | |||
08ce2c98e0 | |||
6d79a322e2 | |||
9e70680044 | |||
7de8c91301 | |||
c333a7f9fc | |||
bc36a06a2d | |||
e62ac22f0b | |||
1092c972c9 | |||
7e5520f974 | |||
2b01bdbc25 | |||
64a3be7d3e | |||
c0e03c3640 | |||
ed8c0f9ecd | |||
2bfc59c461 | |||
727e36e6a6 | |||
09bddd8df4 | |||
f089adc160 | |||
97b68ea05e | |||
972ac220f5 | |||
5d98f3d0f0 | |||
51cd1cd2af | |||
7e940e6e45 | |||
7aa7d8935c | |||
2f4d286a51 | |||
1bc5d87c5d | |||
c2d2be021a | |||
6b32d6bf09 | |||
c18f57f62b | |||
e657f75a17 | |||
d060d3a0e5 | |||
3c8c360f8c | |||
0af2c732ab | |||
68fe365f5b | |||
91bbd5fcb2 | |||
ac6b6bca48 | |||
b6e3f2303f | |||
da370a6a1a | |||
4aa74e5feb | |||
13322fe858 | |||
0645700b33 | |||
d89aadc56c | |||
21a24d6cd7 | |||
9c4c3a754a | |||
5f5f8ef1e4 | |||
958d206bb6 | |||
8fa93cc55b | |||
79cf0c4bfb | |||
81aefde94e | |||
96602df8a8 | |||
c0b72d97b3 | |||
ddee1b686a | |||
2231586033 | |||
13063abce5 | |||
570decf00e | |||
bf5ef9824d | |||
01dcd36c41 | |||
b2f2fdc2f3 | |||
f2af10c746 | |||
3bf664ad31 | |||
67ab88b064 | |||
67f1f65174 | |||
b1dff42434 | |||
57cc6d4bac | |||
e416cafd49 | |||
0aa79ce360 | |||
0a1c9ad4c5 | |||
dd85b16166 | |||
76127b6e42 | |||
03a597983e | |||
33f701dd09 | |||
3db4654b44 | |||
a7546e298e | |||
8a0592a35d | |||
98cce956f9 | |||
a34785fa0d | |||
14ccdbc7b6 | |||
5b5b46ea1c | |||
e3f534a148 | |||
1bcd5b0003 | |||
0d1cfba823 | |||
e986b70981 | |||
9b7b485c33 | |||
c680fa7418 | |||
9772c01161 | |||
6071f9a08b | |||
ad2256b13c | |||
dad0d48c9c | |||
e03a8732a6 | |||
7da307c696 | |||
82438a513b | |||
b5205e58aa | |||
b907cee691 | |||
da6e8e8041 | |||
3fd4495b2f | |||
04607dc9f3 | |||
ece4116329 | |||
74abdd6973 | |||
a316d3fa46 | |||
70ce6b4ae7 | |||
ade302f0a0 | |||
147885fec4 | |||
65aaf27380 | |||
b1588929cc | |||
094fa38360 | |||
71d19820ac | |||
a0dc86ecbc | |||
982685d3a0 | |||
dadb4486ee | |||
d14c1dec59 | |||
21d6d7bc21 | |||
ff0228e752 | |||
b00bc15c3e | |||
50c4cbe06c | |||
573e10665c | |||
d0acb81f2e | |||
e7b20d2877 | |||
588ad6e69f | |||
98462fbcc3 | |||
a93331dd96 | |||
e174af2286 | |||
9decbe0cbd | |||
021817f2b4 | |||
13ff69efbf | |||
8fda9113b8 | |||
b881bcfee3 | |||
1c606980ec | |||
0d6e58d9fd | |||
95e477902e | |||
cc32bfb96f | |||
7c2f11f8e1 | |||
d08dcb7465 | |||
2d1d6ccd75 | |||
7f380028cc | |||
827f77729f | |||
6c81de37f5 | |||
86a8a0429a | |||
4b00548138 | |||
8bb9473443 | |||
da7a5bf269 | |||
7434e116a7 | |||
8f51dc6082 | |||
79deac97dd | |||
9debeadee7 | |||
cae72eec2f | |||
e58370b4ff | |||
e92f7d86c1 | |||
93a33ba15f | |||
ad353c8e3d | |||
09717ffca4 | |||
ce4b840299 | |||
5a8df0ebe4 | |||
6029d1cfd0 | |||
3fe46a1769 | |||
5490bcfe95 | |||
078c562b6c | |||
88612a8be4 | |||
37a6903831 | |||
8017d9e684 | |||
609ae6cb4e | |||
603f785739 | |||
992f9ccf21 | |||
e250fb44f6 | |||
9767d86d97 | |||
7687c99708 | |||
81cc773013 | |||
cdb887e880 | |||
041fee64df | |||
e3dd1f276e | |||
0769ecd70d | |||
2be69b3eb9 | |||
bc601e34d2 | |||
79e39d9d43 | |||
6bc57bd398 | |||
1bca2df642 | |||
59cbe3d483 | |||
21f2522695 | |||
3720b0be58 | |||
413b45a62e | |||
7b8e3d01de | |||
b4a3c6f460 | |||
1d4845d6b8 | |||
c26acdba15 | |||
3f42a56bae | |||
144a0c1791 | |||
cc2b1a1ef1 | |||
84dd473a5d | |||
f014802eb6 | |||
68eb654e7a | |||
3a507b4e39 | |||
0273ec59d7 | |||
9090d87725 | |||
8ccde2e5a1 | |||
31211a607f | |||
56ab93d296 | |||
1d8855da27 | |||
df5a7538b1 | |||
0cedaf7ad6 | |||
b4795f414d | |||
2c9d209eef | |||
a81c86a90e | |||
bf0f90ff03 | |||
7c6f1ef227 | |||
99985bb1b2 | |||
8c5aa5086d | |||
b1232d8061 | |||
2f6b81d8c1 | |||
e1b39bbbfb | |||
6b7cecb9d3 | |||
79dcf7cbe8 | |||
d4702754b7 | |||
98d90f26d7 | |||
b97ceb6442 | |||
c18c645b92 | |||
15cb6d7d1b | |||
2f5d98a0cd | |||
2216c987a0 | |||
86d4d21250 | |||
3eb2355182 | |||
9440395330 | |||
034f2c3779 | |||
e93f5b0971 | |||
8c6f3e910b | |||
78bd2c0736 | |||
4e6ce91dd0 | |||
850d69738b | |||
9c62f83e74 | |||
99fdce0b4d | |||
06b6418044 | |||
57819d1dd9 | |||
80f3376894 | |||
94071cc6e8 | |||
038550a9df | |||
9ca8c691ac | |||
a4881436d2 | |||
70190b3aa2 | |||
8ae166a2c3 | |||
7d0c6d2425 | |||
5995e5521f | |||
59c83ab942 | |||
0a552a47cb | |||
3b5cf359e7 | |||
239453bead | |||
bea92e8842 | |||
ddab816ed7 | |||
007ddb9a5a | |||
6b1a4bfeb7 | |||
6ca8d5e0d9 | |||
6f3dee13a8 | |||
7f14796ba4 | |||
cfb4a9d254 | |||
621c1523c0 | |||
b4d62e4670 | |||
3922d1bb63 | |||
9b9a1d21a6 | |||
033a611f71 | |||
3aa91346ea | |||
a7c0ddb5b3 | |||
de0366105c | |||
3508ceaa58 | |||
29660f9c4d | |||
52b42b4e48 | |||
c88126e1d2 | |||
e6a6fe92d7 | |||
0c7c7cc6ad | |||
fb93c8cb86 | |||
8f0126a13a | |||
0f080552fa | |||
f8a6ea40a1 | |||
1a067034c1 | |||
bd10a8b5aa | |||
d603e75d03 | |||
a422b40041 | |||
44f61e5878 | |||
27c4e90374 | |||
0221f1a9bd | |||
6b21eeccab | |||
bf1f24ab04 | |||
34b69e67ee | |||
64994d76dd | |||
10049f8325 | |||
654fed166a | |||
1bd3b029fa | |||
3305caf40c | |||
85d2657ac1 | |||
8fb85cbb8d | |||
da455124d2 | |||
ef4d33ce89 | |||
7eefe62efe | |||
981f1e2acb | |||
73c0d85ae6 | |||
d495cbd7e6 | |||
ccc3d1c83d | |||
38d8d052d1 | |||
2e26534659 | |||
d1a6e948e3 | |||
81897a6469 | |||
8f8ea09ce8 | |||
ced2139eea | |||
9b398ba0c9 | |||
556adc1de1 | |||
3f060a70d1 | |||
d6322718f3 | |||
0a8037243b | |||
94ef1ac391 | |||
53f278312f | |||
549b93e629 | |||
c2e7221bf9 | |||
a0ceefc91a | |||
37d58e84e3 | |||
ec6219fe13 | |||
05f7c37f54 | |||
e68f0c341e | |||
f47f0f8d16 | |||
ed369d6374 | |||
b6b54610c6 | |||
1d03bbe213 | |||
32ab636fe8 | |||
8e5ffbbe6c | |||
e7f495c094 | |||
1e07edc1ad | |||
2f09079d3f | |||
a1bdd82bd5 | |||
45b6340a98 | |||
22e6daac6c | |||
9ea735c975 | |||
31f3a10d33 | |||
d9f49f2b44 | |||
73c269398a | |||
7a4930f1a1 | |||
d5971171da | |||
035396e89f | |||
c0faf59a86 | |||
a822b27efc | |||
f1e716d897 | |||
612d68eecd | |||
aefea862c2 | |||
f8968ab022 | |||
8f86c2464e | |||
cd57bf5000 | |||
a7125259d8 | |||
3a163b5449 | |||
ff31c73970 | |||
2e11fd8a86 | |||
09c546f63a | |||
8683332b2c | |||
5be71a0e90 | |||
27f5496a65 | |||
918b3da91d | |||
61516be1db | |||
7c968fd38d | |||
d77453b7ad | |||
cf9930fe20 | |||
e30a99d2fc | |||
4a066e4b18 | |||
0fccd93e29 | |||
6932a2d571 | |||
f387994422 | |||
958b1d468f | |||
f5292fd9f7 | |||
ada08d9459 | |||
9a284b4106 | |||
98083078a3 | |||
b8d96be8f7 | |||
68edec9f97 | |||
39bafd7b10 | |||
c788780792 | |||
0acb4ee3e6 | |||
893ebc5adb | |||
7158700502 | |||
1eac47a275 | |||
c6f0175c79 | |||
e1416d0a3e | |||
6031b66f99 | |||
808f1f939f | |||
d863f17673 | |||
24c08646f4 | |||
6604abe600 | |||
39aed02e32 | |||
6b44f3b887 | |||
cd88cb4a30 | |||
32dc45b7bd | |||
275b03e76b | |||
995ef1efdb | |||
8cb85937c4 | |||
e615ac67c2 | |||
880d778ab6 | |||
a8cd8cdd0b | |||
401df0f2fb | |||
531f6804ad | |||
d5230a874b | |||
030fd55d02 | |||
626bb48013 | |||
e64f82ed03 | |||
c8c71d0ad1 | |||
4e759b4444 | |||
9f199eaa23 | |||
2fed2fbd9e | |||
29d63e378b | |||
8a1a475c58 | |||
08230efb44 | |||
2aee3add16 | |||
fa3d93ddbc | |||
f6b8d3957d | |||
992cc0b077 | |||
2f92b12205 | |||
2e80a82554 | |||
5622afdafa | |||
63d56953af | |||
51d2e2564e | |||
2665090568 | |||
d70fcb8c25 | |||
ac0a2fe6c9 | |||
280b1971b6 | |||
6c09b89d0c | |||
8f982c8b27 | |||
a61e876300 | |||
684e40464f | |||
2507fd78e3 | |||
21f1fe8185 | |||
aeea8e05ad | |||
abc556950b | |||
11c9955902 | |||
9cb361f35e | |||
a8f75b7cea | |||
c3477b2624 | |||
a5dcc9dab0 | |||
6ebc2e72ff | |||
1f111edec8 | |||
d2a6ad8c72 | |||
8591c1f180 | |||
087962c16e | |||
4471e056f4 | |||
b56a5ead66 | |||
e3befdba7f | |||
50e8df5e12 | |||
0cf8de5222 | |||
b6a6f530c0 | |||
03245c80ff | |||
2775ae2f2e | |||
8557a30592 | |||
fd530b87f6 | |||
674d635024 | |||
f304e56818 | |||
5a2bf64a65 | |||
f1b78931d1 | |||
3d7b6c64b5 | |||
597d93537d | |||
3a909c8747 | |||
ad38ecf6d8 | |||
dac1dc5837 | |||
c0aaf908c0 | |||
b1d782285c | |||
b0620a46ff | |||
340c98d89a | |||
78241de393 | |||
17ba6c9916 | |||
dbf7c9d6aa | |||
983ad956e0 | |||
45273ea6a5 | |||
9b82dcde10 | |||
b496bc3fa2 | |||
f8abb9633a | |||
76c37f7805 | |||
7d441864ec | |||
ccd895a356 | |||
8ecdee5a93 | |||
0618d01f86 | |||
70c39ad5ea | |||
96fc0fa3c2 | |||
c101aec06c | |||
5867994b8c | |||
bd79d02049 | |||
0ea847a64e | |||
965e25c989 | |||
a3ffd4a7c9 | |||
41b9b8d841 | |||
26a47d33c1 | |||
1154b5729a | |||
fd1aec2998 | |||
659b6fe8ba | |||
ceef4d6521 | |||
86b077b9a1 | |||
28cdebe7a4 | |||
d4087f64d9 | |||
4ec5a0eebd | |||
f58a3fc3eb | |||
11562b3285 | |||
568fd1758d | |||
f64b5ba3f8 | |||
395c744d6f | |||
155077cba0 | |||
4dcf34c264 | |||
4bf3b1bfc5 | |||
6bc99ac0c2 | |||
09e856562a | |||
f6f19aaaaa | |||
5dd13dbfb3 | |||
9ae19a64d7 | |||
bd13f2b1ad | |||
d09bbba6c1 | |||
3f4d031c43 | |||
674b39243f | |||
099a893678 | |||
cfd52c8f38 | |||
a4372314c2 | |||
e295541dae | |||
785a6def3b | |||
53bdec8aab | |||
5191897696 | |||
2ecfa0e08c | |||
c001139465 | |||
e3353a445a | |||
ce779452ba | |||
eb8b8295a1 | |||
94c9c61142 | |||
11e390bf42 | |||
a8fdf19c91 | |||
08bca9a35f | |||
1db630d5c9 | |||
bbad921022 | |||
f64cf03e1d | |||
559122f67a | |||
431f2abfee | |||
5f622027cd | |||
fa97494cc8 | |||
f4d4975077 | |||
f030480e44 | |||
435c21c155 | |||
7438d7a02f | |||
0e5930b8dc | |||
eacca89d4e | |||
99e6bef4ef | |||
3d5314b5f5 | |||
f0517463a5 | |||
c9e0fb9730 | |||
d86a4b0c2f | |||
eced4266c2 | |||
fc483e60bc | |||
910cd41c47 | |||
b4e1d32e85 | |||
ff66f79721 | |||
8b610a6d34 | |||
20e923ba0d | |||
4777eaf367 | |||
a40422fada | |||
b1912055a9 | |||
e8714d79b2 | |||
f8e2a917f9 | |||
140e8852e8 | |||
547e141166 | |||
3fd5635d7d | |||
d9c49a6cde | |||
8ade57b9e3 | |||
147181530d | |||
a4750fbdba | |||
a33949a0a5 | |||
54f9626c12 | |||
4d57147c3d | |||
3d7abd9cbe | |||
5a81ca6ffe | |||
b9188caf7d | |||
df726c038f | |||
14e0e1afc2 | |||
2c1a8894cb | |||
a49c76c69c | |||
eb04f68351 | |||
77bd36d038 | |||
dc8e65043b | |||
1b85f812af | |||
daad24388c | |||
8b4c480d47 | |||
0cbd02d3cc | |||
3a13ddb4a3 | |||
7b272c85d5 | |||
70ca44b503 | |||
5edc45349f | |||
dfaa61b666 | |||
076e195cac | |||
71a8e56ae3 | |||
795d9f0aa7 | |||
ef79fea0b7 | |||
ea33b5d134 | |||
5bab4d4360 | |||
ec97640b1b | |||
10e24f93c4 | |||
d3ca85bdbd | |||
00cebc3dfb | |||
fe2a6c521b | |||
ee034e23bb | |||
958738c7af | |||
1d02663275 | |||
3fb7d15f5b | |||
e594f1eda7 | |||
1bcb5f8b6f | |||
06f63fdc0d | |||
7efcf9ccff | |||
6649b4df3c | |||
71096f4d26 | |||
0f0161a5a2 | |||
b99382b551 | |||
493f905598 | |||
4e6292b439 | |||
2f0a94bcfd | |||
618a51df13 | |||
18a5010436 | |||
c8b893cb77 | |||
a1252fcc0e | |||
ef67d9ae12 | |||
3e638049ec | |||
7f59e8e058 | |||
7023460394 | |||
0dcf1b5cd2 | |||
7b2c5189b3 | |||
d3fe62a646 | |||
1f17294cd3 | |||
3882a61065 | |||
df72c4886f | |||
26c72f9860 | |||
55957bbab5 | |||
ab843eb587 | |||
4438b8e017 | |||
5747836754 | |||
ba5c383877 | |||
b4f08db391 | |||
060acb3f25 | |||
8727de1a1b | |||
8cde8d1252 | |||
6bac25221a | |||
5bedbde746 | |||
2fdd33381c | |||
8d4b503e56 | |||
6c24cccf96 | |||
51fdfa7ac7 | |||
3dff89c240 | |||
4e07c94502 | |||
854dc0b353 | |||
373791d0b2 | |||
fe3d612fe0 | |||
ae0c97a77a | |||
788a3661a2 | |||
1e24f85fbc | |||
4601f5c51f | |||
55eafdf0ee | |||
63e04cfb60 | |||
d0a3efab6a | |||
2b8680d2c4 | |||
31cd8f4e16 | |||
b75b7dd5ac | |||
437a35feaa | |||
f76af2d0c8 | |||
efbf13685e | |||
08d533cb88 | |||
ff6e457651 | |||
965c2ae89c | |||
78b078f41d | |||
491fa330f6 | |||
9ec148aec5 | |||
7598d0d49b | |||
6a8506d959 | |||
7fe53ef5a3 | |||
1743ed118d | |||
848b73f99f | |||
ccc88ecf0a | |||
c40cb50fe5 | |||
386d9f28d7 | |||
4350660626 | |||
1632522967 | |||
178154082f | |||
d5dac9bdae | |||
cf363355df | |||
ca018bfba6 | |||
3c48fa3818 | |||
7bc588d8df | |||
6d1aece43a | |||
7e1dbc4cb7 | |||
2b09a34467 | |||
78ea3024b5 | |||
cec1891586 | |||
6d8ce11934 | |||
b83a73ab40 | |||
caa0b7cdf6 | |||
46caec7d77 | |||
04234cecee | |||
84ff0c3227 | |||
35a3894a88 | |||
bde5df043c | |||
8f70ddf4ef | |||
cfc134b871 | |||
20c9360528 | |||
09b239ed28 | |||
294d58d2fe | |||
3e70155100 | |||
ce379f7bb5 | |||
f8e1ec8d2b | |||
24091f8bd8 | |||
4c3c18467c | |||
3f0e2b478b | |||
ac2409627a | |||
a07e4c5810 | |||
5a86d08271 | |||
4ac0a12a83 | |||
290c7566ff | |||
6ccc68b15c | |||
188bcafdec | |||
3a8739cd60 | |||
2bc986ecbc | |||
638accbec4 | |||
d8fb4f4c38 | |||
3e55934381 | |||
40a89ac649 | |||
d442f20bf8 | |||
d36fc98c15 | |||
700c4717d6 | |||
1e73578ab6 | |||
971224a282 | |||
acce19ce43 | |||
77021c5bbb | |||
fe3873b28f | |||
c1e9a6ac59 | |||
c2425106ea | |||
c8e7874534 | |||
601daa0e5d | |||
d022cc48ad | |||
527a72860d | |||
f0bb74a530 | |||
b75f06d935 | |||
e2d1d75955 | |||
80dc7b5e6a | |||
1f4d8e7c21 | |||
366c09f199 | |||
d98f72c4e1 | |||
e6417fe652 | |||
f5d52cc9b2 | |||
62427c8287 | |||
ab588fe872 | |||
fe1385ab34 | |||
d6f513be52 | |||
d8fa4cef60 | |||
506f478ec7 | |||
f2c420e289 | |||
eae2a90463 | |||
4305d10264 | |||
d5b38b01fc | |||
c49dbd782d | |||
c7bde21be7 | |||
d5fdc0b47e | |||
c3d97bd613 | |||
2960390f79 | |||
f723f857e4 | |||
d66936a640 | |||
3640e1e96c | |||
ec1e809fc3 | |||
8868fa4687 | |||
ebd75b4010 | |||
9bd3f498a7 | |||
659a014976 | |||
885574e1bf |
32
.appveyor.yml
Normal file
32
.appveyor.yml
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2017 Daniel James
|
||||
# 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
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
TOOLSET: msvc-10.0,msvc-11.0,msvc-12.0,msvc-14.0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc-14.1
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
TOOLSET: msvc-14.2
|
||||
|
||||
install:
|
||||
- set BOOST_ROOT=c:\projects\boost
|
||||
- cd c:\projects\
|
||||
- python %APPVEYOR_BUILD_FOLDER%\ci\download-boost-snapshot.py master
|
||||
- rd /s /q %BOOST_ROOT%\boost\unordered
|
||||
- cd %BOOST_ROOT%\tools\build
|
||||
- cmd /c bootstrap
|
||||
- cd %APPVEYOR_BUILD_FOLDER%
|
||||
- echo. 2>Jamroot.jam
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\test
|
||||
- cmd /c %BOOST_ROOT%\tools\build\b2 -j 3 toolset=%TOOLSET% include=%APPVEYOR_BUILD_FOLDER%\include include=%BOOST_ROOT%
|
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
|
||||
[*.?pp]
|
||||
indent_size = 2
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/doc/html/
|
87
.travis.yml
Normal file
87
.travis.yml
Normal file
@ -0,0 +1,87 @@
|
||||
# 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++
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libxml2-utils
|
||||
- g++-multilib
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
env: |
|
||||
label="gcc C++03/11";
|
||||
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address ;"
|
||||
enable_coverage=1
|
||||
CXXSTD=03,11
|
||||
- compiler: gcc
|
||||
env: |
|
||||
label="gcc 32 bit C++11";
|
||||
user_config="using gcc : : g++-4.8 -m32 -fsanitize=address ;"
|
||||
CXXSTD=11
|
||||
- compiler: clang
|
||||
env: |
|
||||
label="clang C++11/17";
|
||||
user_config="using clang : : clang++ -fsanitize=address ;"
|
||||
CXXSTD=11,17
|
||||
# sanitized=address not available for 32-bit clang on travis.
|
||||
- compiler: clang
|
||||
env: |
|
||||
label="clang 32 bit";
|
||||
user_config="using clang : : clang++ -m32 ;"
|
||||
CXXSTD=03
|
||||
|
||||
before_install:
|
||||
- if [ -n $enable_coverage ]; then pip install --user cpp-coveralls; fi
|
||||
|
||||
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
|
||||
- |
|
||||
# Pick snapshot to use
|
||||
if [ "$TRAVIS_EVENT_TYPE" == "cron" ]
|
||||
then
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]
|
||||
then
|
||||
snapshot=master
|
||||
else
|
||||
snapshot=develop
|
||||
fi
|
||||
else
|
||||
#snapshot=stable
|
||||
snapshot=master
|
||||
fi
|
||||
|
||||
# Download and extract snapshot
|
||||
echo "Downloading ${download_url}"
|
||||
mkdir $HOME/download
|
||||
cd $HOME/download
|
||||
python ${TRAVIS_BUILD_DIR}/ci/download-boost-snapshot.py $snapshot
|
||||
mv * ${BOOST_ROOT}
|
||||
- rm -r ${BOOST_ROOT}/boost/unordered
|
||||
- cd ${BOOST_ROOT}/tools/build
|
||||
- mkdir ${HOME}/opt
|
||||
- bash bootstrap.sh
|
||||
- ./b2 install --prefix=$HOME/opt
|
||||
|
||||
after_success:
|
||||
if [ -n $enable_coverage ]; then coveralls -r ${TRAVIS_BUILD_DIR} -b ${TRAVIS_BUILD_DIR}/test --gcov-options '\-lp' --include include/boost/unordered/ ; fi
|
||||
|
||||
script:
|
||||
- cd ${TRAVIS_BUILD_DIR}/test
|
||||
- ${HOME}/opt/bin/b2 -j 3 cxxstd=$CXXSTD -q include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include
|
||||
- xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml
|
38
_clang-format
Normal file
38
_clang-format
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
# 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)
|
||||
|
||||
# Using clang format 4.0
|
||||
# http://llvm.org/releases/4.0.0/tools/clang/docs/ClangFormatStyleOptions.html
|
||||
|
||||
# Becuase you have to start somewhere.
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Basic settings
|
||||
ColumnLimit: 80
|
||||
NamespaceIndentation: All
|
||||
ContinuationIndentWidth: 2
|
||||
IndentWidth: 2
|
||||
UseTab: Never
|
||||
Language: Cpp
|
||||
Standard: Cpp03
|
||||
|
||||
# Code layout
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignTrailingComments: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterNamespace: false
|
||||
AfterClass: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterControlStatement: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
PointerAlignment: Left
|
||||
|
||||
# Boost specific stuff
|
||||
ForEachMacros: [ BOOST_FOREACH, UNORDERED_AUTO_TEST ]
|
66
ci/download-boost-snapshot.py
Normal file
66
ci/download-boost-snapshot.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import urllib, os, os.path, sys, json, tarfile, zipfile, tempfile
|
||||
|
||||
def download(snapshot):
|
||||
if snapshot == 'stable':
|
||||
# TODO: Default version/filename if not available?
|
||||
downloads = [
|
||||
"https://sourceforge.net/projects/boost/files/boost/%s/%s.tar.bz2/download" %
|
||||
(os.environ['BOOST_VERSION'], os.environ['BOOST_FILENAME'])]
|
||||
else:
|
||||
json_response = urllib.urlopen('https://api.bintray.com/packages/boostorg/%s/snapshot/files' % (snapshot))
|
||||
x = json.load(json_response)
|
||||
|
||||
extension_priorities = { '.bz2': 2, '.gz': 1, '.zip': 0 }
|
||||
file_list = []
|
||||
version_dates = {}
|
||||
for file in x:
|
||||
file_extension = os.path.splitext(file['path'])[1]
|
||||
if (file_extension in extension_priorities):
|
||||
file['priority'] = extension_priorities[file_extension]
|
||||
file_list.append(file)
|
||||
if not file['version'] in version_dates or file['created'] < version_dates[file['version']]:
|
||||
version_dates[file['version']] = file['created']
|
||||
file_list.sort(key=lambda x: (version_dates[x['version']], x['priority']), reverse=True)
|
||||
downloads = ['http://dl.bintray.com/boostorg/%s/%s' % (snapshot, file['path']) for file in file_list]
|
||||
|
||||
filename = ''
|
||||
for download_url in downloads:
|
||||
try:
|
||||
print "Downloading: " + download_url
|
||||
(filename, headers) = urllib.urlretrieve(download_url)
|
||||
|
||||
print "Extracting: " + filename
|
||||
dir = tempfile.mkdtemp()
|
||||
extract(filename, dir)
|
||||
os.remove(filename)
|
||||
files = os.listdir(dir)
|
||||
assert(len(files) == 1)
|
||||
os.rename(os.path.join(dir, files[0]), 'boost')
|
||||
return
|
||||
except IOError:
|
||||
print "Error opening URL: " + download_url
|
||||
|
||||
def extract(filename, path = '.'):
|
||||
if (filename.endswith(".gz")):
|
||||
tar = tarfile.open(filename, "r:gz")
|
||||
tar.extractall(path)
|
||||
tar.close
|
||||
elif (filename.endswith(".bz2")):
|
||||
tar = tarfile.open(filename, "r:bz2")
|
||||
tar.extractall(path)
|
||||
tar.close
|
||||
elif (filename.endswith(".zip")):
|
||||
zip = zipfile.ZipFile(filename, "r")
|
||||
zip.extractall(path)
|
||||
zip.close
|
||||
else:
|
||||
assert False
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
download('stable')
|
||||
elif len(sys.argv) == 2:
|
||||
download(sys.argv[1])
|
||||
else:
|
||||
print "Usage: %s [stable|branch-name]" % (sys.argv[0])
|
@ -3,16 +3,16 @@
|
||||
# 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 ;
|
||||
|
||||
path-constant images_location : ../ ;
|
||||
path-constant admonishment_location : ../../../../doc/src/images ;
|
||||
|
||||
xml unordered : unordered.qbk ;
|
||||
boostbook standalone : unordered :
|
||||
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
|
||||
<xsl:param>boost.root=../../../..
|
||||
<xsl:param>boost.libraries=../../../libraries.htm
|
||||
<xsl:param>navig.graphics=1
|
||||
xml unordered : unordered.qbk :
|
||||
<xsl:param>generate.consistent.ids=1 ;
|
||||
|
||||
boostbook standalone : unordered :
|
||||
<xsl:param>chunk.first.sections=1
|
||||
<xsl:param>chunk.section.depth=2
|
||||
<xsl:param>generate.section.toc.level=2
|
||||
@ -23,7 +23,17 @@ boostbook standalone : unordered :
|
||||
<xsl:param>boost.compact.function=0
|
||||
<xsl:param>boost.compact.enum=0
|
||||
|
||||
<xsl:param>generate.consistent.ids=1
|
||||
|
||||
# HTML Options:
|
||||
|
||||
<format>html:<xsl:param>boost.root=../../../..
|
||||
<format>html:<xsl:param>img.src.path=../../../../doc/html/
|
||||
<format>xhtml:<xsl:param>boost.root=../../../..
|
||||
<format>xhtml:<xsl:param>img.src.path=../../../../doc/html/
|
||||
|
||||
# PDF Options:
|
||||
|
||||
# TOC Generation: this is needed for FOP-0.9 and later:
|
||||
<xsl:param>fop1.extensions=0
|
||||
<format>pdf:<xsl:param>xep.extensions=1
|
||||
@ -51,3 +61,12 @@ boostbook standalone : unordered :
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/unordered/doc/html
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: unordered
|
||||
:
|
||||
:
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
|
@ -17,7 +17,7 @@ the hash function, `Hash`, to the element's key (for `unordered_set` and
|
||||
`unordered_multiset` the key is the whole element, but is referred to as the key
|
||||
so that the same terminology can be used for sets and maps). This returns a
|
||||
value of type `std::size_t`. `std::size_t` has a much greater range of values
|
||||
then the number of buckets, so that container applies another transformation to
|
||||
then the number of buckets, so the container applies another transformation to
|
||||
that value to choose a bucket to place the element in.
|
||||
|
||||
Retrieving the elements for a given key is simple. The same process is applied
|
||||
@ -57,7 +57,7 @@ keep collisions to a minimum.
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`size_type bucket(key_type const& k) const`'''</entry>
|
||||
<entry>'''Returns the index of the bucket which would contain k'''</entry>
|
||||
<entry>'''Returns the index of the bucket which would contain `k`.'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`local_iterator begin(size_type n);`'''</entry>
|
||||
@ -92,7 +92,7 @@ You can also tell the container to change the bucket count (if required) by
|
||||
calling `rehash`.
|
||||
|
||||
The standard leaves a lot of freedom to the implementer to decide how the
|
||||
number of buckets are chosen, but it does make some requirements based on the
|
||||
number of buckets is chosen, but it does make some requirements based on the
|
||||
container's 'load factor', the average number of elements per bucket.
|
||||
Containers also have a 'maximum load factor' which they should try to keep the
|
||||
load factor below.
|
||||
@ -112,7 +112,7 @@ load factor is /required/ to be less than the maximum is following a call to
|
||||
below the max load factor, and set the maximum load factor to be the same as
|
||||
or close to the hint - unless your hint is unreasonably small or large.
|
||||
|
||||
[table Methods for Controlling Bucket Size
|
||||
[table:bucket_size Methods for Controlling Bucket Size
|
||||
[[Method] [Description]]
|
||||
|
||||
[
|
||||
@ -138,7 +138,7 @@ or close to the hint - unless your hint is unreasonably small or large.
|
||||
]
|
||||
[
|
||||
[`void rehash(size_type n)`]
|
||||
[Changes the number of buckets so that there at least n buckets, and
|
||||
[Changes the number of buckets so that there at least `n` buckets, and
|
||||
so that the load factor is less than the maximum load factor.]
|
||||
]
|
||||
|
||||
@ -149,7 +149,7 @@ or close to the hint - unless your hint is unreasonably small or large.
|
||||
It is not specified how member functions other than `rehash` affect
|
||||
the bucket count, although `insert` is only allowed to invalidate iterators
|
||||
when the insertion causes the load factor to be greater than or equal to the
|
||||
maximum load factor. For most implementations this means that insert will only
|
||||
maximum load factor. For most implementations this means that `insert` will only
|
||||
change the number of buckets when this happens. While iterators can be
|
||||
invalidated by calls to `insert` and `rehash`, pointers and references to the
|
||||
container's elements are never invalidated.
|
||||
@ -160,12 +160,9 @@ the expensive rehashing out of the way and let you store iterators, safe in
|
||||
the knowledge that they won't be invalidated. If you are inserting `n`
|
||||
elements into container `x`, you could first call:
|
||||
|
||||
x.rehash((x.size() + n) / x.max_load_factor() + 1);
|
||||
x.rehash((x.size() + n) / x.max_load_factor());
|
||||
|
||||
[blurb Note: `rehash`'s argument is the minimum number of buckets, not the
|
||||
number of elements, which is why the new size is divided by the maximum load factor. The
|
||||
`+ 1` guarantees there is no invalidation; without it, reallocation could occur
|
||||
if the number of bucket exactly divides the target size, since the container is
|
||||
allowed to rehash when the load factor is equal to the maximum load factor.]
|
||||
number of elements, which is why the new size is divided by the maximum load factor.]
|
||||
|
||||
[endsect]
|
||||
|
248
doc/changes.qbk
248
doc/changes.qbk
@ -3,6 +3,11 @@
|
||||
/ 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) ]
|
||||
|
||||
[template ticket[number]'''<ulink
|
||||
url="https://svn.boost.org/trac/boost/ticket/'''[number]'''">'''#[number]'''</ulink>''']
|
||||
|
||||
[template pull_request[number][@https://github.com/boostorg/unordered/pull/[number] GitHub #[number]]]
|
||||
|
||||
[section:changes Change Log]
|
||||
|
||||
[h2 Review Version]
|
||||
@ -44,12 +49,12 @@ First official release.
|
||||
|
||||
[h2 Boost 1.38.0]
|
||||
|
||||
* Use [@boost:/libs/utility/swap.html `boost::swap`].
|
||||
* Use [@boost:/libs/core/swap.html `boost::swap`].
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2237 Ticket 2237]:
|
||||
Document that the equality and inequality operators are undefined for two
|
||||
objects if their equality predicates aren't equivalent. Thanks to Daniel
|
||||
Krügler.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/1710 Ticket 1710]:
|
||||
* [@https://svn.boost.org/trac/boost/ticket/1710 Ticket 1710]:
|
||||
Use a larger prime number list. Thanks to Thorsten Ottosen and Hervé
|
||||
Brönnimann.
|
||||
* Use
|
||||
@ -96,13 +101,13 @@ First official release.
|
||||
has been rewritten to use templates instead of macros for the implementation
|
||||
classes.
|
||||
|
||||
* The container objcet is now smaller thanks to using `boost::compressed_pair`
|
||||
* The container object is now smaller thanks to using `boost::compressed_pair`
|
||||
for EBO and a slightly different function buffer - now using a bool instead
|
||||
of a member pointer.
|
||||
|
||||
* Buckets are allocated lazily which means that constructing an empty container
|
||||
will not allocate any memory.
|
||||
|
||||
|
||||
[h2 Boost 1.42.0]
|
||||
|
||||
* Support instantiating the containers with incomplete value types.
|
||||
@ -117,4 +122,239 @@ First official release.
|
||||
Add missing `std` qualifier to `ptrdiff_t`.
|
||||
* Some code formatting changes to fit almost all lines into 80 characters.
|
||||
|
||||
[h2 Boost 1.43.0]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3966 Ticket 3966]:
|
||||
`erase_return_void` is now `quick_erase`, which is the
|
||||
[@http://home.roadrunner.com/~hinnant/issue_review/lwg-active.html#579
|
||||
current forerunner for resolving the slow erase by iterator], although
|
||||
there's a strong possibility that this may change in the future. The old
|
||||
method name remains for backwards compatibility but is considered deprecated
|
||||
and will be removed in a future release.
|
||||
* Use Boost.Exception.
|
||||
* Stop using deprecated `BOOST_HAS_*` macros.
|
||||
|
||||
[h2 Boost 1.45.0]
|
||||
|
||||
* Fix a bug when inserting into an `unordered_map` or `unordered_set` using
|
||||
iterators which returns `value_type` by copy.
|
||||
|
||||
[h2 Boost 1.48.0 - Major update]
|
||||
|
||||
This is major change which has been converted to use Boost.Move's move
|
||||
emulation, and be more compliant with the C++11 standard. See the
|
||||
[link unordered.compliance compliance section] for details.
|
||||
|
||||
The container now meets C++11's complexity requirements, but to do so
|
||||
uses a little more memory. This means that `quick_erase` and
|
||||
`erase_return_void` are no longer required, they'll be removed in a
|
||||
future version.
|
||||
|
||||
C++11 support has resulted in some breaking changes:
|
||||
|
||||
* Equality comparison has been changed to the C++11 specification.
|
||||
In a container with equivalent keys, elements in a group with equal
|
||||
keys used to have to be in the same order to be considered equal,
|
||||
now they can be a permutation of each other. To use the old
|
||||
behavior define the macro `BOOST_UNORDERED_DEPRECATED_EQUALITY`.
|
||||
|
||||
* The behaviour of swap is different when the two containers to be
|
||||
swapped has unequal allocators. It used to allocate new nodes using
|
||||
the appropriate allocators, it now swaps the allocators if
|
||||
the allocator has a member structure `propagate_on_container_swap`,
|
||||
such that `propagate_on_container_swap::value` is true.
|
||||
|
||||
* Allocator's `construct` and `destroy` functions are called with raw
|
||||
pointers, rather than the allocator's `pointer` type.
|
||||
|
||||
* `emplace` used to emulate the variadic pair constructors that
|
||||
appeared in early C++0x drafts. Since they were removed it no
|
||||
longer does so. It does emulate the new `piecewise_construct`
|
||||
pair constructors - only you need to use
|
||||
`boost::piecewise_construct`. To use the old emulation of
|
||||
the variadic constructors define
|
||||
`BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT`.
|
||||
|
||||
[h2 Boost 1.49.0]
|
||||
|
||||
* Fix warning due to accidental odd assignment.
|
||||
* Slightly better error messages.
|
||||
|
||||
[h2 Boost 1.50.0]
|
||||
|
||||
* Fix equality for `unordered_multiset` and `unordered_multimap`.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/6857 Ticket 6857]:
|
||||
Implement `reserve`.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/6771 Ticket 6771]:
|
||||
Avoid gcc's `-Wfloat-equal` warning.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/6784 Ticket 6784]:
|
||||
Fix some Sun specific code.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/6190 Ticket 6190]:
|
||||
Avoid gcc's `-Wshadow` warning.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/6905 Ticket 6905]:
|
||||
Make namespaces in macros compatible with `bcp` custom namespaces.
|
||||
Fixed by Luke Elliott.
|
||||
* Remove some of the smaller prime number of buckets, as they may make
|
||||
collisions quite probable (e.g. multiples of 5 are very common because
|
||||
we used base 10).
|
||||
* On old versions of Visual C++, use the container library's implementation
|
||||
of `allocator_traits`, as it's more likely to work.
|
||||
* On machines with 64 bit std::size_t, use power of 2 buckets, with Thomas
|
||||
Wang's hash function to pick which one to use. As modulus is very slow
|
||||
for 64 bit values.
|
||||
* Some internal changes.
|
||||
|
||||
[h2 Boost 1.51.0]
|
||||
|
||||
* Fix construction/destruction issue when using a C++11 compiler with a
|
||||
C++03 allocator ([ticket 7100]).
|
||||
* Remove a `try..catch` to support compiling without exceptions.
|
||||
* Adjust SFINAE use to try to support g++ 3.4 ([ticket 7175]).
|
||||
* Updated to use the new config macros.
|
||||
|
||||
[h2 Boost 1.52.0]
|
||||
|
||||
* Faster assign, which assigns to existing nodes where possible, rather than
|
||||
creating entirely new nodes and copy constructing.
|
||||
* Fixed bug in `erase_range` ([ticket 7471]).
|
||||
* Reverted some of the internal changes to how nodes are created, especially
|
||||
for C++11 compilers. 'construct' and 'destroy' should work a little better
|
||||
for C++11 allocators.
|
||||
* Simplified the implementation a bit. Hopefully more robust.
|
||||
|
||||
[h2 Boost 1.53.0]
|
||||
|
||||
* Remove support for the old pre-standard variadic pair constructors, and
|
||||
equality implementation. Both have been deprecated since Boost 1.48.
|
||||
* Remove use of deprecated config macros.
|
||||
* More internal implementation changes, including a much simpler
|
||||
implementation of `erase`.
|
||||
|
||||
[h2 Boost 1.54.0]
|
||||
|
||||
* Mark methods specified in standard as `noexpect`. More to come in the next
|
||||
release.
|
||||
* If the hash function and equality predicate are known to both have nothrow
|
||||
move assignment or construction then use them.
|
||||
|
||||
[h2 Boost 1.55.0]
|
||||
|
||||
* Avoid some warnings ([ticket 8851], [ticket 8874]).
|
||||
* Avoid exposing some detail functions via. ADL on the iterators.
|
||||
* Follow the standard by only using the allocators' construct and destroy
|
||||
methods to construct and destroy stored elements. Don't use them for internal
|
||||
data like pointers.
|
||||
|
||||
[h2 Boost 1.56.0]
|
||||
|
||||
* Fix some shadowed variable warnings ([ticket 9377]).
|
||||
* Fix allocator use in documentation ([ticket 9719]).
|
||||
* Always use prime number of buckets for integers. Fixes performance
|
||||
regression when inserting consecutive integers, although makes other
|
||||
uses slower ([ticket 9282]).
|
||||
* Only construct elements using allocators, as specified in C++11 standard.
|
||||
|
||||
[h2 Boost 1.57.0]
|
||||
|
||||
* Fix the `pointer` typedef in iterators ([ticket 10672]).
|
||||
* Fix Coverity warning
|
||||
([@https://github.com/boostorg/unordered/pull/2 GitHub #2]).
|
||||
|
||||
[h2 Boost 1.58.0]
|
||||
|
||||
* Remove unnecessary template parameter from const iterators.
|
||||
* Rename private `iterator` typedef in some iterator classes, as it
|
||||
confuses some traits classes.
|
||||
* Fix move assignment with stateful, propagate_on_container_move_assign
|
||||
allocators ([ticket 10777]).
|
||||
* Fix rare exception safety issue in move assignment.
|
||||
* Fix potential overflow when calculating number of buckets to allocate
|
||||
([@https://github.com/boostorg/unordered/pull/4 GitHub #4]).
|
||||
|
||||
[h2 Boost 1.62.0]
|
||||
|
||||
* Remove use of deprecated `boost::iterator`.
|
||||
* Remove `BOOST_NO_STD_DISTANCE` workaround.
|
||||
* Remove `BOOST_UNORDERED_DEPRECATED_EQUALITY` warning.
|
||||
* Simpler implementation of assignment, fixes an exception safety issue
|
||||
for `unordered_multiset` and `unordered_multimap`. Might be a little slower.
|
||||
* Stop using return value SFINAE which some older compilers have issues
|
||||
with.
|
||||
|
||||
[h2 Boost 1.63.0]
|
||||
|
||||
* Check hint iterator in `insert`/`emplace_hint`.
|
||||
* Fix some warnings, mostly in the tests.
|
||||
* Manually write out `emplace_args` for small numbers of arguments -
|
||||
should make template error messages a little more bearable.
|
||||
* Remove superfluous use of `boost::forward` in emplace arguments,
|
||||
which fixes emplacing string literals in old versions of Visual C++.
|
||||
* Fix an exception safety issue in assignment. If bucket allocation
|
||||
throws an exception, it can overwrite the hash and equality functions while
|
||||
leaving the existing elements in place. This would mean that the function
|
||||
objects wouldn't match the container elements, so elements might be in the
|
||||
wrong bucket and equivalent elements would be incorrectly handled.
|
||||
* Various reference documentation improvements.
|
||||
* Better allocator support ([ticket 12459]).
|
||||
* Make the no argument constructors implicit.
|
||||
* Implement missing allocator aware constructors.
|
||||
* Fix assigning the hash/key equality functions for empty containers.
|
||||
* Remove unary/binary_function from the examples in the documentation.
|
||||
They are removed in C++17.
|
||||
* Support 10 constructor arguments in emplace. It was meant to support up to 10
|
||||
arguments, but an off by one error in the preprocessor code meant it only
|
||||
supported up to 9.
|
||||
|
||||
[h2 Boost 1.64.0]
|
||||
* Initial support for new C++17 member functions:
|
||||
`insert_or_assign` and `try_emplace` in `unordered_map`,
|
||||
* Initial support for `merge` and `extract`.
|
||||
Does not include transferring nodes between
|
||||
`unordered_map` and `unordered_multimap` or between `unordered_set` and
|
||||
`unordered_multiset` yet. That will hopefully be in the next version of
|
||||
Boost.
|
||||
|
||||
[h2 Boost 1.65.0]
|
||||
|
||||
* Add deprecated attributes to `quick_erase` and `erase_return_void`.
|
||||
I really will remove them in a future version this time.
|
||||
* Small standards compliance fixes:
|
||||
* `noexpect` specs for `swap` free functions.
|
||||
* Add missing `insert(P&&)` methods.
|
||||
|
||||
[h2 Boost 1.66.0]
|
||||
|
||||
* Simpler move construction implementation.
|
||||
* Documentation fixes ([pull_request 6]).
|
||||
|
||||
[h2 Boost 1.67.0]
|
||||
|
||||
* Improved C++17 support:
|
||||
* Add template deduction guides from the standard.
|
||||
* Use a simple implementation of `optional` in node handles, so
|
||||
that they're closer to the standard.
|
||||
* Add missing `noexcept` specifications to `swap`, `operator=`
|
||||
and node handles, and change the implementation to match.
|
||||
Using `std::allocator_traits::is_always_equal`, or our own
|
||||
implementation when not available, and
|
||||
`boost::is_nothrow_swappable` in the implementation.
|
||||
* Improved C++20 support:
|
||||
* Use `boost::to_address`, which has the proposed C++20 semantics,
|
||||
rather than the old custom implementation.
|
||||
* Add `element_type` to iterators, so that `std::pointer_traits`
|
||||
will work.
|
||||
* Use `std::piecewise_construct` on recent versions of Visual C++,
|
||||
and other uses of the Dinkumware standard library,
|
||||
now using Boost.Predef to check compiler and library versions.
|
||||
* Use `std::iterator_traits` rather than the boost iterator traits
|
||||
in order to remove dependency on Boost.Iterator.
|
||||
* Remove iterators' inheritance from `std::iterator`, which is
|
||||
deprecated in C++17, thanks to Daniela Engert
|
||||
([@https://github.com/boostorg/unordered/pull/7 PR#7]).
|
||||
* Stop using `BOOST_DEDUCED_TYPENAME`.
|
||||
* Update some Boost include paths.
|
||||
* Rename some internal methods, and variables.
|
||||
* Various testing improvements.
|
||||
* Miscellaneous internal changes.
|
||||
|
||||
[endsect]
|
||||
|
@ -1,10 +1,10 @@
|
||||
[/ Copyright 2006-2008 Daniel James.
|
||||
[/ Copyright 2006-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) ]
|
||||
|
||||
[section:comparison Comparison with Associative Containers]
|
||||
|
||||
[table Interface differences.
|
||||
[table:interface_differences Interface differences.
|
||||
[[Associative Containers] [Unordered Associative Containers]]
|
||||
|
||||
[
|
||||
@ -60,21 +60,18 @@
|
||||
[Iterators iterate through the container in the order defined by
|
||||
the comparison object.]
|
||||
[Iterators iterate through the container in an arbitrary order, that
|
||||
can change as elements are inserted. Although, equivalent elements
|
||||
can change as elements are inserted, although equivalent elements
|
||||
are always adjacent.]
|
||||
]
|
||||
[
|
||||
[No equivalent]
|
||||
[Local iterators can be used to iterate through individual buckets.
|
||||
(I don't think that the order of local iterators and iterators are
|
||||
(The order of local iterators and iterators aren't
|
||||
required to have any correspondence.)]
|
||||
]
|
||||
[
|
||||
[Can be compared using the `==`, `!=`, `<`, `<=`, `>`, `>=` operators.]
|
||||
[No comparison operators are defined in the standard, although
|
||||
[link unordered.rationale.equality_operators
|
||||
implementations might extend the containers to support `==` and
|
||||
`!=`].]
|
||||
[Can be compared using the `==` and `!=` operators.]
|
||||
]
|
||||
[
|
||||
[]
|
||||
@ -88,7 +85,7 @@
|
||||
]
|
||||
]
|
||||
|
||||
[table Complexity Guarantees
|
||||
[table:complexity_guarantees Complexity Guarantees
|
||||
[[Operation] [Associative Containers] [Unordered Associative Containers]]
|
||||
[
|
||||
[Construction of empty container]
|
||||
|
128
doc/compliance.qbk
Normal file
128
doc/compliance.qbk
Normal file
@ -0,0 +1,128 @@
|
||||
[/ Copyright 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) ]
|
||||
|
||||
[section:compliance Standard Compliance]
|
||||
|
||||
The intent of Boost.Unordered is to implement a close (but imperfect)
|
||||
implementation of the C++17 standard, that will work with C++98 upwards.
|
||||
The wide compatibility does mean some comprimises have to be made.
|
||||
With a compiler and library that fully support C++11, the differences should
|
||||
be minor.
|
||||
|
||||
[section:move Move emulation]
|
||||
|
||||
Support for move semantics is implemented using Boost.Move. If rvalue
|
||||
references are available it will use them, but if not it uses a close,
|
||||
but imperfect emulation. On such compilers:
|
||||
|
||||
* Non-copyable objects can be stored in the containers.
|
||||
They can be constructed in place using `emplace`, or if they support
|
||||
Boost.Move, moved into place.
|
||||
* The containers themselves are not movable.
|
||||
* Argument forwarding is not perfect.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:allocator_compliance Use of allocators]
|
||||
|
||||
C++11 introduced a new allocator system. It's backwards compatible due to
|
||||
the lax requirements for allocators in the old standard, but might need
|
||||
some changes for allocators which worked with the old versions of the
|
||||
unordered containers.
|
||||
It uses a traits class, `allocator_traits` to handle the allocator
|
||||
adding extra functionality, and making some methods and types optional.
|
||||
During development a stable release of
|
||||
`allocator_traits` wasn't available so an internal partial implementation
|
||||
is always used in this version. Hopefully a future version will use the
|
||||
standard implementation where available.
|
||||
|
||||
The member functions `construct`, `destroy` and `max_size` are now
|
||||
optional, if they're not available a fallback is used.
|
||||
A full implementation of `allocator_traits` requires sophisticated
|
||||
member function detection so that the fallback is used whenever the
|
||||
member function call is not well formed.
|
||||
This requires support for SFINAE expressions, which are available on
|
||||
GCC from version 4.4 and Clang.
|
||||
|
||||
On other compilers, there's just a test to see if the allocator has
|
||||
a member, but no check that it can be called. So rather than using a
|
||||
fallback there will just be a compile error.
|
||||
|
||||
`propagate_on_container_copy_assignment`,
|
||||
`propagate_on_container_move_assignment`,
|
||||
`propagate_on_container_swap` and
|
||||
`select_on_container_copy_construction` are also supported.
|
||||
Due to imperfect move emulation, some assignments might check
|
||||
`propagate_on_container_copy_assignment` on some compilers and
|
||||
`propagate_on_container_move_assignment` on others.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:construction Construction/Destruction using allocators]
|
||||
|
||||
The following support is required for full use of C++11 style
|
||||
construction/destruction:
|
||||
|
||||
* Variadic templates.
|
||||
* Piecewise construction of `std::pair`.
|
||||
* Either `std::allocator_traits` or expression SFINAE.
|
||||
|
||||
This is detected using Boost.Config. The macro
|
||||
`BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0
|
||||
otherwise.
|
||||
|
||||
When this is the case `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` will always be used, apart from when piecewise
|
||||
constructing a `std::pair` using `boost::tuple` (see [link
|
||||
unordered.compliance.pairs below]), but that should be easily avoided.
|
||||
|
||||
When support is not available `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` are never called.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pointer_traits Pointer Traits]
|
||||
|
||||
`pointer_traits` aren't used. Instead, pointer types are obtained from
|
||||
rebound allocators, this can cause problems if the allocator can't be
|
||||
used with incomplete types. If `const_pointer` is not defined in the
|
||||
allocator, `boost::pointer_to_other<pointer, const value_type>::type`
|
||||
is used to obtain a const pointer.
|
||||
|
||||
[endsect]
|
||||
|
||||
[#unordered.compliance.pairs]
|
||||
[section:pairs Pairs]
|
||||
|
||||
Since the containers use `std::pair` they're limited to the version
|
||||
from the current standard library. But since C++11 `std::pair`'s
|
||||
`piecewise_construct` based constructor is very useful, `emplace`
|
||||
emulates it with a `piecewise_construct` in the `boost::unordered`
|
||||
namespace. So for example, the following will work:
|
||||
|
||||
boost::unordered_multimap<std::string, std::complex> x;
|
||||
|
||||
x.emplace(
|
||||
boost::unordered::piecewise_construct,
|
||||
boost::make_tuple("key"), boost::make_tuple(1, 2));
|
||||
|
||||
Older drafts of the standard also supported variadic constructors
|
||||
for `std::pair`, where the first argument would be used for the
|
||||
first part of the pair, and the remaining for the second part.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:misc Miscellaneous]
|
||||
|
||||
When swapping, `Pred` and `Hash` are not currently swapped by calling
|
||||
`swap`, their copy constructors are used. As a consequence when swapping
|
||||
an exception may be thrown from their copy constructor.
|
||||
|
||||
Variadic constructor arguments for `emplace` are only used when both
|
||||
rvalue references and variadic template parameters are available.
|
||||
Otherwise `emplace` can only take up to 10 constructors arguments.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
@ -67,9 +67,10 @@ so that the hash function doesn't need to be explicitly given:
|
||||
|
||||
See the [link hash.custom Boost.Hash documentation] for more detail on how to
|
||||
do this. Remember that it relies on extensions to the draft standard - so it
|
||||
won't work on other implementations of the unordered associative containers.
|
||||
won't work for other implementations of the unordered associative containers,
|
||||
you'll need to explicitly use Boost.Hash.
|
||||
|
||||
[table Methods for accessing the hash and equality functions.
|
||||
[table:access_methods Methods for accessing the hash and equality functions.
|
||||
[[Method] [Description]]
|
||||
|
||||
[
|
||||
|
@ -2,15 +2,6 @@
|
||||
/ 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 __tr1__
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
|
||||
C++ Standard Library Technical Report]]
|
||||
[def __boost-tr1__
|
||||
[@http://www.boost.org/doc/html/boost_tr1.html
|
||||
Boost.TR1]]
|
||||
[def __draft__
|
||||
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2960.pdf
|
||||
Working Draft of the C++ Standard]]
|
||||
[def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table
|
||||
hash table]]
|
||||
[def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function
|
||||
@ -31,12 +22,10 @@ to order their elements. For some data types this is impossible to implement
|
||||
or isn't practical. In contrast, a hash table only needs an equality function
|
||||
and a hash function for the key.
|
||||
|
||||
With this in mind, the __tr1__ introduced the unordered associative containers,
|
||||
which are implemented using hash tables, and they have now been added to the
|
||||
__draft__.
|
||||
|
||||
This library supplies an almost complete implementation of the specification in
|
||||
the __draft__.
|
||||
With this in mind, unordered associative containers were added to the C++
|
||||
standard. This is an implementation of the containers described in C++11,
|
||||
with some [link unordered.compliance deviations from the standard] in
|
||||
order to work with non-C++11 compilers and libraries.
|
||||
|
||||
`unordered_set` and `unordered_multiset` are defined in the header
|
||||
<[headerref boost/unordered_set.hpp]>
|
||||
@ -65,14 +54,14 @@ the __draft__.
|
||||
class Key, class Mapped,
|
||||
class Hash = ``[classref boost::hash]``<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key> >
|
||||
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
||||
class ``[classref boost::unordered_map unordered_map]``;
|
||||
|
||||
template<
|
||||
class Key, class Mapped,
|
||||
class Hash = ``[classref boost::hash]``<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key> >
|
||||
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
||||
class ``[classref boost::unordered_multimap unordered_multimap]``;
|
||||
}
|
||||
|
||||
@ -95,7 +84,7 @@ can be in any order. For example, it might be:
|
||||
one,1
|
||||
three,3
|
||||
|
||||
To store an object in an unordered associative container requires both an
|
||||
To store an object in an unordered associative container requires both a
|
||||
key equality function and a hash function. The default function objects in
|
||||
the standard containers support a few basic types including integer types,
|
||||
floating point types, pointer types, and the standard strings. Since
|
||||
|
@ -3,7 +3,7 @@
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[def __wang__
|
||||
[@http://www.concentric.net/~Ttwang/tech/inthash.htm
|
||||
[@http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm
|
||||
Thomas Wang's article on integer hash functions]]
|
||||
|
||||
[section:rationale Implementation Rationale]
|
||||
@ -13,7 +13,7 @@ containers in the draft standard, so the interface was fixed. But there are
|
||||
still some implementation decisions to make. The priorities are
|
||||
conformance to the standard and portability.
|
||||
|
||||
The [@http://en.wikipedia.org/wiki/Hash_table wikipedia article on hash tables]
|
||||
The [@http://en.wikipedia.org/wiki/Hash_table Wikipedia article on hash tables]
|
||||
has a good summary of the implementation issues for hash tables in general.
|
||||
|
||||
[h2 Data Structure]
|
||||
@ -23,7 +23,7 @@ standard pretty much requires that the hash table uses chained addressing.
|
||||
|
||||
It would be conceivable to write a hash table that uses another method. For
|
||||
example, it could use open addressing, and use the lookup chain to act as a
|
||||
bucket but there are a some serious problems with this:
|
||||
bucket but there are some serious problems with this:
|
||||
|
||||
* The draft standard requires that pointers to elements aren't invalidated, so
|
||||
the elements can't be stored in one array, but will need a layer of
|
||||
@ -44,6 +44,8 @@ bucket but there are a some serious problems with this:
|
||||
|
||||
So chained addressing is used.
|
||||
|
||||
[/ (Removing for now as this is out of date)
|
||||
|
||||
For containers with unique keys I store the buckets in a single-linked list.
|
||||
There are other possible data structures (such as a double-linked list)
|
||||
that allow for some operations to be faster (such as erasing and iteration)
|
||||
@ -63,6 +65,17 @@ nodes in reverse order. This allows quick navigation to the end of a group (sinc
|
||||
the first element points to the last) and can be quickly updated when elements
|
||||
are inserted or erased. The main disadvantage of this approach is some hairy code
|
||||
for erasing elements.
|
||||
]
|
||||
|
||||
[/ (Starting to write up new structure, might not be ready in time)
|
||||
The node used to be stored in a linked list for each bucket but that
|
||||
didn't meet the complexity requirements for C++11, so now the nodes
|
||||
are stored in one long single linked list. But there needs a way to get
|
||||
the bucket from the node, to do that a copy of the key's hash value is
|
||||
stored in the node. Another possibility would be to store a pointer to
|
||||
the bucket, or the bucket's index, but storing the hash value allows
|
||||
some operations to be faster.
|
||||
]
|
||||
|
||||
[h2 Number of Buckets]
|
||||
|
||||
@ -72,70 +85,27 @@ of 2.
|
||||
|
||||
Using a prime number of buckets, and choosing a bucket by using the modulus
|
||||
of the hash function's result will usually give a good result. The downside
|
||||
is that the required modulus operation is fairly expensive.
|
||||
is that the required modulus operation is fairly expensive. This is what the
|
||||
containers do in most cases.
|
||||
|
||||
Using a power of 2 allows for much quicker selection of the bucket
|
||||
to use, but at the expense of loosing the upper bits of the hash value.
|
||||
to use, but at the expense of losing the upper bits of the hash value.
|
||||
For some specially designed hash functions it is possible to do this and
|
||||
still get a good result but as the containers can take arbitrary hash
|
||||
functions this can't be relied on.
|
||||
|
||||
To avoid this a transformation could be applied to the hash function, for an
|
||||
example see __wang__. Unfortunately, a transformation like Wang's requires
|
||||
knowledge of the number of bits in the hash value, so it isn't portable enough.
|
||||
This leaves more expensive methods, such as Knuth's Multiplicative Method
|
||||
(mentioned in Wang's article). These don't tend to work as well as taking the
|
||||
modulus of a prime, and the extra computation required might negate
|
||||
efficiency advantage of power of 2 hash tables.
|
||||
knowledge of the number of bits in the hash value, so it isn't portable enough
|
||||
to use as a default. It can applicable in certain cases so the containers
|
||||
have a policy based implementation that can use this alternative technique.
|
||||
|
||||
So, this implementation uses a prime number for the hash table size.
|
||||
Currently this is only done on 64 bit architectures, where prime number
|
||||
modulus can be expensive. Although this varies depending on the architecture,
|
||||
so I probably should revisit it.
|
||||
|
||||
[h2 Equality operators]
|
||||
|
||||
`operator==` and `operator!=` are not included in the standard, but I've
|
||||
added them as I think they could be useful and can be implemented
|
||||
fairly efficiently. They are specified differently to the other standard
|
||||
containers, comparing keys using the equality predicate rather than
|
||||
`operator==`.
|
||||
|
||||
It's also different to the proposal
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2944.pdf n2944].
|
||||
which uses the equality operators for the whole of `value_type`. This
|
||||
implementation just uses the key equality function for the key,
|
||||
and `mapped_type`'s equality operator in `unordered_map` and
|
||||
`unordered_multimap` for the mapped part of the element.
|
||||
|
||||
Also, in `unordered_multimap`, the mapped values for a group of elements with
|
||||
equivalent keys are only considered equal if they are in the same order,
|
||||
in n2944 they just need to be a permutation of each other. Since the
|
||||
order of elements with equal keys is now defined to be stable, it seems to me
|
||||
that their order can be considered part of the container's value.
|
||||
|
||||
[h2 Active Issues and Proposals]
|
||||
|
||||
[h3 C++0x allocators]
|
||||
|
||||
Recent drafts have included an overhaul of the allocators, but this was
|
||||
dependent on concepts which are no longer in the standard.
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2946.pdf n2946]
|
||||
attempts to respecify them without concepts. I'll try to implement this (or
|
||||
an appropriate later version) in a future version of boost, possibly changed
|
||||
a little to accomodate non-C++0x compilers.
|
||||
|
||||
[h3 Swapping containers with unequal allocators]
|
||||
|
||||
It isn't clear how to swap containers when their allocators aren't equal.
|
||||
This is
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#431
|
||||
Issue 431: Swapping containers with unequal allocators]. This has been resolved
|
||||
with the new allocator specification, so this should be fixed when
|
||||
support is added.
|
||||
|
||||
[h3 Are insert and erase stable for unordered_multiset and unordered_multimap?]
|
||||
|
||||
It wan't specified if `unordered_multiset` and `unordered_multimap` preserve the order
|
||||
of elements with equivalent keys (i.e. if they're stable under `insert` and `erase`).
|
||||
Since [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf
|
||||
n2691] it's been specified that they do and this implementation follows that.
|
||||
I'm also thinking of introducing a mechanism whereby a hash function can
|
||||
indicate that it's safe to be used directly with power of 2 buckets, in
|
||||
which case a faster plain power of 2 implementation can be used.
|
||||
|
||||
[endsect]
|
||||
|
1788
doc/ref.php
Normal file
1788
doc/ref.php
Normal file
File diff suppressed because it is too large
Load Diff
2820
doc/ref.xml
2820
doc/ref.xml
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,12 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "../../examples/fnv1.hpp"
|
||||
|
||||
//[case_insensitive_functions
|
||||
struct iequal_to
|
||||
: std::binary_function<std::string, std::string, bool>
|
||||
{
|
||||
bool operator()(std::string const& x,
|
||||
std::string const& y) const
|
||||
@ -20,7 +19,6 @@
|
||||
};
|
||||
|
||||
struct ihash
|
||||
: std::unary_function<std::string, std::size_t>
|
||||
{
|
||||
std::size_t operator()(std::string const& x) const
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
//[point_example1
|
||||
struct point {
|
||||
@ -18,7 +18,6 @@
|
||||
}
|
||||
|
||||
struct point_hash
|
||||
: std::unary_function<point, std::size_t>
|
||||
{
|
||||
std::size_t operator()(point const& p) const
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
//[point_example2
|
||||
struct point {
|
||||
|
@ -3,7 +3,8 @@
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[library Boost.Unordered
|
||||
[quickbook 1.4]
|
||||
[quickbook 1.7]
|
||||
[compatibility-mode 1.5]
|
||||
[authors [James, Daniel]]
|
||||
[copyright 2003 2004 Jeremy B. Maitin-Shepard]
|
||||
[copyright 2005 2006 2007 2008 Daniel James]
|
||||
@ -13,7 +14,7 @@
|
||||
[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]
|
||||
[@http://www.boost.org/LICENSE_1_0.txt])
|
||||
]
|
||||
]
|
||||
|
||||
@ -31,6 +32,7 @@
|
||||
[include:unordered buckets.qbk]
|
||||
[include:unordered hash_equality.qbk]
|
||||
[include:unordered comparison.qbk]
|
||||
[include:unordered compliance.qbk]
|
||||
[include:unordered rationale.qbk]
|
||||
[include:unordered changes.qbk]
|
||||
[xinclude ref.xml]
|
||||
|
@ -19,7 +19,6 @@
|
||||
namespace hash_examples
|
||||
{
|
||||
struct iequal_to
|
||||
: std::binary_function<std::string, std::string, bool>
|
||||
{
|
||||
iequal_to() {}
|
||||
explicit iequal_to(std::locale const& l) : locale_(l) {}
|
||||
@ -34,7 +33,6 @@ namespace hash_examples
|
||||
};
|
||||
|
||||
struct ihash
|
||||
: std::unary_function<std::string, std::size_t>
|
||||
{
|
||||
ihash() {}
|
||||
explicit ihash(std::locale const& l) : locale_(l) {}
|
||||
|
@ -4,7 +4,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./case_insensitive.hpp"
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
struct word_info {
|
||||
|
@ -1,111 +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 couple of templates to make using allocators easier.
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
|
||||
&& !defined(__BORLANDC__)
|
||||
# define BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
||||
# include <boost/detail/allocator_utilities.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
// rebind_wrap
|
||||
//
|
||||
// Rebind allocators. For some problematic libraries, use rebind_to
|
||||
// from <boost/detail/allocator_utilities.hpp>.
|
||||
|
||||
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
||||
template <class Alloc, class T>
|
||||
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
|
||||
#else
|
||||
template <class Alloc, class T>
|
||||
struct rebind_wrap
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
|
||||
type;
|
||||
};
|
||||
#endif
|
||||
|
||||
// allocator_array_constructor
|
||||
//
|
||||
// Allocate and construct an array in an exception safe manner, and
|
||||
// clean up if an exception is thrown before the container takes charge
|
||||
// of it.
|
||||
|
||||
template <class Allocator>
|
||||
struct allocator_array_constructor
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
|
||||
|
||||
Allocator& alloc_;
|
||||
pointer ptr_;
|
||||
pointer constructed_;
|
||||
std::size_t length_;
|
||||
|
||||
allocator_array_constructor(Allocator& a)
|
||||
: alloc_(a), ptr_(), constructed_(), length_(0)
|
||||
{
|
||||
constructed_ = pointer();
|
||||
ptr_ = pointer();
|
||||
}
|
||||
|
||||
~allocator_array_constructor() {
|
||||
if (ptr_) {
|
||||
for(pointer p = ptr_; p != constructed_; ++p)
|
||||
alloc_.destroy(p);
|
||||
|
||||
alloc_.deallocate(ptr_, length_);
|
||||
}
|
||||
}
|
||||
|
||||
template <class V>
|
||||
void construct(V const& v, std::size_t l)
|
||||
{
|
||||
BOOST_ASSERT(!ptr_);
|
||||
length_ = l;
|
||||
ptr_ = alloc_.allocate(length_);
|
||||
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
|
||||
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
|
||||
alloc_.construct(constructed_, v);
|
||||
}
|
||||
|
||||
pointer get() const
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
pointer release()
|
||||
{
|
||||
pointer p(ptr_);
|
||||
ptr_ = pointer();
|
||||
return p;
|
||||
}
|
||||
private:
|
||||
allocator_array_constructor(allocator_array_constructor const&);
|
||||
allocator_array_constructor& operator=(
|
||||
allocator_array_constructor const&);
|
||||
};
|
||||
}}
|
||||
|
||||
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
||||
# undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,183 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 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_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/node.hpp>
|
||||
#include <boost/unordered/detail/util.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Buckets
|
||||
|
||||
template <class A, class G>
|
||||
inline std::size_t hash_buckets<A, G>::max_bucket_count() const {
|
||||
// -1 to account for the sentinel.
|
||||
return prev_prime(this->bucket_alloc().max_size() - 1);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
|
||||
hash_buckets<A, G>::get_bucket(std::size_t num) const
|
||||
{
|
||||
return buckets_ + static_cast<std::ptrdiff_t>(num);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
|
||||
hash_buckets<A, G>::bucket_ptr_from_hash(std::size_t hashed) const
|
||||
{
|
||||
return get_bucket(hashed % bucket_count_);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
std::size_t hash_buckets<A, G>::bucket_size(std::size_t index) const
|
||||
{
|
||||
if(!buckets_) return 0;
|
||||
bucket_ptr ptr = get_bucket(index)->next_;
|
||||
std::size_t count = 0;
|
||||
while(ptr) {
|
||||
++count;
|
||||
ptr = ptr->next_;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::node_ptr
|
||||
hash_buckets<A, G>::bucket_begin(std::size_t num) const
|
||||
{
|
||||
return buckets_ ? get_bucket(num)->next_ : node_ptr();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Delete
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::delete_node(node_ptr b)
|
||||
{
|
||||
node* raw_ptr = static_cast<node*>(&*b);
|
||||
boost::unordered_detail::destroy(&raw_ptr->value());
|
||||
real_node_ptr n(node_alloc().address(*raw_ptr));
|
||||
node_alloc().destroy(n);
|
||||
node_alloc().deallocate(n, 1);
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::clear_bucket(bucket_ptr b)
|
||||
{
|
||||
node_ptr node_it = b->next_;
|
||||
b->next_ = node_ptr();
|
||||
|
||||
while(node_it) {
|
||||
node_ptr node_to_delete = node_it;
|
||||
node_it = node_it->next_;
|
||||
delete_node(node_to_delete);
|
||||
}
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::delete_buckets()
|
||||
{
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
|
||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||
clear_bucket(begin);
|
||||
}
|
||||
|
||||
// Destroy the buckets (including the sentinel bucket).
|
||||
++end;
|
||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||
bucket_alloc().destroy(begin);
|
||||
}
|
||||
|
||||
bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1);
|
||||
|
||||
this->buckets_ = bucket_ptr();
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline std::size_t hash_buckets<A, G>::delete_nodes(
|
||||
node_ptr begin, node_ptr end)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
while(begin != end) {
|
||||
node_ptr n = begin;
|
||||
begin = begin->next_;
|
||||
delete_node(n);
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors and Destructors
|
||||
|
||||
template <class A, class G>
|
||||
inline hash_buckets<A, G>::hash_buckets(
|
||||
node_allocator const& a, std::size_t bucket_count)
|
||||
: buckets_(),
|
||||
bucket_count_(bucket_count),
|
||||
allocators_(a,a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline hash_buckets<A, G>::~hash_buckets()
|
||||
{
|
||||
if(this->buckets_) { this->delete_buckets(); }
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::create_buckets()
|
||||
{
|
||||
// The array constructor will clean up in the event of an
|
||||
// exception.
|
||||
allocator_array_constructor<bucket_allocator>
|
||||
constructor(bucket_alloc());
|
||||
|
||||
// Creates an extra bucket to act as a sentinel.
|
||||
constructor.construct(bucket(), this->bucket_count_ + 1);
|
||||
|
||||
// Set up the sentinel (node_ptr cast)
|
||||
bucket_ptr sentinel = constructor.get() +
|
||||
static_cast<std::ptrdiff_t>(this->bucket_count_);
|
||||
sentinel->next_ = sentinel;
|
||||
|
||||
// Only release the buckets once everything is successfully
|
||||
// done.
|
||||
this->buckets_ = constructor.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors and Destructors
|
||||
|
||||
// no throw
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::move(hash_buckets& other)
|
||||
{
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
if(this->buckets_) { this->delete_buckets(); }
|
||||
this->buckets_ = other.buckets_;
|
||||
this->bucket_count_ = other.bucket_count_;
|
||||
other.buckets_ = bucket_ptr();
|
||||
other.bucket_count_ = 0;
|
||||
}
|
||||
|
||||
template <class A, class G>
|
||||
inline void hash_buckets<A, G>::swap(hash_buckets<A, G>& other)
|
||||
{
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
std::swap(buckets_, other.buckets_);
|
||||
std::swap(bucket_count_, other.bucket_count_);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,209 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 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_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
||||
|
||||
#include <boost/unordered/detail/table.hpp>
|
||||
#include <boost/unordered/detail/extract_key.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Equality
|
||||
|
||||
template <class T>
|
||||
bool hash_equivalent_table<T>
|
||||
::equals(hash_equivalent_table<T> const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
if(!this->size_) return true;
|
||||
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
|
||||
{
|
||||
node_ptr it1 = i->next_;
|
||||
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
|
||||
{
|
||||
node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
|
||||
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
|
||||
|
||||
node_ptr end1 = node::next_group(it1);
|
||||
node_ptr end2 = node::next_group(it2);
|
||||
|
||||
do {
|
||||
if(!extractor::compare_mapped(
|
||||
node::get_value(it1), node::get_value(it2)))
|
||||
return false;
|
||||
it1 = it1->next_;
|
||||
it2 = it2->next_;
|
||||
} while(it1 != end1 && it2 != end2);
|
||||
if(it1 != end1 || it2 != end2) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// A convenience method for adding nodes.
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::node_ptr
|
||||
hash_equivalent_table<T>
|
||||
::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos)
|
||||
{
|
||||
node_ptr n = a.release();
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
node::add_after_node(n, pos);
|
||||
}
|
||||
else {
|
||||
node::add_to_bucket(n, *bucket);
|
||||
if(bucket < this->cached_begin_bucket_)
|
||||
this->cached_begin_bucket_ = bucket;
|
||||
}
|
||||
++this->size_;
|
||||
return n;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert methods
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME
|
||||
hash_equivalent_table<T>::iterator_base
|
||||
hash_equivalent_table<T>::emplace_impl(node_constructor& a)
|
||||
{
|
||||
key_type const& k = this->get_key(a.value());
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
|
||||
if(!this->size_) {
|
||||
return this->emplace_empty_impl_with_node(a, 1);
|
||||
}
|
||||
else {
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr position = this->find_iterator(bucket, k);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
return iterator_base(bucket, add_node(a, bucket, position));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_equivalent_table<T>
|
||||
::emplace_impl_no_rehash(node_constructor& a)
|
||||
{
|
||||
key_type const& k = this->get_key(a.value());
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
add_node(a, bucket, this->find_iterator(bucket, k));
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
// Emplace (equivalent key containers)
|
||||
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class... Args>
|
||||
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base
|
||||
hash_equivalent_table<T>
|
||||
::emplace(Args&&... args)
|
||||
{
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
|
||||
return emplace_impl(a);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base \
|
||||
hash_equivalent_table<T> \
|
||||
::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
return emplace_impl(a); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class I>
|
||||
inline void hash_equivalent_table<T>
|
||||
::insert_for_range(I i, I j, forward_traversal_tag)
|
||||
{
|
||||
if(i == j) return;
|
||||
std::size_t distance = unordered_detail::distance(i, j);
|
||||
if(distance == 1) {
|
||||
emplace(*i);
|
||||
}
|
||||
else {
|
||||
node_constructor a(*this);
|
||||
|
||||
// Only require basic exception safety here
|
||||
if(this->size_) {
|
||||
this->reserve_for_insert(this->size_ + distance);
|
||||
}
|
||||
else {
|
||||
a.construct(*i++);
|
||||
this->emplace_empty_impl_with_node(a, distance);
|
||||
}
|
||||
|
||||
for (; i != j; ++i) {
|
||||
a.construct(*i);
|
||||
emplace_impl_no_rehash(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class I>
|
||||
inline void hash_equivalent_table<T>
|
||||
::insert_for_range(I i, I j, boost::incrementable_traversal_tag)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
for (; i != j; ++i) {
|
||||
a.construct(*i);
|
||||
emplace_impl(a);
|
||||
}
|
||||
}
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class I>
|
||||
void hash_equivalent_table<T>::insert_range(I i, I j)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
|
||||
iterator_traversal_tag;
|
||||
insert_for_range(i, j, iterator_traversal_tag);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,148 +0,0 @@
|
||||
|
||||
// Copyright (C) 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_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered_detail {
|
||||
|
||||
// key extractors
|
||||
//
|
||||
// no throw
|
||||
//
|
||||
// 'extract_key' is called with the emplace parameters to return a
|
||||
// key if available or 'no_key' is one isn't and will need to be
|
||||
// constructed. This could be done by overloading the emplace implementation
|
||||
// for the different cases, but that's a bit tricky on compilers without
|
||||
// variadic templates.
|
||||
|
||||
struct no_key {
|
||||
no_key() {}
|
||||
template <class T> no_key(T const&) {}
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
struct set_extractor
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
typedef ValueType key_type;
|
||||
|
||||
static key_type const& extract(key_type const& v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
static no_key extract()
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template <class... Args>
|
||||
static no_key extract(Args const&...)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
#else
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&, Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool compare_mapped(value_type const&, value_type const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Key, class ValueType>
|
||||
struct map_extractor
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::remove_const<Key>::type key_type;
|
||||
|
||||
static key_type const& extract(value_type const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
static key_type const& extract(key_type const& v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class Second>
|
||||
static key_type const& extract(std::pair<key_type, Second> const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
template <class Second>
|
||||
static key_type const& extract(
|
||||
std::pair<key_type const, Second> const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template <class Arg1, class... Args>
|
||||
static key_type const& extract(key_type const& k,
|
||||
Arg1 const&, Args const&...)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
static no_key extract(Args const&...)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#else
|
||||
template <class Arg1>
|
||||
static key_type const& extract(key_type const& k, Arg1 const&)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
static no_key extract()
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg, class Arg1>
|
||||
static no_key extract(Arg const&, Arg1 const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool compare_mapped(value_type const& x, value_type const& y)
|
||||
{
|
||||
return x.second == y.second;
|
||||
}
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
4952
include/boost/unordered/detail/implementation.hpp
Normal file
4952
include/boost/unordered/detail/implementation.hpp
Normal file
File diff suppressed because it is too large
Load Diff
67
include/boost/unordered/detail/map.hpp
Normal file
67
include/boost/unordered/detail/map.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
// Copyright (C) 2005-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)
|
||||
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <typename A, typename K, typename M, typename H, typename P>
|
||||
struct map
|
||||
{
|
||||
typedef boost::unordered::detail::map<A, K, M, H, P> types;
|
||||
|
||||
typedef std::pair<K const, M> value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef K const const_key_type;
|
||||
|
||||
typedef
|
||||
typename ::boost::unordered::detail::rebind_wrap<A, value_type>::type
|
||||
value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
|
||||
typedef boost::unordered::detail::pick_node<A, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table<types> table;
|
||||
typedef boost::unordered::detail::map_extractor<value_type> extractor;
|
||||
|
||||
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
|
||||
|
||||
typedef boost::unordered::iterator_detail::iterator<node> iterator;
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::l_iterator<node> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_map<node, K, M, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_map
|
||||
{
|
||||
typedef boost::unordered_map<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_multimap
|
||||
{
|
||||
typedef boost::unordered_multimap<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,243 +0,0 @@
|
||||
/*
|
||||
Copyright 2005-2007 Adobe Systems Incorporated
|
||||
|
||||
Use, modification and distribution are subject to the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
*/
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER
|
||||
#define BOOST_UNORDERED_DETAIL_MOVE_HEADER
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/mpl/or.hpp>
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#if defined(BOOST_NO_SFINAE)
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#elif defined(__GNUC__) && \
|
||||
(__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
|
||||
BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
|
||||
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
|
||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
namespace boost {
|
||||
namespace unordered_detail {
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
namespace move_detail {
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
template <typename T>
|
||||
struct class_has_move_assign {
|
||||
class type {
|
||||
typedef T& (T::*E)(T t);
|
||||
typedef char (&no_type)[1];
|
||||
typedef char (&yes_type)[2];
|
||||
template <E e> struct sfinae { typedef yes_type type; };
|
||||
template <class U>
|
||||
static typename sfinae<&U::operator=>::type test(int);
|
||||
template <class U>
|
||||
static no_type test(...);
|
||||
public:
|
||||
enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
|
||||
};
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
template<typename T>
|
||||
struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
class test_can_convert_anything { };
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*
|
||||
REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
|
||||
boost::is_convertible<T, T> fails to compile.
|
||||
*/
|
||||
|
||||
template <typename T, typename U>
|
||||
struct is_convertible : boost::mpl::or_<
|
||||
boost::is_same<T, U>,
|
||||
boost::is_convertible<T, U>
|
||||
> { };
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
} //namespace move_detail
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*!
|
||||
\ingroup move_related
|
||||
\brief move_from is used for move_ctors.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct move_from
|
||||
{
|
||||
explicit move_from(T& x) : source(x) { }
|
||||
T& source;
|
||||
private:
|
||||
move_from& operator=(move_from const&);
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*!
|
||||
\ingroup move_related
|
||||
\brief The is_movable trait can be used to identify movable types.
|
||||
*/
|
||||
template <typename T>
|
||||
struct is_movable : boost::mpl::and_<
|
||||
boost::is_convertible<move_from<T>, T>,
|
||||
move_detail::has_move_assign<T>,
|
||||
boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
|
||||
> { };
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
||||
|
||||
// On compilers which don't have adequate SFINAE support, treat most types as unmovable,
|
||||
// unless the trait is specialized.
|
||||
|
||||
template <typename T>
|
||||
struct is_movable : boost::mpl::false_ { };
|
||||
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#if !defined(BOOST_NO_SFINAE)
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*!
|
||||
\ingroup move_related
|
||||
\brief copy_sink and move_sink are used to select between overloaded operations according to
|
||||
whether type T is movable and convertible to type U.
|
||||
\sa move
|
||||
*/
|
||||
|
||||
template <typename T,
|
||||
typename U = T,
|
||||
typename R = void*>
|
||||
struct copy_sink : boost::enable_if<
|
||||
boost::mpl::and_<
|
||||
boost::unordered_detail::move_detail::is_convertible<T, U>,
|
||||
boost::mpl::not_<is_movable<T> >
|
||||
>,
|
||||
R
|
||||
>
|
||||
{ };
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*!
|
||||
\ingroup move_related
|
||||
\brief move_sink and copy_sink are used to select between overloaded operations according to
|
||||
whether type T is movable and convertible to type U.
|
||||
\sa move
|
||||
*/
|
||||
|
||||
template <typename T,
|
||||
typename U = T,
|
||||
typename R = void*>
|
||||
struct move_sink : boost::enable_if<
|
||||
boost::mpl::and_<
|
||||
boost::unordered_detail::move_detail::is_convertible<T, U>,
|
||||
is_movable<T>
|
||||
>,
|
||||
R
|
||||
>
|
||||
{ };
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*!
|
||||
\ingroup move_related
|
||||
\brief This version of move is selected when T is_movable . It in turn calls the move
|
||||
constructor. This call, with the help of the return value optimization, will cause x to be moved
|
||||
instead of copied to its destination. See adobe/test/move/main.cpp for examples.
|
||||
|
||||
*/
|
||||
template <typename T>
|
||||
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*!
|
||||
\ingroup move_related
|
||||
\brief This version of move is selected when T is not movable . The net result will be that
|
||||
x gets copied.
|
||||
*/
|
||||
template <typename T>
|
||||
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#else // BOOST_NO_SFINAE
|
||||
|
||||
// On compilers without SFINAE, define copy_sink to always use the copy function.
|
||||
|
||||
template <typename T,
|
||||
typename U = T,
|
||||
typename R = void*>
|
||||
struct copy_sink
|
||||
{
|
||||
typedef R type;
|
||||
};
|
||||
|
||||
// Always copy the element unless this is overloaded.
|
||||
|
||||
template <typename T>
|
||||
T& move(T& x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif // BOOST_NO_SFINAE
|
||||
|
||||
} // namespace unordered_detail
|
||||
} // namespace boost
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************/
|
@ -1,226 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 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)
|
||||
|
||||
// This contains the basic data structure, apart from the actual values. There's
|
||||
// no construction or deconstruction here. So this only depends on the pointer
|
||||
// type.
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582)
|
||||
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
|
||||
#else
|
||||
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// ungrouped node implementation
|
||||
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME ungrouped_node_base<A>::node_ptr&
|
||||
ungrouped_node_base<A>::next_group(node_ptr ptr)
|
||||
{
|
||||
return ptr->next_;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline std::size_t ungrouped_node_base<A>::group_count(node_ptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
|
||||
{
|
||||
n->next_ = b.next_;
|
||||
b.next_ = n;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::add_after_node(node_ptr n,
|
||||
node_ptr position)
|
||||
{
|
||||
n->next_ = position->next_;
|
||||
position->next_ = position;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b,
|
||||
node_ptr begin, node_ptr end)
|
||||
{
|
||||
node_ptr* pos = &b.next_;
|
||||
while(*pos != begin) pos = &(*pos)->next_;
|
||||
*pos = end;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
|
||||
{
|
||||
b.next_ = end;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
|
||||
{
|
||||
unlink_nodes(b, n, n->next_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// grouped node implementation
|
||||
|
||||
// If ptr is the first element in a group, return pointer to next group.
|
||||
// Otherwise returns a pointer to ptr.
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
|
||||
grouped_node_base<A>::next_group(node_ptr ptr)
|
||||
{
|
||||
return get(ptr).group_prev_->next_;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
|
||||
grouped_node_base<A>::first_in_group(node_ptr ptr)
|
||||
{
|
||||
while(next_group(ptr) == ptr)
|
||||
ptr = get(ptr).group_prev_;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline std::size_t grouped_node_base<A>::group_count(node_ptr ptr)
|
||||
{
|
||||
node_ptr start = ptr;
|
||||
std::size_t size = 0;
|
||||
do {
|
||||
++size;
|
||||
ptr = get(ptr).group_prev_;
|
||||
} while(ptr != start);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void grouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
|
||||
{
|
||||
n->next_ = b.next_;
|
||||
get(n).group_prev_ = n;
|
||||
b.next_ = n;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr pos)
|
||||
{
|
||||
n->next_ = next_group(pos);
|
||||
get(n).group_prev_ = get(pos).group_prev_;
|
||||
next_group(pos) = n;
|
||||
get(pos).group_prev_ = n;
|
||||
}
|
||||
|
||||
// Break a ciruclar list into two, with split as the beginning
|
||||
// of the second group (if split is at the beginning then don't
|
||||
// split).
|
||||
template <class A>
|
||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
|
||||
grouped_node_base<A>::split_group(node_ptr split)
|
||||
{
|
||||
node_ptr first = first_in_group(split);
|
||||
if(first == split) return split;
|
||||
|
||||
node_ptr last = get(first).group_prev_;
|
||||
get(first).group_prev_ = get(split).group_prev_;
|
||||
get(split).group_prev_ = last;
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
void grouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
|
||||
{
|
||||
node_ptr next = n->next_;
|
||||
node_ptr* pos = &next_group(n);
|
||||
|
||||
if(*pos != n) {
|
||||
// The node is at the beginning of a group.
|
||||
|
||||
// Find the previous node pointer:
|
||||
pos = &b.next_;
|
||||
while(*pos != n) pos = &next_group(*pos);
|
||||
|
||||
// Remove from group
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
||||
get(next).group_prev_ == n)
|
||||
{
|
||||
get(next).group_prev_ = get(n).group_prev_;
|
||||
}
|
||||
}
|
||||
else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
||||
get(next).group_prev_ == n)
|
||||
{
|
||||
// The deleted node is not at the end of the group, so
|
||||
// change the link from the next node.
|
||||
get(next).group_prev_ = get(n).group_prev_;
|
||||
}
|
||||
else {
|
||||
// The deleted node is at the end of the group, so the
|
||||
// first node in the group is pointing to it.
|
||||
// Find that to change its pointer.
|
||||
node_ptr x = get(n).group_prev_;
|
||||
while(get(x).group_prev_ != n) {
|
||||
x = get(x).group_prev_;
|
||||
}
|
||||
get(x).group_prev_ = get(n).group_prev_;
|
||||
}
|
||||
*pos = next;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
void grouped_node_base<A>::unlink_nodes(bucket& b,
|
||||
node_ptr begin, node_ptr end)
|
||||
{
|
||||
node_ptr* pos = &next_group(begin);
|
||||
|
||||
if(*pos != begin) {
|
||||
// The node is at the beginning of a group.
|
||||
|
||||
// Find the previous node pointer:
|
||||
pos = &b.next_;
|
||||
while(*pos != begin) pos = &next_group(*pos);
|
||||
|
||||
// Remove from group
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
|
||||
}
|
||||
else {
|
||||
node_ptr group1 = split_group(begin);
|
||||
if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
|
||||
node_ptr group2 = split_group(end);
|
||||
|
||||
if(begin == group2) {
|
||||
node_ptr end1 = get(group1).group_prev_;
|
||||
node_ptr end2 = get(group2).group_prev_;
|
||||
get(group1).group_prev_ = end2;
|
||||
get(group2).group_prev_ = end1;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pos = end;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
|
||||
{
|
||||
split_group(end);
|
||||
b.next_ = end;
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
66
include/boost/unordered/detail/set.hpp
Normal file
66
include/boost/unordered/detail/set.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
// Copyright (C) 2005-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)
|
||||
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
#include <boost/unordered/unordered_set_fwd.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <typename A, typename T, typename H, typename P> struct set
|
||||
{
|
||||
typedef boost::unordered::detail::set<A, T, H, P> types;
|
||||
|
||||
typedef T value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef T const const_key_type;
|
||||
|
||||
typedef
|
||||
typename ::boost::unordered::detail::rebind_wrap<A, value_type>::type
|
||||
value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
|
||||
typedef boost::unordered::detail::pick_node<A, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table<types> table;
|
||||
typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
||||
|
||||
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
|
||||
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_set<node, T, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_set<node, T, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A>
|
||||
class instantiate_set
|
||||
{
|
||||
typedef boost::unordered_set<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A>
|
||||
class instantiate_multiset
|
||||
{
|
||||
typedef boost::unordered_multiset<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,777 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 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_UNORDERED_DETAIL_ALL_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
|
||||
#include <boost/unordered/detail/buckets.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Helper methods
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
inline bool hash_table<T>::equal(
|
||||
key_type const& k, value_type const& v) const
|
||||
{
|
||||
return this->key_eq()(k, get_key(v));
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
template <class Key, class Pred>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr
|
||||
hash_table<T>::find_iterator(bucket_ptr bucket, Key const& k,
|
||||
Pred const& eq) const
|
||||
{
|
||||
node_ptr it = bucket->next_;
|
||||
while (BOOST_UNORDERED_BORLAND_BOOL(it) &&
|
||||
!eq(k, get_key(node::get_value(it))))
|
||||
{
|
||||
it = node::next_group(it);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr
|
||||
hash_table<T>::find_iterator(
|
||||
bucket_ptr bucket, key_type const& k) const
|
||||
{
|
||||
node_ptr it = bucket->next_;
|
||||
while (BOOST_UNORDERED_BORLAND_BOOL(it) &&
|
||||
!equal(k, node::get_value(it)))
|
||||
{
|
||||
it = node::next_group(it);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
// pre: this->buckets_
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr
|
||||
hash_table<T>::find_iterator(key_type const& k) const
|
||||
{
|
||||
return find_iterator(this->get_bucket(this->bucket_index(k)), k);
|
||||
}
|
||||
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME T::node_ptr*
|
||||
hash_table<T>::find_for_erase(
|
||||
bucket_ptr bucket, key_type const& k) const
|
||||
{
|
||||
node_ptr* it = &bucket->next_;
|
||||
while(BOOST_UNORDERED_BORLAND_BOOL(*it) &&
|
||||
!equal(k, node::get_value(*it)))
|
||||
{
|
||||
it = &node::next_group(*it);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Load methods
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
std::size_t hash_table<T>::max_size() const
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// size < mlf_ * count
|
||||
return double_to_size_t(ceil(
|
||||
(double) this->mlf_ * this->max_bucket_count())) - 1;
|
||||
}
|
||||
|
||||
// strong safety
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::bucket_index(
|
||||
key_type const& k) const
|
||||
{
|
||||
// hash_function can throw:
|
||||
return this->hash_function()(k) % this->bucket_count_;
|
||||
}
|
||||
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::calculate_max_load()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// Only resize when size >= mlf_ * count
|
||||
return double_to_size_t(ceil((double) mlf_ * this->bucket_count_));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::max_load_factor(float z)
|
||||
{
|
||||
BOOST_ASSERT(z > 0);
|
||||
mlf_ = (std::max)(z, minimum_max_load_factor);
|
||||
this->max_load_ = this->calculate_max_load();
|
||||
}
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::min_buckets_for_size(
|
||||
std::size_t size) const
|
||||
{
|
||||
BOOST_ASSERT(this->mlf_ != 0);
|
||||
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// size < mlf_ * count
|
||||
// => count > size / mlf_
|
||||
//
|
||||
// Or from rehash post-condition:
|
||||
// count > size / mlf_
|
||||
return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// recompute_begin_bucket
|
||||
|
||||
// init_buckets
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::init_buckets()
|
||||
{
|
||||
if (this->size_) {
|
||||
this->cached_begin_bucket_ = this->buckets_;
|
||||
while (!this->cached_begin_bucket_->next_)
|
||||
++this->cached_begin_bucket_;
|
||||
} else {
|
||||
this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_);
|
||||
}
|
||||
this->max_load_ = calculate_max_load();
|
||||
}
|
||||
|
||||
// After an erase cached_begin_bucket_ might be left pointing to
|
||||
// an empty bucket, so this is called to update it
|
||||
//
|
||||
// no throw
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::recompute_begin_bucket(bucket_ptr b)
|
||||
{
|
||||
BOOST_ASSERT(!(b < this->cached_begin_bucket_));
|
||||
|
||||
if(b == this->cached_begin_bucket_)
|
||||
{
|
||||
if (this->size_ != 0) {
|
||||
while (!this->cached_begin_bucket_->next_)
|
||||
++this->cached_begin_bucket_;
|
||||
} else {
|
||||
this->cached_begin_bucket_ =
|
||||
this->get_bucket(this->bucket_count_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is called when a range has been erased
|
||||
//
|
||||
// no throw
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::recompute_begin_bucket(
|
||||
bucket_ptr b1, bucket_ptr b2)
|
||||
{
|
||||
BOOST_ASSERT(!(b1 < this->cached_begin_bucket_) && !(b2 < b1));
|
||||
BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_));
|
||||
|
||||
if(b1 == this->cached_begin_bucket_ && !b1->next_)
|
||||
this->cached_begin_bucket_ = b2;
|
||||
}
|
||||
|
||||
// no throw
|
||||
template <class T>
|
||||
inline float hash_table<T>::load_factor() const
|
||||
{
|
||||
BOOST_ASSERT(this->bucket_count_ != 0);
|
||||
return static_cast<float>(this->size_)
|
||||
/ static_cast<float>(this->bucket_count_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(std::size_t num_buckets,
|
||||
hasher const& hf, key_equal const& eq, node_allocator const& a)
|
||||
: buckets(a, next_prime(num_buckets)),
|
||||
base(hf, eq),
|
||||
size_(),
|
||||
mlf_(1.0f),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Copy Construct with allocator
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(hash_table const& x,
|
||||
node_allocator const& a)
|
||||
: buckets(a, x.min_buckets_for_size(x.size_)),
|
||||
base(x),
|
||||
size_(x.size_),
|
||||
mlf_(x.mlf_),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
if(x.size_) {
|
||||
x.copy_buckets_to(*this);
|
||||
this->init_buckets();
|
||||
}
|
||||
}
|
||||
|
||||
// Move Construct
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(hash_table& x, move_tag)
|
||||
: buckets(x.node_alloc(), x.bucket_count_),
|
||||
base(x),
|
||||
size_(0),
|
||||
mlf_(1.0f),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
this->partial_swap(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
hash_table<T>::hash_table(hash_table& x,
|
||||
node_allocator const& a, move_tag)
|
||||
: buckets(a, x.bucket_count_),
|
||||
base(x),
|
||||
size_(0),
|
||||
mlf_(x.mlf_),
|
||||
cached_begin_bucket_(),
|
||||
max_load_(0)
|
||||
{
|
||||
if(a == x.node_alloc()) {
|
||||
this->partial_swap(x);
|
||||
}
|
||||
else if(x.size_) {
|
||||
x.copy_buckets_to(*this);
|
||||
this->size_ = x.size_;
|
||||
this->init_buckets();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
hash_table<T>& hash_table<T>::operator=(
|
||||
hash_table const& x)
|
||||
{
|
||||
hash_table tmp(x, this->node_alloc());
|
||||
this->fast_swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Swap & Move
|
||||
|
||||
// Swap
|
||||
//
|
||||
// Strong exception safety
|
||||
//
|
||||
// Can throw if hash or predicate object's copy constructor throws
|
||||
// or if allocators are unequal.
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::partial_swap(hash_table& x)
|
||||
{
|
||||
this->buckets::swap(x); // No throw
|
||||
std::swap(this->size_, x.size_);
|
||||
std::swap(this->mlf_, x.mlf_);
|
||||
std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_);
|
||||
std::swap(this->max_load_, x.max_load_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::fast_swap(hash_table& x)
|
||||
{
|
||||
// These can throw, but they only affect the function objects
|
||||
// that aren't in use so it is strongly exception safe, via.
|
||||
// double buffering.
|
||||
{
|
||||
set_hash_functions<hasher, key_equal> op1(*this, x);
|
||||
set_hash_functions<hasher, key_equal> op2(x, *this);
|
||||
op1.commit();
|
||||
op2.commit();
|
||||
}
|
||||
this->buckets::swap(x); // No throw
|
||||
std::swap(this->size_, x.size_);
|
||||
std::swap(this->mlf_, x.mlf_);
|
||||
std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_);
|
||||
std::swap(this->max_load_, x.max_load_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::slow_swap(hash_table& x)
|
||||
{
|
||||
if(this == &x) return;
|
||||
|
||||
{
|
||||
// These can throw, but they only affect the function objects
|
||||
// that aren't in use so it is strongly exception safe, via.
|
||||
// double buffering.
|
||||
set_hash_functions<hasher, key_equal> op1(*this, x);
|
||||
set_hash_functions<hasher, key_equal> op2(x, *this);
|
||||
|
||||
// Create new buckets in separate hash_buckets objects
|
||||
// which will clean up if anything throws an exception.
|
||||
// (all can throw, but with no effect as these are new objects).
|
||||
|
||||
buckets b1(this->node_alloc(), x.min_buckets_for_size(x.size_));
|
||||
if(x.size_) x.copy_buckets_to(b1);
|
||||
|
||||
buckets b2(x.node_alloc(), this->min_buckets_for_size(this->size_));
|
||||
if(this->size_) copy_buckets_to(b2);
|
||||
|
||||
// Modifying the data, so no throw from now on.
|
||||
|
||||
b1.swap(*this);
|
||||
b2.swap(x);
|
||||
op1.commit();
|
||||
op2.commit();
|
||||
}
|
||||
|
||||
std::swap(this->size_, x.size_);
|
||||
|
||||
if(this->buckets_) this->init_buckets();
|
||||
if(x.buckets_) x.init_buckets();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::swap(hash_table& x)
|
||||
{
|
||||
if(this->node_alloc() == x.node_alloc()) {
|
||||
if(this != &x) this->fast_swap(x);
|
||||
}
|
||||
else {
|
||||
this->slow_swap(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Move
|
||||
//
|
||||
// Strong exception safety (might change unused function objects)
|
||||
//
|
||||
// Can throw if hash or predicate object's copy constructor throws
|
||||
// or if allocators are unequal.
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::move(hash_table& x)
|
||||
{
|
||||
// This can throw, but it only affects the function objects
|
||||
// that aren't in use so it is strongly exception safe, via.
|
||||
// double buffering.
|
||||
set_hash_functions<hasher, key_equal> new_func_this(*this, x);
|
||||
|
||||
if(this->node_alloc() == x.node_alloc()) {
|
||||
this->buckets::move(x); // no throw
|
||||
this->size_ = x.size_;
|
||||
this->cached_begin_bucket_ = x.cached_begin_bucket_;
|
||||
this->max_load_ = x.max_load_;
|
||||
x.size_ = 0;
|
||||
}
|
||||
else {
|
||||
// Create new buckets in separate HASH_TABLE_DATA objects
|
||||
// which will clean up if anything throws an exception.
|
||||
// (all can throw, but with no effect as these are new objects).
|
||||
|
||||
buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_));
|
||||
if(x.size_) x.copy_buckets_to(b);
|
||||
|
||||
// Start updating the data here, no throw from now on.
|
||||
this->size_ = x.size_;
|
||||
b.swap(*this);
|
||||
this->init_buckets();
|
||||
}
|
||||
|
||||
// We've made it, the rest is no throw.
|
||||
this->mlf_ = x.mlf_;
|
||||
new_func_this.commit();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Reserve & Rehash
|
||||
|
||||
// basic exception safety
|
||||
template <class T>
|
||||
inline void hash_table<T>::create_for_insert(std::size_t size)
|
||||
{
|
||||
this->bucket_count_ = (std::max)(this->bucket_count_,
|
||||
this->min_buckets_for_size(size));
|
||||
this->create_buckets();
|
||||
this->init_buckets();
|
||||
}
|
||||
|
||||
// basic exception safety
|
||||
template <class T>
|
||||
inline bool hash_table<T>::reserve_for_insert(std::size_t size)
|
||||
{
|
||||
if(size >= max_load_) {
|
||||
std::size_t num_buckets
|
||||
= this->min_buckets_for_size((std::max)(size,
|
||||
this->size_ + (this->size_ >> 1)));
|
||||
if(num_buckets != this->bucket_count_) {
|
||||
rehash_impl(num_buckets);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise.
|
||||
|
||||
template <class T>
|
||||
inline void hash_table<T>::rehash(std::size_t min_buckets)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
if(!this->size_) {
|
||||
if(this->buckets_) this->delete_buckets();
|
||||
this->bucket_count_ = next_prime(min_buckets);
|
||||
}
|
||||
else {
|
||||
// no throw:
|
||||
min_buckets = next_prime((std::max)(min_buckets,
|
||||
double_to_size_t(floor(this->size_ / (double) mlf_)) + 1));
|
||||
if(min_buckets != this->bucket_count_) rehash_impl(min_buckets);
|
||||
}
|
||||
}
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>
|
||||
::rehash_impl(std::size_t num_buckets)
|
||||
{
|
||||
hasher const& hf = this->hash_function();
|
||||
std::size_t size = this->size_;
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
|
||||
buckets dst(this->node_alloc(), num_buckets);
|
||||
dst.create_buckets();
|
||||
|
||||
buckets src(this->node_alloc(), this->bucket_count_);
|
||||
src.swap(*this);
|
||||
this->size_ = 0;
|
||||
|
||||
for(bucket_ptr bucket = this->cached_begin_bucket_;
|
||||
bucket != end; ++bucket)
|
||||
{
|
||||
node_ptr group = bucket->next_;
|
||||
while(group) {
|
||||
// Move the first group of equivalent nodes in bucket to dst.
|
||||
|
||||
// This next line throws iff the hash function throws.
|
||||
bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
|
||||
hf(get_key_from_ptr(group)));
|
||||
|
||||
node_ptr& next_group = node::next_group(group);
|
||||
bucket->next_ = next_group;
|
||||
next_group = dst_bucket->next_;
|
||||
dst_bucket->next_ = group;
|
||||
group = bucket->next_;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the new nodes back into the container and setup the local
|
||||
// variables.
|
||||
this->size_ = size;
|
||||
dst.swap(*this); // no throw
|
||||
this->init_buckets();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// copy_buckets_to
|
||||
|
||||
// copy_buckets_to
|
||||
//
|
||||
// basic excpetion safety. If an exception is thrown this will
|
||||
// leave dst partially filled.
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>
|
||||
::copy_buckets_to(buckets& dst) const
|
||||
{
|
||||
BOOST_ASSERT(this->buckets_ && !dst.buckets_);
|
||||
|
||||
hasher const& hf = this->hash_function();
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
|
||||
node_constructor a(dst);
|
||||
dst.create_buckets();
|
||||
|
||||
// no throw:
|
||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) {
|
||||
// no throw:
|
||||
for(node_ptr it = i->next_; it;) {
|
||||
// hash function can throw.
|
||||
bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
|
||||
hf(get_key_from_ptr(it)));
|
||||
// throws, strong
|
||||
|
||||
node_ptr group_end = node::next_group(it);
|
||||
|
||||
a.construct(node::get_value(it));
|
||||
node_ptr n = a.release();
|
||||
node::add_to_bucket(n, *dst_bucket);
|
||||
|
||||
for(it = it->next_; it != group_end; it = it->next_) {
|
||||
a.construct(node::get_value(it));
|
||||
node::add_after_node(a.release(), n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Misc. key methods
|
||||
|
||||
// strong exception safety
|
||||
|
||||
// count
|
||||
//
|
||||
// strong exception safety, no side effects
|
||||
|
||||
template <class T>
|
||||
std::size_t hash_table<T>::count(key_type const& k) const
|
||||
{
|
||||
if(!this->size_) return 0;
|
||||
node_ptr it = find_iterator(k); // throws, strong
|
||||
return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0;
|
||||
}
|
||||
|
||||
// find
|
||||
//
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base
|
||||
hash_table<T>::find(key_type const& k) const
|
||||
{
|
||||
if(!this->size_) return this->end();
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr it = find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(it))
|
||||
return iterator_base(bucket, it);
|
||||
else
|
||||
return this->end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class Key, class Hash, class Pred>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base hash_table<T>::find(Key const& k,
|
||||
Hash const& h, Pred const& eq) const
|
||||
{
|
||||
if(!this->size_) return this->end();
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(h(k) % this->bucket_count_);
|
||||
node_ptr it = find_iterator(bucket, k, eq);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(it))
|
||||
return iterator_base(bucket, it);
|
||||
else
|
||||
return this->end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::value_type&
|
||||
hash_table<T>::at(key_type const& k) const
|
||||
{
|
||||
if(!this->size_)
|
||||
throw std::out_of_range("Unable to find key in unordered_map.");
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr it = find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(it))
|
||||
return node::get_value(it);
|
||||
else
|
||||
throw std::out_of_range("Unable to find key in unordered_map.");
|
||||
}
|
||||
|
||||
// equal_range
|
||||
//
|
||||
// strong exception safety, no side effects
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_pair
|
||||
hash_table<T>::equal_range(key_type const& k) const
|
||||
{
|
||||
if(!this->size_)
|
||||
return iterator_pair(this->end(), this->end());
|
||||
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr it = find_iterator(bucket, k);
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(it)) {
|
||||
iterator_base first(iterator_base(bucket, it));
|
||||
iterator_base second(first);
|
||||
second.increment_bucket(node::next_group(second.node_));
|
||||
return iterator_pair(first, second);
|
||||
}
|
||||
else {
|
||||
return iterator_pair(this->end(), this->end());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Erase methods
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::clear()
|
||||
{
|
||||
if(!this->size_) return;
|
||||
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||
this->clear_bucket(begin);
|
||||
}
|
||||
|
||||
this->size_ = 0;
|
||||
this->cached_begin_bucket_ = end;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline std::size_t hash_table<T>::erase_group(
|
||||
node_ptr* it, bucket_ptr bucket)
|
||||
{
|
||||
node_ptr pos = *it;
|
||||
node_ptr end = node::next_group(pos);
|
||||
*it = end;
|
||||
std::size_t count = this->delete_nodes(pos, end);
|
||||
this->size_ -= count;
|
||||
this->recompute_begin_bucket(bucket);
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::size_t hash_table<T>::erase_key(key_type const& k)
|
||||
{
|
||||
if(!this->size_) return 0;
|
||||
|
||||
// No side effects in initial section
|
||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
||||
node_ptr* it = this->find_for_erase(bucket, k);
|
||||
|
||||
// No throw.
|
||||
return *it ? this->erase_group(it, bucket) : 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hash_table<T>::erase(iterator_base r)
|
||||
{
|
||||
BOOST_ASSERT(r.node_);
|
||||
--this->size_;
|
||||
node::unlink_node(*r.bucket_, r.node_);
|
||||
this->delete_node(r.node_);
|
||||
// r has been invalidated but its bucket is still valid
|
||||
this->recompute_begin_bucket(r.bucket_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base
|
||||
hash_table<T>::erase_return_iterator(iterator_base r)
|
||||
{
|
||||
BOOST_ASSERT(r.node_);
|
||||
iterator_base next = r;
|
||||
next.increment();
|
||||
--this->size_;
|
||||
node::unlink_node(*r.bucket_, r.node_);
|
||||
this->delete_node(r.node_);
|
||||
// r has been invalidated but its bucket is still valid
|
||||
this->recompute_begin_bucket(r.bucket_, next.bucket_);
|
||||
return next;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME T::iterator_base
|
||||
hash_table<T>::erase_range(
|
||||
iterator_base r1, iterator_base r2)
|
||||
{
|
||||
if(r1 != r2)
|
||||
{
|
||||
BOOST_ASSERT(r1.node_);
|
||||
if (r1.bucket_ == r2.bucket_) {
|
||||
node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_);
|
||||
this->size_ -= this->delete_nodes(r1.node_, r2.node_);
|
||||
|
||||
// No need to call recompute_begin_bucket because
|
||||
// the nodes are only deleted from one bucket, which
|
||||
// still contains r2 after the erase.
|
||||
BOOST_ASSERT(r1.bucket_->next_);
|
||||
}
|
||||
else {
|
||||
bucket_ptr end_bucket = r2.node_ ?
|
||||
r2.bucket_ : this->get_bucket(this->bucket_count_);
|
||||
BOOST_ASSERT(r1.bucket_ < end_bucket);
|
||||
node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr());
|
||||
this->size_ -= this->delete_nodes(r1.node_, node_ptr());
|
||||
|
||||
bucket_ptr i = r1.bucket_;
|
||||
for(++i; i != end_bucket; ++i) {
|
||||
this->size_ -= this->delete_nodes(i->next_, node_ptr());
|
||||
i->next_ = node_ptr();
|
||||
}
|
||||
|
||||
if(r2.node_) {
|
||||
node_ptr first = r2.bucket_->next_;
|
||||
node::unlink_nodes(*r2.bucket_, r2.node_);
|
||||
this->size_ -= this->delete_nodes(first, r2.node_);
|
||||
}
|
||||
|
||||
// r1 has been invalidated but its bucket is still
|
||||
// valid.
|
||||
this->recompute_begin_bucket(r1.bucket_, end_bucket);
|
||||
}
|
||||
}
|
||||
|
||||
return r2;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME hash_table<T>::iterator_base
|
||||
hash_table<T>::emplace_empty_impl_with_node(
|
||||
node_constructor& a, std::size_t size)
|
||||
{
|
||||
key_type const& k = get_key(a.value());
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
if(this->buckets_) this->reserve_for_insert(size);
|
||||
else this->create_for_insert(size);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr n = a.release();
|
||||
node::add_to_bucket(n, *bucket);
|
||||
++this->size_;
|
||||
this->cached_begin_bucket_ = bucket;
|
||||
return iterator_base(bucket, n);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,387 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 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_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
||||
|
||||
#include <boost/unordered/detail/table.hpp>
|
||||
#include <boost/unordered/detail/extract_key.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Equality
|
||||
|
||||
template <class T>
|
||||
bool hash_unique_table<T>
|
||||
::equals(hash_unique_table<T> const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
if(!this->size_) return true;
|
||||
|
||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
|
||||
{
|
||||
node_ptr it1 = i->next_;
|
||||
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
|
||||
{
|
||||
node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
|
||||
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
|
||||
if(!extractor::compare_mapped(
|
||||
node::get_value(it1), node::get_value(it2)))
|
||||
return false;
|
||||
it1 = it1->next_;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// A convenience method for adding nodes.
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::node_ptr
|
||||
hash_unique_table<T>::add_node(node_constructor& a,
|
||||
bucket_ptr bucket)
|
||||
{
|
||||
node_ptr n = a.release();
|
||||
node::add_to_bucket(n, *bucket);
|
||||
++this->size_;
|
||||
if(bucket < this->cached_begin_bucket_)
|
||||
this->cached_begin_bucket_ = bucket;
|
||||
return n;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert methods
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::value_type&
|
||||
hash_unique_table<T>::operator[](key_type const& k)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
|
||||
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
if(!this->buckets_) {
|
||||
node_constructor a(*this);
|
||||
a.construct_pair(k, (mapped_type*) 0);
|
||||
return *this->emplace_empty_impl_with_node(a, 1);
|
||||
}
|
||||
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
return node::get_value(pos);
|
||||
}
|
||||
else {
|
||||
// Side effects only in this block.
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(*this);
|
||||
a.construct_pair(k, (mapped_type*) 0);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
// Nothing after this point can throw.
|
||||
|
||||
return node::get_value(add_node(a, bucket));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_impl_with_node(node_constructor& a)
|
||||
{
|
||||
// No side effects in this initial code
|
||||
key_type const& k = this->get_key(a.value());
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
// Found an existing key, return it (no throw).
|
||||
return emplace_return(iterator_base(bucket, pos), false);
|
||||
} else {
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
// Nothing after this point can throw.
|
||||
|
||||
return emplace_return(
|
||||
iterator_base(bucket, add_node(a, bucket)),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_impl(key_type const& k,
|
||||
Args&&... args)
|
||||
{
|
||||
// No side effects in this initial code
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
// Found an existing key, return it (no throw).
|
||||
return emplace_return(iterator_base(bucket, pos), false);
|
||||
|
||||
} else {
|
||||
// Doesn't already exist, add to bucket.
|
||||
// Side effects only in this block.
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->reserve_for_insert(this->size_ + 1))
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
|
||||
// Nothing after this point can throw.
|
||||
|
||||
return emplace_return(
|
||||
iterator_base(bucket, add_node(a, bucket)),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_impl(no_key, Args&&... args)
|
||||
{
|
||||
// Construct the node regardless - in order to get the key.
|
||||
// It will be discarded if it isn't used
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
return emplace_impl_with_node(a);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace_empty_impl(Args&&... args)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
a.construct(std::forward<Args>(args)...);
|
||||
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
inline BOOST_DEDUCED_TYPENAME \
|
||||
hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>::emplace_impl( \
|
||||
key_type const& k, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
std::size_t hash_value = this->hash_function()(k); \
|
||||
bucket_ptr bucket \
|
||||
= this->bucket_ptr_from_hash(hash_value); \
|
||||
node_ptr pos = this->find_iterator(bucket, k); \
|
||||
\
|
||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
|
||||
return emplace_return(iterator_base(bucket, pos), false); \
|
||||
} else { \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
\
|
||||
if(this->reserve_for_insert(this->size_ + 1)) \
|
||||
bucket = this->bucket_ptr_from_hash(hash_value); \
|
||||
\
|
||||
return emplace_return(iterator_base(bucket, \
|
||||
add_node(a, bucket)), true); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
inline BOOST_DEDUCED_TYPENAME \
|
||||
hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>:: \
|
||||
emplace_impl(no_key, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
return emplace_impl_with_node(a); \
|
||||
} \
|
||||
\
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
inline BOOST_DEDUCED_TYPENAME \
|
||||
hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>:: \
|
||||
emplace_empty_impl( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
node_constructor a(*this); \
|
||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
// Emplace (unique keys)
|
||||
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise
|
||||
|
||||
template <class T>
|
||||
template<class... Args>
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace(Args&&... args)
|
||||
{
|
||||
return this->size_ ?
|
||||
emplace_impl(
|
||||
extractor::extract(std::forward<Args>(args)...),
|
||||
std::forward<Args>(args)...) :
|
||||
emplace_empty_impl(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
template <class Arg0>
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
||||
hash_unique_table<T>::emplace(Arg0 const& arg0)
|
||||
{
|
||||
return this->size_ ?
|
||||
emplace_impl(extractor::extract(arg0), arg0) :
|
||||
emplace_empty_impl(arg0);
|
||||
}
|
||||
|
||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
||||
template <class T> \
|
||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return \
|
||||
hash_unique_table<T>::emplace( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
return this->size_ ? \
|
||||
emplace_impl(extractor::extract(arg0, arg1), \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \
|
||||
emplace_empty_impl( \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
|
||||
template <class T>
|
||||
template <class InputIt>
|
||||
inline void hash_unique_table<T>::insert_range_impl(
|
||||
key_type const&, InputIt i, InputIt j)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
|
||||
if(!this->size_) {
|
||||
a.construct(*i);
|
||||
this->emplace_empty_impl_with_node(a, 1);
|
||||
++i;
|
||||
if(i == j) return;
|
||||
}
|
||||
|
||||
do {
|
||||
// No side effects in this initial code
|
||||
// Note: can't use get_key as '*i' might not be value_type - it
|
||||
// could be a pair with first_types as key_type without const or a
|
||||
// different second_type.
|
||||
key_type const& k = extractor::extract(*i);
|
||||
std::size_t hash_value = this->hash_function()(k);
|
||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
node_ptr pos = this->find_iterator(bucket, k);
|
||||
|
||||
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||
// Doesn't already exist, add to bucket.
|
||||
// Side effects only in this block.
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
a.construct(*i);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
if(this->size_ + 1 >= this->max_load_) {
|
||||
this->reserve_for_insert(this->size_ + insert_size(i, j));
|
||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
||||
}
|
||||
|
||||
// Nothing after this point can throw.
|
||||
add_node(a, bucket);
|
||||
}
|
||||
} while(++i != j);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class InputIt>
|
||||
inline void hash_unique_table<T>::insert_range_impl(
|
||||
no_key, InputIt i, InputIt j)
|
||||
{
|
||||
node_constructor a(*this);
|
||||
|
||||
if(!this->size_) {
|
||||
a.construct(*i);
|
||||
this->emplace_empty_impl_with_node(a, 1);
|
||||
++i;
|
||||
if(i == j) return;
|
||||
}
|
||||
|
||||
do {
|
||||
// No side effects in this initial code
|
||||
a.construct(*i);
|
||||
emplace_impl_with_node(a);
|
||||
} while(++i != j);
|
||||
}
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
||||
// strong otherwise
|
||||
template <class T>
|
||||
template <class InputIt>
|
||||
void hash_unique_table<T>::insert_range(InputIt i, InputIt j)
|
||||
{
|
||||
if(i != j)
|
||||
return insert_range_impl(extractor::extract(*i), i, j);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
@ -1,323 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 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_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
|
||||
namespace boost { namespace unordered_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// convert double to std::size_t
|
||||
|
||||
inline std::size_t double_to_size_t(double f)
|
||||
{
|
||||
return f >= static_cast<double>(
|
||||
(std::numeric_limits<std::size_t>::max)()) ?
|
||||
(std::numeric_limits<std::size_t>::max)() :
|
||||
static_cast<std::size_t>(f);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// primes
|
||||
|
||||
template<class T> struct prime_list_template
|
||||
{
|
||||
static std::size_t const value[];
|
||||
static std::ptrdiff_t const length;
|
||||
};
|
||||
|
||||
#define BOOST_UNORDERED_PRIMES \
|
||||
(5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \
|
||||
(97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \
|
||||
(1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \
|
||||
(49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \
|
||||
(1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \
|
||||
(50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \
|
||||
(1610612741ul)(3221225473ul)(4294967291ul)
|
||||
|
||||
template<class T>
|
||||
std::size_t const prime_list_template<T>::value[] = {
|
||||
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)
|
||||
};
|
||||
|
||||
template<class T>
|
||||
std::ptrdiff_t const prime_list_template<T>::length
|
||||
= BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
|
||||
|
||||
#undef BOOST_UNORDERED_PRIMES
|
||||
|
||||
typedef prime_list_template<std::size_t> prime_list;
|
||||
|
||||
// no throw
|
||||
inline std::size_t next_prime(std::size_t num) {
|
||||
std::size_t const* const prime_list_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::lower_bound(prime_list_begin, prime_list_end, num);
|
||||
if(bound == prime_list_end)
|
||||
bound--;
|
||||
return *bound;
|
||||
}
|
||||
|
||||
// no throw
|
||||
inline std::size_t prev_prime(std::size_t num) {
|
||||
std::size_t const* const prime_list_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::upper_bound(prime_list_begin,prime_list_end, num);
|
||||
if(bound != prime_list_begin)
|
||||
bound--;
|
||||
return *bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// pair_cast - because some libraries don't have the full pair constructors.
|
||||
|
||||
template <class Dst1, class Dst2, class Src1, class Src2>
|
||||
inline std::pair<Dst1, Dst2> pair_cast(std::pair<Src1, Src2> const& x)
|
||||
{
|
||||
return std::pair<Dst1, Dst2>(Dst1(x.first), Dst2(x.second));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// insert_size/initial_size
|
||||
|
||||
#if !defined(BOOST_NO_STD_DISTANCE)
|
||||
using ::std::distance;
|
||||
#else
|
||||
template <class ForwardIterator>
|
||||
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
|
||||
std::size_t x;
|
||||
std::distance(i, j, x);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class I>
|
||||
inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag)
|
||||
{
|
||||
return std::distance(i, j);
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline std::size_t insert_size(I i, I j)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
|
||||
iterator_traversal_tag;
|
||||
return insert_size(i, j, iterator_traversal_tag);
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline std::size_t initial_size(I i, I j,
|
||||
std::size_t num_buckets = boost::unordered_detail::default_bucket_count)
|
||||
{
|
||||
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
|
||||
num_buckets);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Node Constructors
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
|
||||
template <class T, class... Args>
|
||||
inline void construct_impl(T*, void* address, Args&&... args)
|
||||
{
|
||||
new(address) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_CPP0X_PAIR)
|
||||
template <class First, class Second, class Key, class Arg0, class... Args>
|
||||
inline void construct_impl(std::pair<First, Second>*, void* address,
|
||||
Key&& k, Arg0&& arg0, Args&&... args)
|
||||
)
|
||||
{
|
||||
new(address) std::pair<First, Second>(k,
|
||||
Second(arg0, std::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
|
||||
template < \
|
||||
class T, \
|
||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||
> \
|
||||
inline void construct_impl( \
|
||||
T*, void* address, \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||
) \
|
||||
{ \
|
||||
new(address) T( \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||
} \
|
||||
\
|
||||
template <class First, class Second, class Key, \
|
||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||
> \
|
||||
inline void construct_impl( \
|
||||
std::pair<First, Second>*, void* address, \
|
||||
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||
{ \
|
||||
new(address) std::pair<First, Second>(k, \
|
||||
Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
|
||||
#endif
|
||||
|
||||
// hash_node_constructor
|
||||
//
|
||||
// Used to construct nodes in an exception safe manner.
|
||||
|
||||
template <class Alloc, class Grouped>
|
||||
class hash_node_constructor
|
||||
{
|
||||
typedef hash_buckets<Alloc, Grouped> buckets;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr;
|
||||
typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type;
|
||||
|
||||
buckets& buckets_;
|
||||
real_node_ptr node_;
|
||||
bool node_constructed_;
|
||||
bool value_constructed_;
|
||||
|
||||
public:
|
||||
|
||||
hash_node_constructor(buckets& m) :
|
||||
buckets_(m),
|
||||
node_(),
|
||||
node_constructed_(false),
|
||||
value_constructed_(false)
|
||||
{
|
||||
}
|
||||
|
||||
~hash_node_constructor();
|
||||
void construct_preamble();
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template <class... Args>
|
||||
void construct(Args&&... args)
|
||||
{
|
||||
construct_preamble();
|
||||
construct_impl((value_type*) 0, node_->address(),
|
||||
std::forward<Args>(args)...);
|
||||
value_constructed_ = true;
|
||||
}
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \
|
||||
template < \
|
||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||
> \
|
||||
void construct( \
|
||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||
) \
|
||||
{ \
|
||||
construct_preamble(); \
|
||||
construct_impl( \
|
||||
(value_type*) 0, node_->address(), \
|
||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
||||
); \
|
||||
value_constructed_ = true; \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_CONSTRUCT, _)
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT
|
||||
|
||||
#endif
|
||||
template <class K, class M>
|
||||
void construct_pair(K const& k, M*)
|
||||
{
|
||||
construct_preamble();
|
||||
new(node_->address()) value_type(k, M());
|
||||
value_constructed_ = true;
|
||||
}
|
||||
|
||||
value_type& value() const
|
||||
{
|
||||
BOOST_ASSERT(node_);
|
||||
return node_->value();
|
||||
}
|
||||
|
||||
// no throw
|
||||
BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
|
||||
{
|
||||
real_node_ptr p = node_;
|
||||
node_ = real_node_ptr();
|
||||
// node_ptr cast
|
||||
return buckets_.bucket_alloc().address(*p);
|
||||
}
|
||||
|
||||
private:
|
||||
hash_node_constructor(hash_node_constructor const&);
|
||||
hash_node_constructor& operator=(hash_node_constructor const&);
|
||||
};
|
||||
|
||||
// hash_node_constructor
|
||||
|
||||
template <class Alloc, class Grouped>
|
||||
inline hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
|
||||
{
|
||||
if (node_) {
|
||||
if (value_constructed_) {
|
||||
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
|
||||
struct dummy { hash_node<Alloc, Grouped> x; };
|
||||
#endif
|
||||
boost::unordered_detail::destroy(&node_->value());
|
||||
}
|
||||
|
||||
if (node_constructed_)
|
||||
buckets_.node_alloc().destroy(node_);
|
||||
|
||||
buckets_.node_alloc().deallocate(node_, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Alloc, class Grouped>
|
||||
inline void hash_node_constructor<Alloc, Grouped>::construct_preamble()
|
||||
{
|
||||
if(!node_) {
|
||||
node_constructed_ = false;
|
||||
value_constructed_ = false;
|
||||
|
||||
node_ = buckets_.node_alloc().allocate(1);
|
||||
buckets_.node_alloc().construct(node_, node());
|
||||
node_constructed_ = true;
|
||||
}
|
||||
else {
|
||||
BOOST_ASSERT(node_constructed_ && value_constructed_);
|
||||
boost::unordered_detail::destroy(&node_->value());
|
||||
value_constructed_ = false;
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,53 +1,64 @@
|
||||
|
||||
// Copyright (C) 2008-2009 Daniel James.
|
||||
// Copyright (C) 2008-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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_MAP_FWD_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_MAP_FWD_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class K,
|
||||
class T,
|
||||
class H = hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
template <class K, class T, class H = boost::hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_map;
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator==(unordered_map<K, T, H, P, A> const&,
|
||||
unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator!=(unordered_map<K, T, H, P, A> const&,
|
||||
unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void swap(unordered_map<K, T, H, P, A>&,
|
||||
unordered_map<K, T, H, P, A>&);
|
||||
|
||||
template <class K,
|
||||
class T,
|
||||
class H = hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator==(
|
||||
unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator!=(
|
||||
unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_map<K, T, H, P, A>& m1, unordered_map<K, T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
template <class K, class T, class H = boost::hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_multimap;
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator==(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void swap(unordered_multimap<K, T, H, P, A>&,
|
||||
unordered_multimap<K, T, H, P, A>&);
|
||||
inline void swap(unordered_multimap<K, T, H, P, A>& m1,
|
||||
unordered_multimap<K, T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
template <class N, class K, class T, class A> class node_handle_map;
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_map;
|
||||
using boost::unordered::unordered_multimap;
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +1,62 @@
|
||||
|
||||
// Copyright (C) 2008-2009 Daniel James.
|
||||
// Copyright (C) 2008-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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_SET_FWD_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_SET_FWD_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class T,
|
||||
class H = hash<T>,
|
||||
class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
template <class T, class H = boost::hash<T>, class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_set;
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator==(unordered_set<T, H, P, A> const&,
|
||||
unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator!=(unordered_set<T, H, P, A> const&,
|
||||
unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
void swap(unordered_set<T, H, P, A> &m1,
|
||||
unordered_set<T, H, P, A> &m2);
|
||||
|
||||
template <class T,
|
||||
class H = hash<T>,
|
||||
class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator==(
|
||||
unordered_set<T, H, P, A> const&, unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator!=(
|
||||
unordered_set<T, H, P, A> const&, unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_set<T, H, P, A>& m1, unordered_set<T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
template <class T, class H = boost::hash<T>, class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_multiset;
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator==(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
inline bool operator==(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
void swap(unordered_multiset<T, H, P, A> &m1,
|
||||
unordered_multiset<T, H, P, A> &m2);
|
||||
inline void swap(
|
||||
unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
template <class N, class T, class A> class node_handle_set;
|
||||
template <class N, class T, class A> struct insert_return_type_set;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_set;
|
||||
using boost::unordered::unordered_multiset;
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,8 +9,9 @@
|
||||
#ifndef BOOST_UNORDERED_MAP_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_MAP_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/unordered_map.hpp>
|
||||
|
@ -9,8 +9,9 @@
|
||||
#ifndef BOOST_UNORDERED_SET_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_SET_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/unordered_set.hpp>
|
||||
|
44
meta/explicit-failures-markup.xml
Normal file
44
meta/explicit-failures-markup.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2017-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>
|
||||
<!-- unordered -->
|
||||
<library name="unordered">
|
||||
<mark-expected-failures>
|
||||
<test name="unnecessary_copy_tests"/>
|
||||
<toolset name="borland-*"/>
|
||||
<toolset name="sun-*"/>
|
||||
<note author="Daniel James">
|
||||
This tests whether inserting elements creates as few copies as I think
|
||||
is possible. If this fails it just means that the container might be
|
||||
a little inefficient.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="compile_map_unordered_allocator"/>
|
||||
<toolset name="msvc-7.1"/>
|
||||
<note author="Daniel James">
|
||||
This test fail because it's using unordered's internal
|
||||
allocator traits, which doesn't work on Visual C++ 7.1.
|
||||
It normally uses the one from Boost.Container by default.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="noexcept_tests"/>
|
||||
<toolset name="gcc-4.3c+"/>
|
||||
<note author="Daniel James">
|
||||
boost::is_nothrow_move_constructible and
|
||||
boost::is_nothrow_move_assignable don't seem to work on this
|
||||
compiler. I'd hope that anyone wanting noexcept support would
|
||||
use a more recent compiler anyway.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
</library>
|
||||
</explicit-failures-markup>
|
||||
|
17
meta/libraries.json
Normal file
17
meta/libraries.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"key": "unordered",
|
||||
"name": "Unordered",
|
||||
"authors": [
|
||||
"Daniel James"
|
||||
],
|
||||
"maintainers": [
|
||||
"Daniel James <dnljms -at- gmail.com>"
|
||||
],
|
||||
"description": "Unordered associative containers.",
|
||||
"std": [
|
||||
"tr1"
|
||||
],
|
||||
"category": [
|
||||
"Containers"
|
||||
]
|
||||
}
|
@ -5,5 +5,93 @@
|
||||
|
||||
import testing ;
|
||||
|
||||
build-project unordered ;
|
||||
build-project exception ;
|
||||
project unordered-test/unordered
|
||||
: requirements
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
# Would be nice to define -Wundef, but I'm getting warnings from
|
||||
# Boost.Preprocessor on trunk.
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>clang:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>msvc:<cxxflags>"/wd4494"
|
||||
<toolset>gcc:<c++-template-depth>500
|
||||
;
|
||||
|
||||
#alias framework : /boost/test//boost_unit_test_framework ;
|
||||
alias framework : ;
|
||||
|
||||
test-suite unordered
|
||||
:
|
||||
[ run unordered/fwd_set_test.cpp ]
|
||||
[ run unordered/fwd_map_test.cpp ]
|
||||
[ run unordered/allocator_traits.cpp ]
|
||||
[ run unordered/minimal_allocator.cpp ]
|
||||
[ run unordered/compile_set.cpp ]
|
||||
[ run unordered/compile_map.cpp ]
|
||||
[ run unordered/compile_map.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_ALLOCATOR_TRAITS=0
|
||||
: compile_map_unordered_allocator ]
|
||||
[ run unordered/noexcept_tests.cpp ]
|
||||
[ run unordered/link_test_1.cpp unordered/link_test_2.cpp ]
|
||||
[ run unordered/incomplete_test.cpp ]
|
||||
[ run unordered/simple_tests.cpp ]
|
||||
[ run unordered/equivalent_keys_tests.cpp ]
|
||||
[ run unordered/constructor_tests.cpp ]
|
||||
[ run unordered/copy_tests.cpp ]
|
||||
[ run unordered/move_tests.cpp ]
|
||||
[ run unordered/assign_tests.cpp ]
|
||||
[ run unordered/insert_tests.cpp ]
|
||||
[ run unordered/insert_stable_tests.cpp ]
|
||||
[ run unordered/insert_hint_tests.cpp ]
|
||||
[ run unordered/emplace_tests.cpp ]
|
||||
[ run unordered/unnecessary_copy_tests.cpp ]
|
||||
[ run unordered/erase_tests.cpp : : : <define>BOOST_UNORDERED_SUPPRESS_DEPRECATED ]
|
||||
[ run unordered/erase_equiv_tests.cpp ]
|
||||
[ run unordered/extract_tests.cpp ]
|
||||
[ run unordered/node_handle_tests.cpp ]
|
||||
[ run unordered/merge_tests.cpp ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MAP : insert_node_type_fail_map ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_SET : insert_node_type_fail_set ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ]
|
||||
[ run unordered/find_tests.cpp ]
|
||||
[ run unordered/at_tests.cpp ]
|
||||
[ run unordered/bucket_tests.cpp ]
|
||||
[ run unordered/load_factor_tests.cpp ]
|
||||
[ run unordered/rehash_tests.cpp ]
|
||||
[ run unordered/equality_tests.cpp ]
|
||||
[ run unordered/swap_tests.cpp ]
|
||||
[ run unordered/detail_tests.cpp ]
|
||||
[ run unordered/deduction_tests.cpp ]
|
||||
|
||||
[ run unordered/compile_set.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_compile_set ]
|
||||
[ run unordered/compile_map.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_compile_map ]
|
||||
[ run unordered/copy_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_copy ]
|
||||
[ run unordered/move_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_move ]
|
||||
[ run unordered/assign_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_assign ]
|
||||
;
|
||||
|
||||
test-suite unordered-exception
|
||||
:
|
||||
[ run exception/constructor_exception_tests.cpp framework ]
|
||||
[ run exception/copy_exception_tests.cpp framework ]
|
||||
[ run exception/assign_exception_tests.cpp framework ]
|
||||
[ run exception/move_assign_exception_tests.cpp framework ]
|
||||
[ run exception/insert_exception_tests.cpp framework ]
|
||||
[ run exception/erase_exception_tests.cpp framework ]
|
||||
[ run exception/rehash_exception_tests.cpp framework ]
|
||||
[ run exception/swap_exception_tests.cpp framework : : :
|
||||
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
|
||||
[ run exception/merge_exception_tests.cpp framework ]
|
||||
;
|
||||
|
@ -1,34 +0,0 @@
|
||||
|
||||
# Copyright 2006-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)
|
||||
|
||||
import testing ;
|
||||
|
||||
#alias framework : /boost/test//boost_unit_test_framework ;
|
||||
alias framework : ;
|
||||
|
||||
project unordered-test/exception-tests
|
||||
: requirements
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>gcc:<define>_GLIBCXX_DEBUG
|
||||
<toolset>darwin:<define>_GLIBCXX_DEBUG
|
||||
<toolset>msvc:<warnings-as-errors>on
|
||||
#<toolset>gcc:<warnings-as-errors>on
|
||||
#<toolset>darwin:<warnings-as-errors>on
|
||||
;
|
||||
|
||||
test-suite unordered-exception
|
||||
:
|
||||
[ run constructor_exception_tests.cpp framework ]
|
||||
[ run copy_exception_tests.cpp framework ]
|
||||
[ run assign_exception_tests.cpp framework ]
|
||||
[ run insert_exception_tests.cpp framework ]
|
||||
[ run erase_exception_tests.cpp framework ]
|
||||
[ run rehash_exception_tests.cpp framework ]
|
||||
[ run swap_exception_tests.cpp framework : : :
|
||||
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
|
||||
;
|
@ -3,91 +3,183 @@
|
||||
// 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
#pragma warning(disable : 4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t seed(12847);
|
||||
test::seed_t initialize_seed(12847);
|
||||
|
||||
template <class T>
|
||||
struct self_assign_base : public test::exception_base
|
||||
template <class T> struct self_assign_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
self_assign_base(int count = 0) : values(count) {}
|
||||
test::random_values<T> values;
|
||||
self_assign_base(std::size_t count = 0) : values(count, test::limited_range)
|
||||
{
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
void run(T& x) const { x = x; }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{ test::check_equivalent_keys(x); }
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
|
||||
void run(T& x) const
|
||||
{
|
||||
x = x;
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct self_assign_test1 : self_assign_base<T> {};
|
||||
|
||||
template <class T>
|
||||
struct self_assign_test2 : self_assign_base<T>
|
||||
template <class T> struct self_assign_test1 : self_assign_base<T>
|
||||
{
|
||||
self_assign_test2() : self_assign_base<T>(100) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_base : public test::exception_base
|
||||
template <class T> struct self_assign_test2 : self_assign_base<T>
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
const T x,y;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
|
||||
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2) :
|
||||
x_values(count1),
|
||||
y_values(count2),
|
||||
x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1),
|
||||
allocator_type(tag1)),
|
||||
y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2),
|
||||
allocator_type(tag2))
|
||||
{}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(x); }
|
||||
void run(T& x1) const { x1 = y; }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{ test::check_equivalent_keys(x1); }
|
||||
self_assign_test2() : self_assign_base<T>(100) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test1 : assign_base<T>
|
||||
template <class T> struct assign_base : public test::exception_base
|
||||
{
|
||||
assign_test1() : assign_base<T>(0, 0, 0, 0) {}
|
||||
test::random_values<T> x_values, y_values;
|
||||
T x, y;
|
||||
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: x_values(), y_values(),
|
||||
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(x); }
|
||||
|
||||
void run(T& x1) const
|
||||
{
|
||||
x1 = y;
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x1, y_values);
|
||||
test::check_equivalent_keys(x1);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it, at the cost of
|
||||
// messing up the data.
|
||||
if (x_values.size()) {
|
||||
T& x2 = const_cast<T&>(x1);
|
||||
x2.emplace(*x_values.begin());
|
||||
test::check_equivalent_keys(x2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test2 : assign_base<T>
|
||||
template <class T> struct assign_values : assign_base<T>
|
||||
{
|
||||
assign_test2() : assign_base<T>(60, 0, 0, 0) {}
|
||||
assign_values(unsigned int count1, unsigned int count2, int tag1, int tag2,
|
||||
test::random_generator gen = test::default_generator, float mlf1 = 1.0,
|
||||
float mlf2 = 1.0)
|
||||
: assign_base<T>(tag1, tag2, mlf1, mlf2)
|
||||
{
|
||||
this->x_values.fill(count1, gen);
|
||||
this->y_values.fill(count2, gen);
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test3 : assign_base<T>
|
||||
template <class T> struct assign_test1 : assign_values<T>
|
||||
{
|
||||
assign_test3() : assign_base<T>(0, 60, 0, 0) {}
|
||||
assign_test1() : assign_values<T>(0, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test4 : assign_base<T>
|
||||
template <class T> struct assign_test2 : assign_values<T>
|
||||
{
|
||||
assign_test4() : assign_base<T>(10, 10, 1, 2) {}
|
||||
assign_test2() : assign_values<T>(60, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
template <class T> struct assign_test2a : assign_values<T>
|
||||
{
|
||||
assign_test2a() : assign_values<T>(60, 0, 0, 0, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test3 : assign_values<T>
|
||||
{
|
||||
assign_test3() : assign_values<T>(0, 60, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test3a : assign_values<T>
|
||||
{
|
||||
assign_test3a() : assign_values<T>(0, 60, 0, 0, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test4 : assign_values<T>
|
||||
{
|
||||
assign_test4() : assign_values<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test4a : assign_values<T>
|
||||
{
|
||||
assign_test4a() : assign_values<T>(10, 100, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test4b : assign_values<T>
|
||||
{
|
||||
assign_test4b() : assign_values<T>(10, 100, 1, 2, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test5 : assign_values<T>
|
||||
{
|
||||
assign_test5()
|
||||
: assign_values<T>(5, 60, 0, 0, test::default_generator, 1.0f, 0.1f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct equivalent_test1 : assign_base<T>
|
||||
{
|
||||
equivalent_test1() : assign_base<T>(0, 0)
|
||||
{
|
||||
test::random_values<T> x_values2(10);
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
test::random_values<T> y_values2(10);
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS_REPEAT(5,
|
||||
(self_assign_test1)(self_assign_test2)
|
||||
(assign_test1)(assign_test2)(assign_test3)(assign_test4),
|
||||
(assign_test1)(assign_test2)(assign_test2a)
|
||||
(assign_test3)(assign_test3a)
|
||||
(assign_test4)(assign_test4a)(assign_test4b)
|
||||
(assign_test5)
|
||||
(equivalent_test1),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,148 +3,210 @@
|
||||
// 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
|
||||
test::seed_t seed(91274);
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
template <typename T> inline void avoid_unused_warning(T const&) {}
|
||||
|
||||
test::seed_t initialize_seed(91274);
|
||||
|
||||
struct objects
|
||||
{
|
||||
test::exception::object obj;
|
||||
test::exception::hash hash;
|
||||
test::exception::equal_to equal_to;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
test::exception::object obj;
|
||||
test::exception::hash hash;
|
||||
test::exception::equal_to equal_to;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test1 : public objects, test::exception_base
|
||||
template <class T> struct construct_test1 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x;
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x;
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test2 : public objects, test::exception_base
|
||||
template <class T> struct construct_test2 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(300);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(300);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test3 : public objects, test::exception_base
|
||||
template <class T> struct construct_test3 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(0, hash);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(0, hash);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test4 : public objects, test::exception_base
|
||||
template <class T> struct construct_test4 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(0, hash, equal_to);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(0, hash, equal_to);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test5 : public objects, test::exception_base
|
||||
template <class T> struct construct_test5 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(50, hash, equal_to, allocator);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(50, hash, equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test6 : public objects, test::exception_base
|
||||
template <class T> struct construct_test6 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(allocator);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range : public test::exception_base
|
||||
template <class T> struct range : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
test::random_values<T> values;
|
||||
|
||||
range() : values(5) {}
|
||||
range(unsigned int count) : values(count) {}
|
||||
range() : values(5, test::limited_range) {}
|
||||
range(unsigned int count) : values(count, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test1 : public range<T>, objects
|
||||
template <class T> struct range_construct_test1 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end());
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end());
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test2 : public range<T>, objects
|
||||
template <class T> struct range_construct_test2 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test3 : public range<T>, objects
|
||||
template <class T> struct range_construct_test3 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0, hash);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 0, hash);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test4 : public range<T>, objects
|
||||
template <class T> struct range_construct_test4 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
// Need to run at least one test with a fairly large number
|
||||
// of objects in case it triggers a rehash.
|
||||
template <class T>
|
||||
struct range_construct_test5 : public range<T>, objects
|
||||
template <class T> struct range_construct_test5 : public range<T>, objects
|
||||
{
|
||||
range_construct_test5() : range<T>(60) {}
|
||||
range_construct_test5() : range<T>(60) {}
|
||||
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0,
|
||||
hash, equal_to, allocator);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct input_range_construct_test : public range<T>, objects
|
||||
template <class T> struct input_range_construct_test : public range<T>, objects
|
||||
{
|
||||
input_range_construct_test() : range<T>(60) {}
|
||||
input_range_construct_test() : range<T>(60) {}
|
||||
|
||||
void run() const {
|
||||
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
begin = this->values.begin(), end = this->values.end();
|
||||
T x(test::input_iterator(begin), test::input_iterator(end),
|
||||
0, hash, equal_to, allocator);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
typename test::random_values<T>::const_iterator begin =
|
||||
this->values.begin(),
|
||||
end = this->values.end();
|
||||
T x(test::input_iterator(begin), test::input_iterator(end), 0, hash,
|
||||
equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
(construct_test1)
|
||||
(construct_test2)
|
||||
(construct_test3)
|
||||
(construct_test4)
|
||||
(construct_test5)
|
||||
(construct_test6)
|
||||
(range_construct_test1)
|
||||
(range_construct_test2)
|
||||
(range_construct_test3)
|
||||
(range_construct_test4)
|
||||
(range_construct_test5)
|
||||
(input_range_construct_test),
|
||||
CONTAINER_SEQ)
|
||||
template <class T> struct copy_range_construct_test : public range<T>, objects
|
||||
{
|
||||
copy_range_construct_test() : range<T>(60) {}
|
||||
|
||||
void run() const
|
||||
{
|
||||
T x(test::copy_iterator(this->values.begin()),
|
||||
test::copy_iterator(this->values.end()), 0, hash, equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(construct_test1)(construct_test2)(construct_test3)(construct_test4)
|
||||
(construct_test5)(construct_test6)(range_construct_test1)
|
||||
(range_construct_test2)(range_construct_test3)(range_construct_test4)
|
||||
(range_construct_test5)(input_range_construct_test)
|
||||
(copy_range_construct_test),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,31 +3,42 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../objects/exception.hpp"
|
||||
|
||||
typedef boost::unordered_set<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_set;
|
||||
typedef boost::unordered_multiset<test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >
|
||||
test_multiset;
|
||||
typedef boost::unordered_map<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >
|
||||
test_map;
|
||||
typedef boost::unordered_multimap<test::exception::object,
|
||||
test::exception::object, test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_multimap;
|
||||
typedef boost::unordered_set<
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> > test_set;
|
||||
std::pair<test::exception::object, test::exception::object>,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_pair_set;
|
||||
typedef boost::unordered_multiset<
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> > test_multiset;
|
||||
typedef boost::unordered_map<
|
||||
test::exception::object,
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> > test_map;
|
||||
typedef boost::unordered_multimap<
|
||||
test::exception::object,
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> > test_multimap;
|
||||
std::pair<test::exception::object, test::exception::object>,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >
|
||||
test_pair_multiset;
|
||||
|
||||
#define CONTAINER_SEQ (test_set)(test_multiset)(test_map)(test_multimap)
|
||||
#define CONTAINER_PAIR_SEQ \
|
||||
(test_pair_set)(test_pair_multiset)(test_map)(test_multimap)
|
||||
|
@ -3,63 +3,108 @@
|
||||
// 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
test::seed_t seed(73041);
|
||||
template <typename T> inline void avoid_unused_warning(T const&) {}
|
||||
|
||||
template <class T>
|
||||
struct copy_test1 : public test::exception_base
|
||||
test::seed_t initialize_seed(73041);
|
||||
|
||||
template <class T> struct copy_test1 : public test::exception_base
|
||||
{
|
||||
T x;
|
||||
T x;
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(y.empty());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct copy_test2 : public test::exception_base
|
||||
template <class T> struct copy_test2 : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
|
||||
copy_test2() : values(5), x(values.begin(), values.end()) {}
|
||||
copy_test2() : values(5, test::limited_range), x(values.begin(), values.end())
|
||||
{
|
||||
}
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct copy_test3 : public test::exception_base
|
||||
template <class T> struct copy_test3 : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
|
||||
copy_test3() : values(100), x(values.begin(), values.end()) {}
|
||||
copy_test3() : values(100), x(values.begin(), values.end()) {}
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct copy_with_allocator_test : public test::exception_base
|
||||
template <class T> struct copy_test3a : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
|
||||
copy_with_allocator_test() : values(100), x(values.begin(), values.end()) {}
|
||||
copy_test3a()
|
||||
: values(100, test::limited_range), x(values.begin(), values.end())
|
||||
{
|
||||
}
|
||||
|
||||
void run() const {
|
||||
T y(x, allocator);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
(copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test),
|
||||
template <class T> struct copy_with_allocator_test : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
|
||||
copy_with_allocator_test() : values(100), x(values.begin(), values.end()) {}
|
||||
|
||||
void run() const
|
||||
{
|
||||
T y(x, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(copy_test1)(copy_test2)(copy_test3)(copy_test3a)(copy_with_allocator_test),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,54 +3,53 @@
|
||||
// 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
test::seed_t seed(835193);
|
||||
test::seed_t initialize_seed(835193);
|
||||
|
||||
template <class T>
|
||||
struct erase_test_base : public test::exception_base
|
||||
template <class T> struct erase_test_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
erase_test_base(unsigned int count = 5) : values(count) {}
|
||||
test::random_values<T> values;
|
||||
erase_test_base(unsigned int count = 5) : values(count, test::limited_range)
|
||||
{
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
typedef T data_type;
|
||||
|
||||
data_type init() const {
|
||||
return T(values.begin(), values.end());
|
||||
}
|
||||
data_type init() const { return T(values.begin(), values.end()); }
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
std::string scope(test::scope);
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
BOOST_TEST(scope.find("hash::") != std::string::npos ||
|
||||
scope.find("equal_to::") != std::string::npos ||
|
||||
scope == "operator==(object, object)");
|
||||
BOOST_TEST(scope.find("hash::") != std::string::npos ||
|
||||
scope.find("equal_to::") != std::string::npos ||
|
||||
scope == "operator==(object, object)");
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct erase_by_key_test1 : public erase_test_base<T>
|
||||
template <class T> struct erase_by_key_test1 : public erase_test_base<T>
|
||||
{
|
||||
void run(T& x) const
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
test::random_values<T>::const_iterator iterator;
|
||||
void run(T& x) const
|
||||
{
|
||||
typedef typename test::random_values<T>::const_iterator iterator;
|
||||
|
||||
for(iterator it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
x.erase(test::get_key<T>(*it));
|
||||
}
|
||||
for (iterator it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it) {
|
||||
x.erase(test::get_key<T>(*it));
|
||||
}
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
(erase_by_key_test1),
|
||||
CONTAINER_SEQ)
|
||||
EXCEPTION_TESTS((erase_by_key_test1), CONTAINER_SEQ)
|
||||
RUN_TESTS()
|
||||
|
@ -2,247 +2,415 @@
|
||||
// Copyright 2006-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)
|
||||
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include <string>
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/strong.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
test::seed_t seed(747373);
|
||||
test::seed_t initialize_seed(747373);
|
||||
|
||||
template <class T>
|
||||
struct insert_test_base : public test::exception_base
|
||||
// Fill in a container so that it's about to rehash
|
||||
template <typename T> void rehash_prep(T& x)
|
||||
{
|
||||
test::random_values<T> values;
|
||||
insert_test_base(unsigned int count = 5) : values(count) {}
|
||||
using namespace std;
|
||||
typedef typename T::size_type size_type;
|
||||
|
||||
typedef T data_type;
|
||||
typedef test::strong<T> strong_type;
|
||||
x.max_load_factor(0.25);
|
||||
size_type bucket_count = x.bucket_count();
|
||||
size_type initial_elements = static_cast<size_type>(
|
||||
ceil((double)bucket_count * (double)x.max_load_factor()) - 1);
|
||||
test::random_values<T> v(initial_elements);
|
||||
x.insert(v.begin(), v.end());
|
||||
BOOST_TEST(bucket_count == x.bucket_count());
|
||||
}
|
||||
|
||||
data_type init() const {
|
||||
return T();
|
||||
// Overload to generate inserters that need type information.
|
||||
|
||||
template <typename Inserter, typename T>
|
||||
Inserter generate(Inserter inserter, T&)
|
||||
{
|
||||
return inserter;
|
||||
}
|
||||
|
||||
// Get the iterator returned from an insert/emplace.
|
||||
|
||||
template <typename T> T get_iterator(T const& x) { return x; }
|
||||
|
||||
template <typename T> T get_iterator(std::pair<T, bool> const& x)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
|
||||
// Generic insert exception test for typical single element inserts..
|
||||
|
||||
template <typename T, typename Inserter, typename Values>
|
||||
void insert_exception_test_impl(T x, Inserter insert, Values const& v)
|
||||
{
|
||||
test::strong<T> strong;
|
||||
|
||||
test::ordered<T> tracker;
|
||||
tracker.insert(x.begin(), x.end());
|
||||
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
|
||||
for (typename Values::const_iterator it = v.begin(); it != v.end(); ++it) {
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
insert(x, it);
|
||||
}
|
||||
} catch (...) {
|
||||
test::check_equivalent_keys(x);
|
||||
insert.exception_check(x, strong);
|
||||
throw;
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(
|
||||
T const& x, strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
test::check_equivalent_keys(x);
|
||||
insert.track(tracker, v.begin(), v.end());
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
if(scope.find("hash::operator()") == std::string::npos)
|
||||
strong.test(x, test::exception::detail::tracker.count_allocations);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
// Simple insert exception test
|
||||
|
||||
template <typename T, typename Inserter>
|
||||
void insert_exception_test(T*, Inserter insert, test::random_generator gen)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
test::random_values<T> v(10, gen);
|
||||
T x;
|
||||
|
||||
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v));
|
||||
}
|
||||
}
|
||||
|
||||
// Insert into a container which is about to hit its max load, so that it
|
||||
// rehashes.
|
||||
|
||||
template <typename T, typename Inserter>
|
||||
void insert_rehash_exception_test(
|
||||
T*, Inserter insert, test::random_generator gen)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
T x;
|
||||
rehash_prep(x);
|
||||
|
||||
test::random_values<T> v2(5, gen);
|
||||
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v2));
|
||||
}
|
||||
}
|
||||
|
||||
// Various methods for inserting a single element
|
||||
|
||||
struct inserter_base
|
||||
{
|
||||
template <typename T> void exception_check(T& x, test::strong<T>& strong)
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if (scope.find("hash::operator()") == std::string::npos)
|
||||
strong.test(x, test::detail::tracker.count_allocations);
|
||||
}
|
||||
|
||||
template <typename T, typename Iterator>
|
||||
void track(T& tracker, Iterator begin, Iterator end)
|
||||
{
|
||||
tracker.insert(begin, end);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
|
||||
template <class T>
|
||||
struct emplace_test1 : public insert_test_base<T>
|
||||
struct insert_lvalue_type : inserter_base
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(*it);
|
||||
}
|
||||
} insert_lvalue;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.emplace(*it);
|
||||
}
|
||||
}
|
||||
struct insert_lvalue_begin_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(x.begin(), *it);
|
||||
}
|
||||
} insert_lvalue_begin;
|
||||
|
||||
struct insert_lvalue_end_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(x.end(), *it);
|
||||
}
|
||||
} insert_lvalue_end;
|
||||
|
||||
template <typename T> struct insert_lvalue_pos_type_impl : inserter_base
|
||||
{
|
||||
typename T::iterator pos;
|
||||
|
||||
insert_lvalue_pos_type_impl(T& x) : pos(x.begin()) {}
|
||||
|
||||
template <typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
pos = get_iterator(x.insert(pos, *it));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
struct insert_test1 : public insert_test_base<T>
|
||||
struct insert_lvalue_pos_type
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T>
|
||||
friend insert_lvalue_pos_type_impl<T> generate(insert_lvalue_pos_type, T& x)
|
||||
{
|
||||
return insert_lvalue_pos_type_impl<T>(x);
|
||||
}
|
||||
} insert_lvalue_pos;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(*it);
|
||||
}
|
||||
}
|
||||
struct insert_single_item_range_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(it, test::next(it));
|
||||
}
|
||||
} insert_single_item_range;
|
||||
|
||||
struct emplace_lvalue_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace(*it);
|
||||
}
|
||||
} emplace_lvalue;
|
||||
|
||||
struct emplace_lvalue_begin_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace_hint(x.begin(), *it);
|
||||
}
|
||||
} emplace_lvalue_begin;
|
||||
|
||||
struct emplace_lvalue_end_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace_hint(x.end(), *it);
|
||||
}
|
||||
} emplace_lvalue_end;
|
||||
|
||||
template <typename T> struct emplace_lvalue_pos_type_impl : inserter_base
|
||||
{
|
||||
typename T::iterator pos;
|
||||
|
||||
emplace_lvalue_pos_type_impl(T& x) : pos(x.begin()) {}
|
||||
|
||||
template <typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
pos = get_iterator(x.emplace_hint(pos, *it));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test2 : public insert_test_base<T>
|
||||
struct emplace_lvalue_pos_type
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T>
|
||||
friend emplace_lvalue_pos_type_impl<T> generate(emplace_lvalue_pos_type, T& x)
|
||||
{
|
||||
return emplace_lvalue_pos_type_impl<T>(x);
|
||||
}
|
||||
} emplace_lvalue_pos;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(x.begin(), *it);
|
||||
}
|
||||
// Run the exception tests in various combinations.
|
||||
|
||||
test_set* test_set_;
|
||||
test_multiset* test_multiset_;
|
||||
test_map* test_map_;
|
||||
test_multimap* test_multimap_;
|
||||
|
||||
using test::default_generator;
|
||||
using test::limited_range;
|
||||
using test::generate_collisions;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
|
||||
(insert_lvalue_pos)(insert_single_item_range)
|
||||
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
|
||||
(emplace_lvalue_pos)
|
||||
)
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
|
||||
(insert_lvalue_pos)(insert_single_item_range)
|
||||
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
|
||||
(emplace_lvalue_pos)
|
||||
)
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
// Repeat insert tests with pairs
|
||||
|
||||
struct pair_emplace_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(it->first), boost::make_tuple(it->second));
|
||||
}
|
||||
} pair_emplace;
|
||||
|
||||
struct pair_emplace2_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace_hint(x.begin(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(it->first),
|
||||
boost::make_tuple(it->second.tag1_, it->second.tag2_));
|
||||
}
|
||||
} pair_emplace2;
|
||||
|
||||
test_pair_set* test_pair_set_;
|
||||
test_pair_multiset* test_pair_multiset_;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
|
||||
((pair_emplace)(pair_emplace2))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
|
||||
((pair_emplace)(pair_emplace2))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
// Test inserting using operator[]
|
||||
|
||||
struct try_emplace_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.try_emplace(it->first, it->second);
|
||||
}
|
||||
} try_emplace;
|
||||
|
||||
struct try_emplace2_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.try_emplace(it->first, it->second.tag1_, it->second.tag2_);
|
||||
}
|
||||
} try_emplace2;
|
||||
|
||||
struct map_inserter_base
|
||||
{
|
||||
template <typename T> void exception_check(T& x, test::strong<T>& strong)
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if (scope.find("hash::operator()") == std::string::npos &&
|
||||
scope.find("::operator=") == std::string::npos)
|
||||
strong.test(x, test::detail::tracker.count_allocations);
|
||||
}
|
||||
|
||||
template <typename T, typename Iterator>
|
||||
void track(T& tracker, Iterator begin, Iterator end)
|
||||
{
|
||||
for (; begin != end; ++begin) {
|
||||
tracker[begin->first] = begin->second;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test3 : public insert_test_base<T>
|
||||
struct map_insert_operator_type : map_inserter_base
|
||||
{
|
||||
void run(T& x) const {
|
||||
x.insert(this->values.begin(), this->values.end());
|
||||
}
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x[it->first] = it->second;
|
||||
}
|
||||
} map_insert_operator;
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test4 : public insert_test_base<T>
|
||||
struct map_insert_or_assign_type : map_inserter_base
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert_or_assign(it->first, it->second);
|
||||
}
|
||||
} map_insert_or_assign;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(it, boost::next(it));
|
||||
}
|
||||
}
|
||||
};
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_map_))
|
||||
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_map_))
|
||||
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
template <class T>
|
||||
struct insert_test_rehash1 : public insert_test_base<T>
|
||||
// Range insert tests
|
||||
|
||||
template <typename T, typename Values>
|
||||
void insert_range_exception_test_impl(T x, Values const& v)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
test::ordered<T> tracker;
|
||||
tracker.insert(x.begin(), x.end());
|
||||
|
||||
insert_test_rehash1() : insert_test_base<T>(1000) {}
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
x.insert(v.begin(), v.end());
|
||||
} catch (...) {
|
||||
test::check_equivalent_keys(x);
|
||||
throw;
|
||||
}
|
||||
|
||||
T init() const {
|
||||
using namespace std;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
|
||||
test::check_equivalent_keys(x);
|
||||
tracker.insert(v.begin(), v.end());
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
T x;
|
||||
x.max_load_factor(0.25);
|
||||
size_type bucket_count = x.bucket_count();
|
||||
size_type initial_elements = static_cast<size_type>(
|
||||
ceil(bucket_count * (double) x.max_load_factor()) - 1);
|
||||
BOOST_TEST(initial_elements < this->values.size());
|
||||
x.insert(this->values.begin(),
|
||||
boost::next(this->values.begin(), initial_elements));
|
||||
BOOST_TEST(bucket_count == x.bucket_count());
|
||||
return x;
|
||||
}
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
|
||||
int count = 0;
|
||||
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = boost::next(this->values.begin(), x.size()),
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
pos = x.insert(pos, *it);
|
||||
}
|
||||
|
||||
// This isn't actually a failure, but it means the test isn't doing its
|
||||
// job.
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test_rehash2 : public insert_test_rehash1<T>
|
||||
template <typename T>
|
||||
void insert_range_exception_test(T*, test::random_generator gen)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
test::random_values<T> v(10, gen);
|
||||
T x;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
|
||||
int count = 0;
|
||||
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v));
|
||||
}
|
||||
}
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = boost::next(this->values.begin(), x.size()),
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(*it);
|
||||
}
|
||||
|
||||
// This isn't actually a failure, but it means the test isn't doing its
|
||||
// job.
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test_rehash3 : public insert_test_base<T>
|
||||
template <typename T>
|
||||
void insert_range_rehash_exception_test(T*, test::random_generator gen)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::size_type mutable
|
||||
rehash_bucket_count, original_bucket_count;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
T x;
|
||||
rehash_prep(x);
|
||||
|
||||
insert_test_rehash3() : insert_test_base<T>(1000) {}
|
||||
test::random_values<T> v2(5, gen);
|
||||
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v2));
|
||||
}
|
||||
}
|
||||
|
||||
T init() const {
|
||||
using namespace std;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_range_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
|
||||
T x;
|
||||
x.max_load_factor(0.25);
|
||||
UNORDERED_TEST(insert_range_rehash_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
original_bucket_count = x.bucket_count();
|
||||
rehash_bucket_count = static_cast<size_type>(
|
||||
ceil(original_bucket_count * (double) x.max_load_factor())) - 1;
|
||||
|
||||
size_type initial_elements =
|
||||
rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1;
|
||||
|
||||
BOOST_TEST(initial_elements < this->values.size());
|
||||
x.insert(this->values.begin(),
|
||||
boost::next(this->values.begin(), initial_elements));
|
||||
BOOST_TEST(original_bucket_count == x.bucket_count());
|
||||
return x;
|
||||
}
|
||||
|
||||
void run(T& x) const {
|
||||
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
|
||||
|
||||
x.insert(boost::next(this->values.begin(), x.size()),
|
||||
boost::next(this->values.begin(), x.size() + 20));
|
||||
|
||||
// This isn't actually a failure, but it means the test isn't doing its
|
||||
// job.
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
if(x.size() < rehash_bucket_count) {
|
||||
//BOOST_TEST(x.bucket_count() == original_bucket_count);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
#define BASIC_TESTS \
|
||||
(insert_test1)(insert_test2)(insert_test3)(insert_test4) \
|
||||
(insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3)
|
||||
|
||||
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
|
||||
#define ALL_TESTS (emplace_test1)BASIC_TESTS
|
||||
#else
|
||||
#define ALL_TESTS BASIC_TESTS
|
||||
#endif
|
||||
|
||||
|
||||
RUN_EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
|
||||
RUN_TESTS()
|
||||
|
108
test/exception/merge_exception_tests.cpp
Normal file
108
test/exception/merge_exception_tests.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
// Copyright 2017-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)
|
||||
|
||||
#include "../helpers/exception_test.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/metafunctions.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "./containers.hpp"
|
||||
|
||||
template <typename T1, typename T2> void merge_exception_test(T1 x, T2 y)
|
||||
{
|
||||
std::size_t size = x.size() + y.size();
|
||||
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
x.merge(y);
|
||||
} catch (...) {
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
throw;
|
||||
}
|
||||
|
||||
// Not a full check, just want to make sure the merge completed.
|
||||
BOOST_TEST(size == x.size() + y.size());
|
||||
if (y.size()) {
|
||||
BOOST_TEST(test::has_unique_keys<T1>::value);
|
||||
for (typename T2::iterator it = y.begin(); it != y.end(); ++it) {
|
||||
BOOST_TEST(x.find(test::get_key<T2>(*it)) != x.end());
|
||||
}
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void merge_exception_test(T1 const*, T2 const*, std::size_t count12, int tag12,
|
||||
test::random_generator gen1, test::random_generator gen2)
|
||||
{
|
||||
std::size_t count1 = count12 / 256;
|
||||
std::size_t count2 = count12 % 256;
|
||||
int tag1 = tag12 / 256;
|
||||
int tag2 = tag12 % 256;
|
||||
test::random_values<T1> v1(count1, gen1);
|
||||
test::random_values<T2> v2(count2, gen2);
|
||||
T1 x(v1.begin(), v1.end(), 0, test::exception::hash(tag1),
|
||||
test::exception::equal_to(tag1));
|
||||
T2 y(v2.begin(), v2.end(), 0, test::exception::hash(tag2),
|
||||
test::exception::equal_to(tag2));
|
||||
|
||||
EXCEPTION_LOOP(merge_exception_test(x, y))
|
||||
}
|
||||
|
||||
boost::unordered_set<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >* test_set_;
|
||||
boost::unordered_multiset<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >* test_multiset_;
|
||||
boost::unordered_map<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >* test_map_;
|
||||
boost::unordered_multimap<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >* test_multimap_;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_MULTI_TEST(set_merge, merge_exception_test,
|
||||
((test_set_)(test_multiset_))
|
||||
((test_set_)(test_multiset_))
|
||||
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
|
||||
((0x0000)(0x0001)(0x0102))
|
||||
((default_generator)(limited_range))
|
||||
((default_generator)(limited_range))
|
||||
)
|
||||
UNORDERED_MULTI_TEST(map_merge, merge_exception_test,
|
||||
((test_map_)(test_multimap_))
|
||||
((test_map_)(test_multimap_))
|
||||
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
|
||||
((0x0101)(0x0200)(0x0201))
|
||||
((default_generator)(limited_range))
|
||||
((default_generator)(limited_range))
|
||||
)
|
||||
// Run fewer generate_collisions tests, as they're slow.
|
||||
UNORDERED_MULTI_TEST(set_merge_collisions, merge_exception_test,
|
||||
((test_set_)(test_multiset_))
|
||||
((test_set_)(test_multiset_))
|
||||
((0x0a0a))
|
||||
((0x0202)(0x0100)(0x0201))
|
||||
((generate_collisions))
|
||||
((generate_collisions))
|
||||
)
|
||||
UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test,
|
||||
((test_map_)(test_multimap_))
|
||||
((test_map_)(test_multimap_))
|
||||
((0x0a0a))
|
||||
((0x0000)(0x0002)(0x0102))
|
||||
((generate_collisions))
|
||||
((generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS_QUIET()
|
132
test/exception/move_assign_exception_tests.cpp
Normal file
132
test/exception/move_assign_exception_tests.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
|
||||
// Copyright 2006-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)
|
||||
|
||||
#include "./containers.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning( \
|
||||
disable : 4512) // move_assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t initialize_seed(12847);
|
||||
|
||||
template <class T> struct move_assign_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> x_values, y_values;
|
||||
T x, y;
|
||||
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
move_assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: x_values(), y_values(),
|
||||
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(x); }
|
||||
void run(T& x1) const
|
||||
{
|
||||
test::exceptions_enable disable_exceptions(false);
|
||||
T y1 = y;
|
||||
disable_exceptions.release();
|
||||
x1 = boost::move(y1);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x1, y_values);
|
||||
test::check_equivalent_keys(x1);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it, at the cost of
|
||||
// messing up the data.
|
||||
if (x_values.size()) {
|
||||
T& x2 = const_cast<T&>(x1);
|
||||
x2.emplace(*x_values.begin());
|
||||
test::check_equivalent_keys(x2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_values : move_assign_base<T>
|
||||
{
|
||||
move_assign_values(unsigned int count1, unsigned int count2, int tag1,
|
||||
int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: move_assign_base<T>(tag1, tag2, mlf1, mlf2)
|
||||
{
|
||||
this->x_values.fill(count1, test::limited_range);
|
||||
this->y_values.fill(count2, test::limited_range);
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test1 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test1() : move_assign_values<T>(0, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test2 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test2() : move_assign_values<T>(60, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test3 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test3() : move_assign_values<T>(0, 60, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test4 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test4() : move_assign_values<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test4a : move_assign_values<T>
|
||||
{
|
||||
move_assign_test4a() : move_assign_values<T>(10, 100, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test5 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test5() : move_assign_values<T>(5, 60, 0, 0, 1.0f, 0.1f) {}
|
||||
};
|
||||
|
||||
template <class T> struct equivalent_test1 : move_assign_base<T>
|
||||
{
|
||||
equivalent_test1() : move_assign_base<T>(0, 0)
|
||||
{
|
||||
test::random_values<T> x_values2(10, test::limited_range);
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
test::random_values<T> y_values2(10, test::limited_range);
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(move_assign_test1)(move_assign_test2)(move_assign_test3)
|
||||
(move_assign_test4)(move_assign_test4a)(move_assign_test5)
|
||||
(equivalent_test1),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
@ -3,85 +3,131 @@
|
||||
// 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include <string>
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/strong.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
test::seed_t initialize_seed(3298597);
|
||||
|
||||
test::seed_t seed(3298597);
|
||||
|
||||
template <class T>
|
||||
struct rehash_test_base : public test::exception_base
|
||||
template <class T> struct rehash_test_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
unsigned int n;
|
||||
rehash_test_base(unsigned int count = 100, unsigned int n = 0)
|
||||
: values(count), n(n)
|
||||
{}
|
||||
test::random_values<T> values;
|
||||
unsigned int n;
|
||||
rehash_test_base(unsigned int count = 100, unsigned int n_ = 0)
|
||||
: values(count, test::limited_range), n(n_)
|
||||
{
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
typedef test::strong<T> strong_type;
|
||||
typedef T data_type;
|
||||
typedef test::strong<T> strong_type;
|
||||
|
||||
data_type init() const {
|
||||
T x(values.begin(), values.end(), n);
|
||||
return x;
|
||||
}
|
||||
data_type init() const
|
||||
{
|
||||
T x(values.begin(), values.end(), n);
|
||||
return x;
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x,
|
||||
strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(
|
||||
T const& x, strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if(scope.find("hash::operator()") == std::string::npos &&
|
||||
scope.find("equal_to::operator()") == std::string::npos &&
|
||||
scope != "operator==(object, object)")
|
||||
strong.test(x);
|
||||
if (scope.find("hash::operator()") == std::string::npos &&
|
||||
scope.find("equal_to::operator()") == std::string::npos &&
|
||||
scope != "operator==(object, object)")
|
||||
strong.test(x);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test0 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test0 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test0() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const { x.rehash(0); }
|
||||
rehash_test0() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test1 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test1 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test1() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const { x.rehash(200); }
|
||||
rehash_test1() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(200);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test2 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test2 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test2() : rehash_test_base<T>(0, 200) {}
|
||||
void run(T& x) const { x.rehash(0); }
|
||||
rehash_test2() : rehash_test_base<T>(0, 200) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test3 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test3 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test3() : rehash_test_base<T>(10, 0) {}
|
||||
void run(T& x) const { x.rehash(200); }
|
||||
rehash_test3() : rehash_test_base<T>(10, 0) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(200);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test4 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test4 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test4() : rehash_test_base<T>(10, 200) {}
|
||||
void run(T& x) const { x.rehash(0); }
|
||||
rehash_test4() : rehash_test_base<T>(10, 200) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
|
||||
CONTAINER_SEQ)
|
||||
template <class T> struct rehash_test5 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test5() : rehash_test_base<T>(200, 10) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4)
|
||||
(rehash_test5),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,123 +3,143 @@
|
||||
// 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 "../helpers/prefix.hpp"
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
#pragma warning(disable : 4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t seed(9387);
|
||||
test::seed_t initialize_seed(9387);
|
||||
|
||||
template <class T>
|
||||
struct self_swap_base : public test::exception_base
|
||||
template <class T> struct self_swap_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
self_swap_base(int count = 0) : values(count) {}
|
||||
test::random_values<T> values;
|
||||
self_swap_base(std::size_t count = 0) : values(count, test::limited_range) {}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
void run(T& x) const { x.swap(x); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
std::string scope(test::scope);
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
|
||||
#if BOOST_UNORDERED_SWAP_METHOD != 2
|
||||
BOOST_TEST(
|
||||
scope == "hash::operator(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::operator(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
#endif
|
||||
void run(T& x) const
|
||||
{
|
||||
x.swap(x);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct self_swap_test1 : self_swap_base<T> {};
|
||||
|
||||
template <class T>
|
||||
struct self_swap_test2 : self_swap_base<T>
|
||||
template <class T> struct self_swap_test1 : self_swap_base<T>
|
||||
{
|
||||
self_swap_test2() : self_swap_base<T>(100) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_base : public test::exception_base
|
||||
template <class T> struct self_swap_test2 : self_swap_base<T>
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
const T initial_x, initial_y;
|
||||
self_swap_test2() : self_swap_base<T>(100) {}
|
||||
};
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
template <class T> struct swap_base : public test::exception_base
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
const T initial_x, initial_y;
|
||||
|
||||
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
|
||||
: x_values(count1), y_values(count2),
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
|
||||
: x_values(count1, test::limited_range),
|
||||
y_values(count2, test::limited_range),
|
||||
initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1),
|
||||
key_equal(tag1), allocator_type(tag1)),
|
||||
key_equal(tag1), allocator_type(tag1)),
|
||||
initial_y(y_values.begin(), y_values.end(), 0, hasher(tag2),
|
||||
key_equal(tag2), allocator_type(tag2))
|
||||
{}
|
||||
key_equal(tag2),
|
||||
allocator_type(T::allocator_type::propagate_on_container_swap::value
|
||||
? tag2
|
||||
: tag1))
|
||||
{
|
||||
}
|
||||
|
||||
struct data_type {
|
||||
data_type(T const& x, T const& y)
|
||||
: x(x), y(y) {}
|
||||
struct data_type
|
||||
{
|
||||
data_type(T const& x_, T const& y_) : x(x_), y(y_) {}
|
||||
|
||||
T x, y;
|
||||
};
|
||||
T x, y;
|
||||
};
|
||||
|
||||
data_type init() const { return data_type(initial_x, initial_y); }
|
||||
void run(data_type& d) const {
|
||||
try {
|
||||
d.x.swap(d.y);
|
||||
} catch (std::runtime_error) {}
|
||||
data_type init() const { return data_type(initial_x, initial_y); }
|
||||
|
||||
void run(data_type& d) const
|
||||
{
|
||||
try {
|
||||
d.x.swap(d.y);
|
||||
} catch (std::runtime_error&) {
|
||||
}
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const {
|
||||
std::string scope(test::scope);
|
||||
|
||||
#if BOOST_UNORDERED_SWAP_METHOD != 2
|
||||
BOOST_TEST(
|
||||
scope == "hash::operator(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::operator(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
#endif
|
||||
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(d.x, this->y_values);
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_container(d.y, this->x_values);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test1 : swap_base<T>
|
||||
template <class T> struct swap_test1 : swap_base<T>
|
||||
{
|
||||
swap_test1() : swap_base<T>(0, 0, 0, 0) {}
|
||||
swap_test1() : swap_base<T>(0, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test2 : swap_base<T>
|
||||
template <class T> struct swap_test2 : swap_base<T>
|
||||
{
|
||||
swap_test2() : swap_base<T>(60, 0, 0, 0) {}
|
||||
swap_test2() : swap_base<T>(60, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test3 : swap_base<T>
|
||||
template <class T> struct swap_test3 : swap_base<T>
|
||||
{
|
||||
swap_test3() : swap_base<T>(0, 60, 0, 0) {}
|
||||
swap_test3() : swap_base<T>(0, 60, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test4 : swap_base<T>
|
||||
template <class T> struct swap_test4 : swap_base<T>
|
||||
{
|
||||
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
|
||||
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
(self_swap_test1)(self_swap_test2)
|
||||
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(self_swap_test1)(self_swap_test2)
|
||||
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -1,84 +0,0 @@
|
||||
|
||||
// Copyright 2006-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_UNORDERED_TEST_MALLOC_ALLOCATOR_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_MALLOC_ALLOCATOR_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <boost/limits.hpp>
|
||||
#include <new>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class T>
|
||||
struct malloc_allocator
|
||||
{
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind { typedef malloc_allocator<U> other; };
|
||||
|
||||
malloc_allocator() {}
|
||||
template <class Y> malloc_allocator(malloc_allocator<Y> const&) {}
|
||||
malloc_allocator(malloc_allocator const&) {}
|
||||
|
||||
pointer address(reference r) { return &r; }
|
||||
const_pointer address(const_reference r) { return &r; }
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
using namespace std;
|
||||
T* ptr = static_cast<T*>(malloc(n * sizeof(T)));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, void const* u) { return allocate(n); }
|
||||
|
||||
void deallocate(pointer p, size_type) {
|
||||
using namespace std;
|
||||
free(p);
|
||||
}
|
||||
void construct(pointer p, T const& t) { new(p) T(t); }
|
||||
void destroy(pointer p) { p->~T(); }
|
||||
|
||||
size_type max_size() const {
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
|
||||
bool operator==(malloc_allocator const&) const { return true; }
|
||||
bool operator!=(malloc_allocator const&) const { return false; }
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
template <class T> void deallocate(T* p, size_type) {
|
||||
using namespace std;
|
||||
free(p);
|
||||
}
|
||||
char* _Charalloc(size_type n) {
|
||||
using namespace std;
|
||||
T* ptr = static_cast<T*>(malloc(n * sizeof(char)));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
return (char*) ptr;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
#endif
|
@ -6,33 +6,28 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER
|
||||
|
||||
#include <boost/mpl/assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class T1>
|
||||
struct check_return_type
|
||||
namespace test {
|
||||
template <class T1> struct check_return_type
|
||||
{
|
||||
template <class T2> static void equals(T2)
|
||||
{
|
||||
template <class T2>
|
||||
static void equals(T2)
|
||||
{
|
||||
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
|
||||
}
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
static void equals_ref(T2&)
|
||||
{
|
||||
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
|
||||
}
|
||||
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_MPL_ASSERT((boost::is_convertible<T2, T1>));
|
||||
}
|
||||
};
|
||||
template <class T2> static void convertible(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,75 +6,84 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace test {
|
||||
struct object_count {
|
||||
int instances;
|
||||
int constructions;
|
||||
struct object_count
|
||||
{
|
||||
int instances;
|
||||
int constructions;
|
||||
|
||||
object_count() : instances(0), constructions(0) {}
|
||||
void reset() { *this = object_count(); }
|
||||
object_count() : instances(0), constructions(0) {}
|
||||
void reset() { *this = object_count(); }
|
||||
|
||||
void construct() {
|
||||
++instances;
|
||||
++constructions;
|
||||
}
|
||||
|
||||
void destruct() {
|
||||
if(instances == 0) {
|
||||
BOOST_ERROR("Unbalanced constructions.");
|
||||
}
|
||||
else {
|
||||
--instances;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(object_count const& x) const {
|
||||
return instances == x.instances &&
|
||||
constructions == x.constructions;
|
||||
}
|
||||
|
||||
bool operator!=(object_count const& x) const {
|
||||
return !(*this == x);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out,
|
||||
object_count const& c)
|
||||
{
|
||||
out
|
||||
<< "[instances: "
|
||||
<< c.instances
|
||||
<< ", constructions: "
|
||||
<< c.constructions
|
||||
<< "]";
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct counted_object
|
||||
void construct()
|
||||
{
|
||||
static object_count count_;
|
||||
|
||||
counted_object() { count_.construct(); }
|
||||
counted_object(counted_object const&) { count_.construct(); }
|
||||
~counted_object() { count_.destruct(); }
|
||||
};
|
||||
|
||||
template <class T> object_count counted_object<T>::count_;
|
||||
|
||||
struct globally_counted_object
|
||||
: counted_object<globally_counted_object> {};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
object_count& global_object_count = globally_counted_object::count_;
|
||||
++instances;
|
||||
++constructions;
|
||||
}
|
||||
|
||||
void destruct()
|
||||
{
|
||||
if (instances == 0) {
|
||||
BOOST_ERROR("Unbalanced constructions.");
|
||||
} else {
|
||||
--instances;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(object_count const& x) const
|
||||
{
|
||||
return instances == x.instances && constructions == x.constructions;
|
||||
}
|
||||
|
||||
bool operator!=(object_count const& x) const { return !(*this == x); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, object_count const& c)
|
||||
{
|
||||
out << "[instances: " << c.instances
|
||||
<< ", constructions: " << c.constructions << "]";
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
object_count global_object_count;
|
||||
}
|
||||
|
||||
struct counted_object
|
||||
{
|
||||
counted_object() { global_object_count.construct(); }
|
||||
counted_object(counted_object const&) { global_object_count.construct(); }
|
||||
~counted_object() { global_object_count.destruct(); }
|
||||
};
|
||||
|
||||
struct check_instances
|
||||
{
|
||||
int instances_;
|
||||
int constructions_;
|
||||
|
||||
check_instances()
|
||||
: instances_(global_object_count.instances),
|
||||
constructions_(global_object_count.constructions)
|
||||
{
|
||||
}
|
||||
~check_instances()
|
||||
{
|
||||
BOOST_TEST(global_object_count.instances == instances_);
|
||||
}
|
||||
|
||||
int instances() const { return global_object_count.instances - instances_; }
|
||||
int constructions() const
|
||||
{
|
||||
return global_object_count.constructions - constructions_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,93 +6,91 @@
|
||||
#if !defined(BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER)
|
||||
#define BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <algorithm>
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./fwd.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
namespace test {
|
||||
template <class T1, class T2>
|
||||
bool equivalent_impl(T1 const& x, T2 const& y, base_type)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(
|
||||
boost::hash<T> const&, boost::hash<T> const&, derived_type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(
|
||||
std::equal_to<T> const&, std::equal_to<T> const&, derived_type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
bool equivalent_impl(
|
||||
std::pair<T1, T2> const& x1, std::pair<T3, T4> const& x2, derived_type)
|
||||
{
|
||||
return equivalent_impl(x1.first, x2.first, derived) &&
|
||||
equivalent_impl(x1.second, x2.second, derived);
|
||||
}
|
||||
|
||||
struct equivalent_type
|
||||
{
|
||||
equivalent_type() {}
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class T1, class T2>
|
||||
bool equivalent_impl(T1 const& x, T2 const& y, base_type) {
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(boost::hash<T> const&, boost::hash<T> const&,
|
||||
derived_type)
|
||||
bool operator()(T1 const& x, T2 const& y) const
|
||||
{
|
||||
return true;
|
||||
return equivalent_impl(x, y, derived);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(std::equal_to<T> const&, std::equal_to<T> const&,
|
||||
derived_type)
|
||||
const equivalent_type equivalent;
|
||||
|
||||
template <class Container> class unordered_equivalence_tester
|
||||
{
|
||||
typename Container::size_type size_;
|
||||
typename Container::hasher hasher_;
|
||||
typename Container::key_equal key_equal_;
|
||||
float max_load_factor_;
|
||||
|
||||
typedef test::list<typename Container::value_type> value_list;
|
||||
value_list values_;
|
||||
|
||||
public:
|
||||
unordered_equivalence_tester(Container const& x)
|
||||
: size_(x.size()), hasher_(x.hash_function()), key_equal_(x.key_eq()),
|
||||
max_load_factor_(x.max_load_factor()), values_(x.begin(), x.end())
|
||||
{
|
||||
return true;
|
||||
values_.sort();
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
bool equivalent_impl(std::pair<T1, T2> const& x1,
|
||||
std::pair<T3, T4> const& x2, derived_type) {
|
||||
return equivalent_impl(x1.first, x2.first, derived) &&
|
||||
equivalent_impl(x1.second, x2.second, derived);
|
||||
}
|
||||
|
||||
struct equivalent_type {
|
||||
template <class T1, class T2>
|
||||
bool operator()(T1 const& x, T2 const& y) {
|
||||
return equivalent_impl(x, y, derived);
|
||||
}
|
||||
};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
equivalent_type equivalent;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
class unordered_equivalence_tester
|
||||
bool operator()(Container const& x) const
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::size_type size_;
|
||||
BOOST_DEDUCED_TYPENAME Container::hasher hasher_;
|
||||
BOOST_DEDUCED_TYPENAME Container::key_equal key_equal_;
|
||||
float max_load_factor_;
|
||||
if (!((size_ == x.size()) &&
|
||||
(test::equivalent(hasher_, x.hash_function())) &&
|
||||
(test::equivalent(key_equal_, x.key_eq())) &&
|
||||
(max_load_factor_ == x.max_load_factor()) &&
|
||||
(values_.size() == x.size())))
|
||||
return false;
|
||||
|
||||
typedef test::list<BOOST_DEDUCED_TYPENAME Container::value_type>
|
||||
value_list;
|
||||
value_list values_;
|
||||
public:
|
||||
unordered_equivalence_tester(Container const &x)
|
||||
: size_(x.size()),
|
||||
hasher_(x.hash_function()), key_equal_(x.key_eq()),
|
||||
max_load_factor_(x.max_load_factor()),
|
||||
values_(x.begin(), x.end())
|
||||
{
|
||||
values_.sort();
|
||||
}
|
||||
value_list copy(x.begin(), x.end());
|
||||
copy.sort();
|
||||
return values_ == copy;
|
||||
}
|
||||
|
||||
bool operator()(Container const& x) const
|
||||
{
|
||||
if(!((size_ == x.size()) &&
|
||||
(test::equivalent(hasher_, x.hash_function())) &&
|
||||
(test::equivalent(key_equal_, x.key_eq())) &&
|
||||
(max_load_factor_ == x.max_load_factor()) &&
|
||||
(values_.size() == x.size()))) return false;
|
||||
|
||||
value_list copy(x.begin(), x.end());
|
||||
copy.sort();
|
||||
return values_ == copy;
|
||||
}
|
||||
private:
|
||||
unordered_equivalence_tester();
|
||||
};
|
||||
private:
|
||||
unordered_equivalence_tester();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,231 +6,343 @@
|
||||
#if !defined(BOOST_UNORDERED_EXCEPTION_TEST_HEADER)
|
||||
#define BOOST_UNORDERED_EXCEPTION_TEST_HEADER
|
||||
|
||||
#include "./count.hpp"
|
||||
#include "./test.hpp"
|
||||
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
|
||||
# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
|
||||
UNORDERED_AUTO_TEST(name) \
|
||||
{ \
|
||||
test_func< type > fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
} \
|
||||
#define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
|
||||
UNORDERED_AUTO_TEST (name) { \
|
||||
test_func<type> fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
}
|
||||
|
||||
# define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
|
||||
#define UNORDERED_EXCEPTION_TEST_CASE_REPEAT(name, test_func, n, type) \
|
||||
UNORDERED_AUTO_TEST (name) { \
|
||||
for (unsigned i = 0; i < n; ++i) { \
|
||||
test_func<type> fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
|
||||
|
||||
#define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
|
||||
|
||||
#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, \
|
||||
(test_seq)(param_seq)) \
|
||||
RUN_TESTS() \
|
||||
#define EXCEPTION_TESTS(test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((1))(param_seq))
|
||||
|
||||
#define RUN_EXCEPTION_TESTS_OP(r, product) \
|
||||
UNORDERED_EXCEPTION_TEST_CASE( \
|
||||
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \
|
||||
), \
|
||||
BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product) \
|
||||
) \
|
||||
#define EXCEPTION_TESTS_REPEAT(n, test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((n))(param_seq))
|
||||
|
||||
#define UNORDERED_SCOPE(scope_name) \
|
||||
for(::test::scope_guard unordered_test_guard( \
|
||||
BOOST_STRINGIZE(scope_name)); \
|
||||
!unordered_test_guard.dismissed(); \
|
||||
unordered_test_guard.dismiss()) \
|
||||
#define EXCEPTION_TESTS_OP(r, product) \
|
||||
UNORDERED_EXCEPTION_TEST_CASE_REPEAT( \
|
||||
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(2, product))), \
|
||||
BOOST_PP_SEQ_ELEM(0, product), BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_ELEM(2, product))
|
||||
|
||||
#define UNORDERED_EPOINT(name) \
|
||||
if(::test::exceptions_enabled) { \
|
||||
UNORDERED_EPOINT_IMPL(name); \
|
||||
} \
|
||||
#define UNORDERED_SCOPE(scope_name) \
|
||||
for (::test::scope_guard unordered_test_guard(BOOST_STRINGIZE(scope_name)); \
|
||||
!unordered_test_guard.dismissed(); unordered_test_guard.dismiss())
|
||||
|
||||
#define ENABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT( \
|
||||
ENABLE_EXCEPTIONS_, __LINE__)(true) \
|
||||
#define UNORDERED_EPOINT(name) \
|
||||
if (::test::exceptions_enabled) { \
|
||||
UNORDERED_EPOINT_IMPL(name); \
|
||||
}
|
||||
|
||||
#define DISABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT( \
|
||||
ENABLE_EXCEPTIONS_, __LINE__)(false) \
|
||||
#define ENABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true)
|
||||
|
||||
#define DISABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false)
|
||||
|
||||
namespace test {
|
||||
static char const* scope = "";
|
||||
bool exceptions_enabled = false;
|
||||
static char const* scope = "";
|
||||
bool exceptions_enabled = false;
|
||||
|
||||
class scope_guard {
|
||||
scope_guard& operator=(scope_guard const&);
|
||||
scope_guard(scope_guard const&);
|
||||
class scope_guard
|
||||
{
|
||||
scope_guard& operator=(scope_guard const&);
|
||||
scope_guard(scope_guard const&);
|
||||
|
||||
char const* old_scope_;
|
||||
char const* scope_;
|
||||
bool dismissed_;
|
||||
public:
|
||||
scope_guard(char const* name)
|
||||
: old_scope_(scope),
|
||||
scope_(name),
|
||||
dismissed_(false)
|
||||
{
|
||||
scope = scope_;
|
||||
}
|
||||
char const* old_scope_;
|
||||
char const* scope_;
|
||||
bool dismissed_;
|
||||
|
||||
~scope_guard() {
|
||||
if(dismissed_) scope = old_scope_;
|
||||
}
|
||||
|
||||
void dismiss() {
|
||||
dismissed_ = true;
|
||||
}
|
||||
|
||||
bool dismissed() const {
|
||||
return dismissed_;
|
||||
}
|
||||
};
|
||||
|
||||
class exceptions_enable
|
||||
public:
|
||||
scope_guard(char const* name)
|
||||
: old_scope_(scope), scope_(name), dismissed_(false)
|
||||
{
|
||||
exceptions_enable& operator=(exceptions_enable const&);
|
||||
exceptions_enable(exceptions_enable const&);
|
||||
|
||||
bool old_value_;
|
||||
public:
|
||||
exceptions_enable(bool enable)
|
||||
: old_value_(exceptions_enabled)
|
||||
{
|
||||
exceptions_enabled = enable;
|
||||
}
|
||||
|
||||
~exceptions_enable()
|
||||
{
|
||||
exceptions_enabled = old_value_;
|
||||
}
|
||||
};
|
||||
|
||||
struct exception_base {
|
||||
struct data_type {};
|
||||
struct strong_type {
|
||||
template <class T> void store(T const&) {}
|
||||
template <class T> void test(T const&) const {}
|
||||
};
|
||||
data_type init() const { return data_type(); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
|
||||
};
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)() const, T2 const& obj,
|
||||
P1&, P2&)
|
||||
{
|
||||
(obj.*fn)();
|
||||
scope = scope_;
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&) const, T2 const& obj,
|
||||
P1& p1, P2&)
|
||||
~scope_guard()
|
||||
{
|
||||
(obj.*fn)(p1);
|
||||
if (dismissed_)
|
||||
scope = old_scope_;
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&, P2&) const, T2 const& obj,
|
||||
P1& p1, P2& p2)
|
||||
void dismiss() { dismissed_ = true; }
|
||||
|
||||
bool dismissed() const { return dismissed_; }
|
||||
};
|
||||
|
||||
class exceptions_enable
|
||||
{
|
||||
exceptions_enable& operator=(exceptions_enable const&);
|
||||
exceptions_enable(exceptions_enable const&);
|
||||
|
||||
bool old_value_;
|
||||
bool released_;
|
||||
|
||||
public:
|
||||
exceptions_enable(bool enable)
|
||||
: old_value_(exceptions_enabled), released_(false)
|
||||
{
|
||||
(obj.*fn)(p1, p2);
|
||||
exceptions_enabled = enable;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T const& constant(T const& x) {
|
||||
return x;
|
||||
~exceptions_enable()
|
||||
{
|
||||
if (!released_) {
|
||||
exceptions_enabled = old_value_;
|
||||
released_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (!released_) {
|
||||
exceptions_enabled = old_value_;
|
||||
released_ = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct exception_base
|
||||
{
|
||||
struct data_type
|
||||
{
|
||||
};
|
||||
struct strong_type
|
||||
{
|
||||
template <class T> void store(T const&) {}
|
||||
template <class T> void test(T const&) const {}
|
||||
};
|
||||
data_type init() const { return data_type(); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
|
||||
};
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)() const, T2 const& obj, P1&, P2&)
|
||||
{
|
||||
(obj.*fn)();
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&) const, T2 const& obj, P1& p1, P2&)
|
||||
{
|
||||
(obj.*fn)(p1);
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&, P2&) const, T2 const& obj, P1& p1, P2& p2)
|
||||
{
|
||||
(obj.*fn)(p1, p2);
|
||||
}
|
||||
|
||||
template <class T> T const& constant(T const& x) { return x; }
|
||||
|
||||
template <class Test> class test_runner
|
||||
{
|
||||
Test const& test_;
|
||||
bool exception_in_check_;
|
||||
|
||||
test_runner(test_runner const&);
|
||||
test_runner& operator=(test_runner const&);
|
||||
|
||||
public:
|
||||
test_runner(Test const& t) : test_(t), exception_in_check_(false) {}
|
||||
void run()
|
||||
{
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_instances check;
|
||||
test::scope = "";
|
||||
typename Test::data_type x(test_.init());
|
||||
typename Test::strong_type strong;
|
||||
strong.store(x);
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
call_ignore_extra_parameters<Test, typename Test::data_type,
|
||||
typename Test::strong_type>(&Test::run, test_, x, strong);
|
||||
} catch (...) {
|
||||
try {
|
||||
DISABLE_EXCEPTIONS;
|
||||
call_ignore_extra_parameters<Test, typename Test::data_type const,
|
||||
typename Test::strong_type const>(
|
||||
&Test::check, test_, constant(x), constant(strong));
|
||||
} catch (...) {
|
||||
exception_in_check_ = true;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
void end()
|
||||
{
|
||||
if (exception_in_check_) {
|
||||
BOOST_ERROR("Unexcpected exception in test_runner check call.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Quick exception testing based on lightweight test
|
||||
|
||||
namespace lightweight {
|
||||
static int iteration;
|
||||
static int count;
|
||||
|
||||
struct test_exception
|
||||
{
|
||||
char const* name;
|
||||
test_exception(char const* n) : name(n) {}
|
||||
};
|
||||
|
||||
struct test_failure
|
||||
{
|
||||
};
|
||||
|
||||
void epoint(char const* name)
|
||||
{
|
||||
++count;
|
||||
if (count == iteration) {
|
||||
throw test_exception(name);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Test>
|
||||
class test_runner
|
||||
void exception_safety(Test const& f, char const* /*name*/)
|
||||
{
|
||||
Test const& test_;
|
||||
test_runner<Test> runner(f);
|
||||
|
||||
test_runner(test_runner const&);
|
||||
test_runner& operator=(test_runner const&);
|
||||
public:
|
||||
test_runner(Test const& t) : test_(t) {}
|
||||
void operator()() const {
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::scope = "";
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init());
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type strong;
|
||||
strong.store(x);
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
call_ignore_extra_parameters<
|
||||
Test,
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type,
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type
|
||||
>(&Test::run, test_, x, strong);
|
||||
}
|
||||
catch(...) {
|
||||
call_ignore_extra_parameters<
|
||||
Test,
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type const,
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type const
|
||||
>(&Test::check, test_, constant(x), constant(strong));
|
||||
throw;
|
||||
}
|
||||
iteration = 0;
|
||||
bool success = false;
|
||||
unsigned int failure_count = 0;
|
||||
char const* error_msg = 0;
|
||||
do {
|
||||
int error_count = boost::detail::test_errors();
|
||||
++iteration;
|
||||
count = 0;
|
||||
|
||||
try {
|
||||
runner.run();
|
||||
success = true;
|
||||
} catch (test_failure) {
|
||||
error_msg = "test_failure caught.";
|
||||
break;
|
||||
} catch (test_exception e) {
|
||||
if (error_count != boost::detail::test_errors()) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM
|
||||
<< "Iteration: " << iteration
|
||||
<< " Error found for epoint: " << e.name << std::endl;
|
||||
}
|
||||
} catch (...) {
|
||||
error_msg = "Unexpected exception.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (error_count != boost::detail::test_errors()) {
|
||||
++failure_count;
|
||||
}
|
||||
} while (!success && failure_count < 5);
|
||||
|
||||
if (error_msg) {
|
||||
BOOST_ERROR(error_msg);
|
||||
}
|
||||
runner.end();
|
||||
}
|
||||
|
||||
//
|
||||
// An alternative way to run exception tests.
|
||||
// See merge_exception_tests.cpp for an example.
|
||||
|
||||
struct exception_looper
|
||||
{
|
||||
bool success;
|
||||
unsigned int failure_count;
|
||||
char const* error_msg;
|
||||
int error_count;
|
||||
|
||||
exception_looper() : success(false), failure_count(0), error_msg(0) {}
|
||||
|
||||
void start() { iteration = 0; }
|
||||
|
||||
bool loop_condition() const
|
||||
{
|
||||
return !error_msg && !success && failure_count < 5;
|
||||
}
|
||||
|
||||
void start_iteration()
|
||||
{
|
||||
error_count = boost::detail::test_errors();
|
||||
++iteration;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
void successful_run() { success = true; }
|
||||
|
||||
void test_failure_caught(test_failure const&)
|
||||
{
|
||||
error_msg = "test_failure caught.";
|
||||
}
|
||||
|
||||
void test_exception_caught(test_exception const& e)
|
||||
{
|
||||
if (error_count != boost::detail::test_errors()) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM
|
||||
<< "Iteration: " << iteration
|
||||
<< " Error found for epoint: " << e.name << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void unexpected_exception_caught()
|
||||
{
|
||||
error_msg = "Unexpected exception.";
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
if (error_msg) {
|
||||
BOOST_ERROR(error_msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Quick exception testing based on lightweight test
|
||||
|
||||
namespace lightweight {
|
||||
static int iteration;
|
||||
static int count;
|
||||
|
||||
struct test_exception {
|
||||
char const* name;
|
||||
test_exception(char const* n) : name(n) {}
|
||||
};
|
||||
|
||||
struct test_failure {
|
||||
};
|
||||
|
||||
void epoint(char const* name) {
|
||||
++count;
|
||||
if(count == iteration) {
|
||||
throw test_exception(name);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Test>
|
||||
void exception_safety(Test const& f, char const* /*name*/) {
|
||||
test_runner<Test> runner(f);
|
||||
|
||||
iteration = 0;
|
||||
bool success = false;
|
||||
do {
|
||||
++iteration;
|
||||
count = 0;
|
||||
|
||||
try {
|
||||
runner();
|
||||
success = true;
|
||||
}
|
||||
catch(test_failure) {
|
||||
BOOST_ERROR("test_failure caught.");
|
||||
break;
|
||||
}
|
||||
catch(test_exception) {
|
||||
continue;
|
||||
}
|
||||
catch(...) {
|
||||
BOOST_ERROR("Unexpected exception.");
|
||||
break;
|
||||
}
|
||||
} while(!success);
|
||||
}
|
||||
}
|
||||
#define EXCEPTION_LOOP(op) \
|
||||
test::lightweight::exception_looper looper; \
|
||||
looper.start(); \
|
||||
while (looper.loop_condition()) { \
|
||||
looper.start_iteration(); \
|
||||
try { \
|
||||
op; \
|
||||
looper.successful_run(); \
|
||||
} catch (test::lightweight::test_failure e) { \
|
||||
looper.test_failure_caught(e); \
|
||||
} catch (test::lightweight::test_exception e) { \
|
||||
looper.test_exception_caught(e); \
|
||||
} catch (...) { \
|
||||
looper.unexpected_exception_caught(); \
|
||||
} \
|
||||
} \
|
||||
looper.end();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -8,17 +8,25 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace test
|
||||
{
|
||||
int generate(int const*);
|
||||
char generate(char const*);
|
||||
signed char generate(signed char const*);
|
||||
std::string generate(std::string*);
|
||||
float generate(float const*);
|
||||
namespace test {
|
||||
typedef enum {
|
||||
default_generator,
|
||||
generate_collisions,
|
||||
limited_range
|
||||
} random_generator;
|
||||
|
||||
struct base_type {} base;
|
||||
struct derived_type : base_type {} derived;
|
||||
int generate(int const*, random_generator);
|
||||
char generate(char const*, random_generator);
|
||||
signed char generate(signed char const*, random_generator);
|
||||
std::string generate(std::string const*, random_generator);
|
||||
float generate(float const*, random_generator);
|
||||
|
||||
struct base_type
|
||||
{
|
||||
} base;
|
||||
struct derived_type : base_type
|
||||
{
|
||||
} derived;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -11,60 +11,83 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER
|
||||
|
||||
#include "./fwd.hpp"
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include "./fwd.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
struct seed_t {
|
||||
seed_t(unsigned int x) {
|
||||
using namespace std;
|
||||
srand(x);
|
||||
}
|
||||
};
|
||||
|
||||
inline int generate(int const*)
|
||||
namespace test {
|
||||
struct seed_t
|
||||
{
|
||||
seed_t(unsigned int x)
|
||||
{
|
||||
using namespace std;
|
||||
return rand();
|
||||
using namespace std;
|
||||
srand(x);
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t random_value(std::size_t max)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<std::size_t>(rand()) % max;
|
||||
}
|
||||
|
||||
inline int generate(int const*, random_generator g)
|
||||
{
|
||||
using namespace std;
|
||||
int value = rand();
|
||||
if (g == limited_range) {
|
||||
value = value % 100;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
inline char generate(char const*, random_generator)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<char>((rand() >> 1) % (128 - 32) + 32);
|
||||
}
|
||||
|
||||
inline signed char generate(signed char const*, random_generator)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<signed char>(rand());
|
||||
}
|
||||
|
||||
inline std::string generate(std::string const*, random_generator g)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
char* char_ptr = 0;
|
||||
|
||||
std::string result;
|
||||
|
||||
if (g == limited_range) {
|
||||
std::size_t length = test::random_value(2) + 2;
|
||||
|
||||
char const* strings[] = {"'vZh(3~ms", "%m", "_Y%U", "N'Y", "4,J_J"};
|
||||
for (std::size_t i = 0; i < length; ++i) {
|
||||
result += strings[random_value(sizeof(strings) / sizeof(strings[0]))];
|
||||
}
|
||||
} else {
|
||||
std::size_t length = test::random_value(10) + 1;
|
||||
for (std::size_t i = 0; i < length; ++i) {
|
||||
result += generate(char_ptr, g);
|
||||
}
|
||||
}
|
||||
|
||||
inline char generate(char const*)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<char>((rand() >> 1) % (128-32) + 32);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline signed char generate(signed char const*)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<signed char>(rand());
|
||||
}
|
||||
|
||||
inline std::string generate(std::string const*)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
char* char_ptr = 0;
|
||||
|
||||
std::string result;
|
||||
|
||||
int length = rand() % 10;
|
||||
for(int i = 0; i < length; ++i)
|
||||
result += generate(char_ptr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float generate(float const*)
|
||||
{
|
||||
using namespace std;
|
||||
return (float) rand() / (float) RAND_MAX;
|
||||
}
|
||||
float generate(float const*, random_generator g)
|
||||
{
|
||||
using namespace std;
|
||||
int x = 0;
|
||||
int value = generate(&x, g);
|
||||
return (float)value / (float)RAND_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,38 +6,51 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_HEADER
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class Container>
|
||||
struct get_key_impl
|
||||
#include <iterator>
|
||||
|
||||
namespace test {
|
||||
template <class Container> struct get_key_impl
|
||||
{
|
||||
typedef typename Container::key_type key_type;
|
||||
|
||||
static key_type const& get_key(key_type const& x) { return x; }
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(std::pair<key_type, T> const& x, char = 0)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Container::key_type key_type;
|
||||
|
||||
static key_type const& get_key(key_type const& x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(
|
||||
std::pair<key_type, T> const& x, char = 0)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(std::pair<key_type const, T> const& x,
|
||||
unsigned char = 0)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Container, class T>
|
||||
inline BOOST_DEDUCED_TYPENAME Container::key_type const& get_key(T const& x)
|
||||
{
|
||||
return get_key_impl<Container>::get_key(x);
|
||||
return x.first;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(
|
||||
std::pair<key_type const, T> const& x, unsigned char = 0)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Container, class T>
|
||||
inline typename Container::key_type const& get_key(T const& x)
|
||||
{
|
||||
return get_key_impl<Container>::get_key(x);
|
||||
}
|
||||
|
||||
// test::next
|
||||
//
|
||||
// Increments an iterator by 1 or a given value.
|
||||
// Like boost::next, but simpler.
|
||||
// Mainly because boost::next uses an MPL file
|
||||
// which causes warnings.
|
||||
|
||||
template <typename Iterator> Iterator next(Iterator it) { return ++it; }
|
||||
|
||||
template <typename Iterator, typename IntType>
|
||||
Iterator next(Iterator it, IntType x)
|
||||
{
|
||||
std::advance(it,
|
||||
static_cast<typename std::iterator_traits<Iterator>::difference_type>(x));
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2005-2010 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)
|
||||
|
||||
@ -7,69 +7,159 @@
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
#include <boost/iterator/iterator_traits.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class Iterator>
|
||||
struct proxy
|
||||
namespace test {
|
||||
template <class Iterator> struct proxy
|
||||
{
|
||||
typedef typename Iterator::value_type value_type;
|
||||
|
||||
explicit proxy(value_type const& v) : v_(v) {}
|
||||
proxy(proxy const& x) : v_(x.v_) {}
|
||||
operator value_type const&() const { return v_; }
|
||||
|
||||
value_type v_;
|
||||
|
||||
private:
|
||||
proxy& operator=(proxy const&);
|
||||
};
|
||||
|
||||
template <class Iterator> struct input_iterator_adaptor
|
||||
{
|
||||
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||||
typedef typename std::iterator_traits<Iterator>::pointer pointer;
|
||||
typedef proxy<Iterator> reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
|
||||
input_iterator_adaptor() : base_() {}
|
||||
explicit input_iterator_adaptor(Iterator& it) : base_(&it) {}
|
||||
proxy<Iterator> operator*() const { return proxy<Iterator>(**base_); }
|
||||
value_type* operator->() const { return &**base_; }
|
||||
input_iterator_adaptor& operator++()
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Iterator::value_type value_type;
|
||||
|
||||
explicit proxy(value_type const& v) : v_(v) {}
|
||||
proxy(proxy const& x) : v_(x.v_) {}
|
||||
operator value_type const&() const { return v_; }
|
||||
|
||||
value_type v_;
|
||||
private:
|
||||
proxy& operator=(proxy const&);
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
struct input_iterator_adaptor
|
||||
: public boost::iterator<
|
||||
std::input_iterator_tag,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type,
|
||||
std::ptrdiff_t,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_pointer<Iterator>::type,
|
||||
proxy<Iterator>
|
||||
>
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type
|
||||
value_type;
|
||||
|
||||
input_iterator_adaptor()
|
||||
: base_() {}
|
||||
explicit input_iterator_adaptor(Iterator& it)
|
||||
: base_(&it) {}
|
||||
proxy<Iterator> operator*() const {
|
||||
return proxy<Iterator>(**base_);
|
||||
}
|
||||
value_type* operator->() const {
|
||||
return &**base_;
|
||||
}
|
||||
input_iterator_adaptor& operator++() {
|
||||
++*base_; return *this;
|
||||
}
|
||||
//input_iterator_adaptor operator++(int) {
|
||||
//}
|
||||
bool operator==(input_iterator_adaptor const& x) const {
|
||||
return *base_ == *x.base_;
|
||||
}
|
||||
bool operator!=(input_iterator_adaptor const& x) const {
|
||||
return *base_ != *x.base_;
|
||||
}
|
||||
private:
|
||||
Iterator* base_;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
input_iterator_adaptor<Iterator> input_iterator(Iterator& it)
|
||||
{
|
||||
return input_iterator_adaptor<Iterator>(it);
|
||||
++*base_;
|
||||
return *this;
|
||||
}
|
||||
// input_iterator_adaptor operator++(int) {
|
||||
//}
|
||||
bool operator==(input_iterator_adaptor const& x) const
|
||||
{
|
||||
return *base_ == *x.base_;
|
||||
}
|
||||
bool operator!=(input_iterator_adaptor const& x) const
|
||||
{
|
||||
return *base_ != *x.base_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator* base_;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
input_iterator_adaptor<Iterator> input_iterator(Iterator& it)
|
||||
{
|
||||
return input_iterator_adaptor<Iterator>(it);
|
||||
}
|
||||
|
||||
template <class Iterator> struct copy_iterator_adaptor
|
||||
{
|
||||
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||||
typedef
|
||||
typename std::iterator_traits<Iterator>::difference_type difference_type;
|
||||
typedef typename std::iterator_traits<Iterator>::iterator_category
|
||||
iterator_category;
|
||||
typedef typename std::iterator_traits<Iterator>::pointer pointer;
|
||||
typedef proxy<Iterator> reference;
|
||||
|
||||
copy_iterator_adaptor() : base_() {}
|
||||
explicit copy_iterator_adaptor(Iterator const& it) : base_(it) {}
|
||||
value_type operator*() const { return *base_; }
|
||||
value_type* operator->() const { return &*base_; }
|
||||
value_type operator[](difference_type d) { return base_[d]; }
|
||||
copy_iterator_adaptor& operator++()
|
||||
{
|
||||
++base_;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator++(int)
|
||||
{
|
||||
copy_iterator_adaptor tmp(*this);
|
||||
++base_;
|
||||
return tmp;
|
||||
}
|
||||
copy_iterator_adaptor& operator--()
|
||||
{
|
||||
--base_;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator--(int)
|
||||
{
|
||||
copy_iterator_adaptor tmp(*this);
|
||||
--base_;
|
||||
return tmp;
|
||||
}
|
||||
copy_iterator_adaptor operator+=(difference_type x)
|
||||
{
|
||||
base_ += x;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator-=(difference_type x)
|
||||
{
|
||||
base_ -= x;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator+(difference_type n)
|
||||
{
|
||||
return copy_iterator_adaptor(base_ + n);
|
||||
}
|
||||
copy_iterator_adaptor operator-(difference_type n)
|
||||
{
|
||||
return copy_iterator_adaptor(base_ - n);
|
||||
}
|
||||
friend copy_iterator_adaptor operator+(
|
||||
difference_type n, copy_iterator_adaptor x)
|
||||
{
|
||||
return x + n;
|
||||
}
|
||||
difference_type operator-(copy_iterator_adaptor const& other)
|
||||
{
|
||||
return base_ - other.base_;
|
||||
}
|
||||
bool operator==(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ == x.base_;
|
||||
}
|
||||
bool operator!=(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ != x.base_;
|
||||
}
|
||||
bool operator<(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ < x.base_;
|
||||
}
|
||||
bool operator>(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ > x.base_;
|
||||
}
|
||||
bool operator<=(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ <= x.base_;
|
||||
}
|
||||
bool operator>=(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ >= x.base_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator base_;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
copy_iterator_adaptor<Iterator> copy_iterator(Iterator const& it)
|
||||
{
|
||||
return copy_iterator_adaptor<Iterator>(it);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -9,99 +9,118 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER
|
||||
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./helpers.hpp"
|
||||
#include "./allocator.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data
|
||||
#endif
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class X>
|
||||
void check_equivalent_keys(X const& x1)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal eq = x1.key_eq();
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
// Boost.Test was reporting memory leaks for std::set on g++-3.3.
|
||||
// So I work around it by using malloc.
|
||||
std::set<key_type, std::less<key_type>,
|
||||
test::malloc_allocator<key_type> > found_;
|
||||
namespace test {
|
||||
template <class X> void check_equivalent_keys(X const& x1)
|
||||
{
|
||||
typename X::key_equal eq = x1.key_eq();
|
||||
typedef typename X::key_type key_type;
|
||||
std::set<key_type, std::less<key_type> > found_;
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator
|
||||
it = x1.begin(), end = x1.end();
|
||||
BOOST_DEDUCED_TYPENAME X::size_type size = 0;
|
||||
while(it != end) {
|
||||
// First test that the current key has not occured before, required
|
||||
// to test either that keys are unique or that equivalent keys are
|
||||
// adjacent. (6.3.1/6)
|
||||
key_type key = get_key<X>(*it);
|
||||
if(!found_.insert(key).second)
|
||||
BOOST_ERROR("Elements with equivalent keys aren't adjacent.");
|
||||
typename X::const_iterator it = x1.begin(), end = x1.end();
|
||||
typename X::size_type size = 0;
|
||||
while (it != end) {
|
||||
// First test that the current key has not occurred before, required
|
||||
// to test either that keys are unique or that equivalent keys are
|
||||
// adjacent. (6.3.1/6)
|
||||
key_type key = get_key<X>(*it);
|
||||
if (!found_.insert(key).second)
|
||||
BOOST_ERROR("Elements with equivalent keys aren't adjacent.");
|
||||
|
||||
// Iterate over equivalent keys, counting them.
|
||||
unsigned int count = 0;
|
||||
do {
|
||||
++it;
|
||||
++count;
|
||||
++size;
|
||||
} while(it != end && eq(get_key<X>(*it), key));
|
||||
// Iterate over equivalent keys, counting them.
|
||||
unsigned int count = 0;
|
||||
do {
|
||||
++it;
|
||||
++count;
|
||||
++size;
|
||||
} while (it != end && eq(get_key<X>(*it), key));
|
||||
|
||||
// If the container has unique keys, test that there's only one.
|
||||
// Since the previous test makes sure that all equivalent keys are
|
||||
// adjacent, this is all the equivalent keys - so the test is
|
||||
// sufficient. (6.3.1/6 again).
|
||||
if(test::has_unique_keys<X>::value && count != 1)
|
||||
BOOST_ERROR("Non-unique key.");
|
||||
// If the container has unique keys, test that there's only one.
|
||||
// Since the previous test makes sure that all equivalent keys are
|
||||
// adjacent, this is all the equivalent keys - so the test is
|
||||
// sufficient. (6.3.1/6 again).
|
||||
if (test::has_unique_keys<X>::value && count != 1)
|
||||
BOOST_ERROR("Non-unique key.");
|
||||
|
||||
if(x1.count(key) != count) {
|
||||
BOOST_ERROR("Incorrect output of count.");
|
||||
std::cerr<<x1.count(key)<<","<<count<<"\n";
|
||||
}
|
||||
if (x1.count(key) != count) {
|
||||
BOOST_ERROR("Incorrect output of count.");
|
||||
std::cerr << x1.count(key) << "," << count << "\n";
|
||||
}
|
||||
|
||||
// I'm not bothering with the following test for now, as the
|
||||
// previous test is probably more enough to catch the kind of
|
||||
// errors that this would catch (if an element was in the wrong
|
||||
// bucket it not be found by the call to count, if elements are not
|
||||
// adjacent then they would be caught when checking against
|
||||
// found_.
|
||||
// Check that the keys are in the correct bucket and are
|
||||
// adjacent in the bucket.
|
||||
typename X::size_type bucket = x1.bucket(key);
|
||||
typename X::const_local_iterator lit = x1.begin(bucket),
|
||||
lend = x1.end(bucket);
|
||||
|
||||
// // Check that the keys are in the correct bucket and are
|
||||
// // adjacent in the bucket.
|
||||
// BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
|
||||
// BOOST_DEDUCED_TYPENAME X::const_local_iterator
|
||||
// lit = x1.begin(bucket), lend = x1.end(bucket);
|
||||
// for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
||||
// if(lit == lend)
|
||||
// BOOST_ERROR("Unable to find element with a local_iterator");
|
||||
// unsigned int count2 = 0;
|
||||
// for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
|
||||
// if(count != count2)
|
||||
// BOOST_ERROR("Element count doesn't match local_iterator.");
|
||||
// for(; lit != lend; ++lit) {
|
||||
// if(eq(get_key<X>(*lit), key)) {
|
||||
// BOOST_ERROR("Non-adjacent element with equivalent key "
|
||||
// "in bucket.");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
};
|
||||
unsigned int count_checked = 0;
|
||||
for (; lit != lend && !eq(get_key<X>(*lit), key); ++lit) {
|
||||
++count_checked;
|
||||
}
|
||||
|
||||
// Finally, check that size matches up.
|
||||
if(x1.size() != size)
|
||||
BOOST_ERROR("x1.size() doesn't match actual size.");
|
||||
float load_factor =
|
||||
static_cast<float>(size) / static_cast<float>(x1.bucket_count());
|
||||
using namespace std;
|
||||
if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
|
||||
BOOST_ERROR("x1.load_factor() doesn't match actual load_factor.");
|
||||
if (lit == lend) {
|
||||
BOOST_ERROR("Unable to find element with a local_iterator");
|
||||
std::cerr << "Checked: " << count_checked << " elements" << std::endl;
|
||||
} else {
|
||||
unsigned int count2 = 0;
|
||||
for (; lit != lend && eq(get_key<X>(*lit), key); ++lit)
|
||||
++count2;
|
||||
if (count != count2)
|
||||
BOOST_ERROR("Element count doesn't match local_iterator.");
|
||||
for (; lit != lend; ++lit) {
|
||||
if (eq(get_key<X>(*lit), key)) {
|
||||
BOOST_ERROR("Non-adjacent element with equivalent key "
|
||||
"in bucket.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Check that size matches up.
|
||||
|
||||
if (x1.size() != size) {
|
||||
BOOST_ERROR("x1.size() doesn't match actual size.");
|
||||
std::cout << x1.size() << "/" << size << std::endl;
|
||||
}
|
||||
|
||||
// Check the load factor.
|
||||
|
||||
float load_factor = size == 0 ? 0
|
||||
: static_cast<float>(size) /
|
||||
static_cast<float>(x1.bucket_count());
|
||||
using namespace std;
|
||||
if (fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
|
||||
BOOST_ERROR("x1.load_factor() doesn't match actual load_factor.");
|
||||
|
||||
// Check that size in the buckets matches up.
|
||||
|
||||
typename X::size_type bucket_size = 0;
|
||||
|
||||
for (typename X::size_type i = 0; i < x1.bucket_count(); ++i) {
|
||||
for (typename X::const_local_iterator begin2 = x1.begin(i),
|
||||
end2 = x1.end(i);
|
||||
begin2 != end2; ++begin2) {
|
||||
++bucket_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (x1.size() != bucket_size) {
|
||||
BOOST_ERROR("x1.size() doesn't match bucket size.");
|
||||
std::cout << x1.size() << "/" << bucket_size << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
@ -109,4 +128,3 @@ namespace test
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -11,308 +11,317 @@
|
||||
#if !defined(UNORDERED_TEST_LIST_HEADER)
|
||||
#define UNORDERED_TEST_LIST_HEADER
|
||||
|
||||
#include <boost/iterator.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <typename It1, typename It2>
|
||||
bool equal(It1 begin, It1 end, It2 compare)
|
||||
namespace test {
|
||||
template <typename It1, typename It2>
|
||||
bool equal(It1 begin, It1 end, It2 compare)
|
||||
{
|
||||
for (; begin != end; ++begin, ++compare)
|
||||
if (*begin != *compare)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename It1, typename It2, typename Pred>
|
||||
bool equal(It1 begin, It1 end, It2 compare, Pred predicate)
|
||||
{
|
||||
for (; begin != end; ++begin, ++compare)
|
||||
if (!predicate(*begin, *compare))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> class list;
|
||||
|
||||
namespace test_detail {
|
||||
template <typename T> class list_node;
|
||||
template <typename T> class list_data;
|
||||
template <typename T> class list_iterator;
|
||||
template <typename T> class list_const_iterator;
|
||||
|
||||
template <typename T> class list_node
|
||||
{
|
||||
for(;begin != end; ++begin, ++compare)
|
||||
if(*begin != *compare) return false;
|
||||
return true;
|
||||
}
|
||||
list_node(list_node const&);
|
||||
list_node& operator=(list_node const&);
|
||||
|
||||
template <typename It1, typename It2, typename Pred>
|
||||
bool equal(It1 begin, It1 end, It2 compare, Pred predicate)
|
||||
{
|
||||
for(;begin != end; ++begin, ++compare)
|
||||
if(!predicate(*begin, *compare)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename T> class list;
|
||||
|
||||
namespace test_detail
|
||||
{
|
||||
template <typename T> class list_node;
|
||||
template <typename T> class list_data;
|
||||
template <typename T> class list_iterator;
|
||||
template <typename T> class list_const_iterator;
|
||||
|
||||
template <typename T>
|
||||
class list_node
|
||||
{
|
||||
list_node(list_node const&);
|
||||
list_node& operator=(list_node const&);
|
||||
public:
|
||||
T value_;
|
||||
list_node* next_;
|
||||
|
||||
list_node(T const& v) : value_(v), next_(0) {}
|
||||
list_node(T const& v, list_node* n) : value_(v), next_(n) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class list_data
|
||||
{
|
||||
public:
|
||||
typedef list_node<T> node;
|
||||
typedef unsigned int size_type;
|
||||
|
||||
node* first_;
|
||||
node** last_ptr_;
|
||||
size_type size_;
|
||||
|
||||
list_data() : first_(0), last_ptr_(&first_), size_(0) {}
|
||||
|
||||
~list_data() {
|
||||
while(first_) {
|
||||
node* tmp = first_;
|
||||
first_ = first_->next_;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
private:
|
||||
list_data(list_data const&);
|
||||
list_data& operator=(list_data const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class list_iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag, T,
|
||||
int, T*, T&>
|
||||
{
|
||||
friend class list_const_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
public:
|
||||
list_iterator() : ptr_(0) {};
|
||||
explicit list_iterator(node* x) : ptr_(x) {}
|
||||
|
||||
T& operator*() const { return ptr_->value_; }
|
||||
T* operator->() const { return &ptr_->value_; }
|
||||
list_iterator& operator++() {
|
||||
ptr_ = ptr_->next_; return *this; }
|
||||
list_iterator operator++(int) {
|
||||
list_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; }
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class list_const_iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag, T,
|
||||
int, T const*, T const&>
|
||||
{
|
||||
friend class list_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_iterator<T> iterator;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
public:
|
||||
list_const_iterator() : ptr_(0) {}
|
||||
list_const_iterator(list_iterator<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return ptr_->value_; }
|
||||
T const* operator->() const { return &ptr_->value_; }
|
||||
|
||||
list_const_iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_const_iterator operator++(int)
|
||||
{
|
||||
list_const_iterator tmp = *this;
|
||||
ptr_ = ptr_->next_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const_iterator y) const
|
||||
{
|
||||
return ptr_ == y.ptr_;
|
||||
}
|
||||
|
||||
bool operator!=(const_iterator y) const
|
||||
{
|
||||
return ptr_ != y.ptr_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class list
|
||||
{
|
||||
typedef test::test_detail::list_data<T> data;
|
||||
typedef test::test_detail::list_node<T> node;
|
||||
data data_;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const& const_reference;
|
||||
typedef unsigned int size_type;
|
||||
T value_;
|
||||
list_node* next_;
|
||||
|
||||
typedef test::test_detail::list_iterator<T> iterator;
|
||||
typedef test::test_detail::list_const_iterator<T> const_iterator;
|
||||
list_node(T const& v) : value_(v), next_(0) {}
|
||||
list_node(T const& v, list_node* n) : value_(v), next_(n) {}
|
||||
};
|
||||
|
||||
list() : data_() {}
|
||||
template <typename T> class list_data
|
||||
{
|
||||
public:
|
||||
typedef list_node<T> node;
|
||||
typedef unsigned int size_type;
|
||||
|
||||
list(list const& other) : data_() {
|
||||
insert(other.begin(), other.end());
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
list(InputIterator i, InputIterator j) : data_() {
|
||||
insert(i, j);
|
||||
}
|
||||
|
||||
list& operator=(list const& other) {
|
||||
clear();
|
||||
insert(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(data_.first_); }
|
||||
iterator end() { return iterator(); }
|
||||
const_iterator begin() const { return iterator(data_.first_); }
|
||||
const_iterator end() const { return iterator(); }
|
||||
const_iterator cbegin() const { return iterator(data_.first_); }
|
||||
const_iterator cend() const { return iterator(); }
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator i, InputIterator j) {
|
||||
for(; i != j; ++i)
|
||||
push_back(*i);
|
||||
}
|
||||
|
||||
void push_front(value_type const& v) {
|
||||
data_.first_ = new node(v, data_.first_);
|
||||
if(!data_.size_) data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void push_back(value_type const& v) {
|
||||
*data_.last_ptr_ = new node(v);
|
||||
data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
while(data_.first_) {
|
||||
node* tmp = data_.first_;
|
||||
data_.first_ = data_.first_->next_;
|
||||
--data_.size_;
|
||||
delete tmp;
|
||||
}
|
||||
data_.last_ptr_ = &data_.first_;
|
||||
}
|
||||
|
||||
void erase(const_iterator start, const_iterator end) {
|
||||
node** ptr = &data_.first_;
|
||||
|
||||
while(*ptr != start.ptr_) {
|
||||
ptr = &(*ptr)->next_;
|
||||
}
|
||||
|
||||
while(*ptr != end.ptr_) {
|
||||
node* to_delete = *ptr;
|
||||
*ptr = (*ptr)->next_;
|
||||
--data_.size_;
|
||||
delete to_delete;
|
||||
}
|
||||
|
||||
if(!*ptr) data_.last_ptr_ = ptr;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return !data_.size_;
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return data_.size_;
|
||||
}
|
||||
|
||||
void sort() {
|
||||
sort(std::less<T>());
|
||||
}
|
||||
|
||||
template <typename Less>
|
||||
void sort(Less less = Less()) {
|
||||
if(!empty()) merge_sort(&data_.first_,
|
||||
(std::numeric_limits<size_type>::max)(), less);
|
||||
}
|
||||
|
||||
bool operator==(list const& y) const {
|
||||
return size() == y.size() &&
|
||||
test::equal(begin(), end(), y.begin());
|
||||
}
|
||||
|
||||
bool operator!=(list const& y) const {
|
||||
return !(*this == y);
|
||||
node* first_;
|
||||
node** last_ptr_;
|
||||
size_type size_;
|
||||
|
||||
list_data() : first_(0), last_ptr_(&first_), size_(0) {}
|
||||
|
||||
~list_data()
|
||||
{
|
||||
while (first_) {
|
||||
node* tmp = first_;
|
||||
first_ = first_->next_;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Less>
|
||||
node** merge_sort(node** l, size_type recurse_limit, Less less)
|
||||
{
|
||||
node** ptr = &(*l)->next_;
|
||||
for(size_type count = 0; count < recurse_limit && *ptr; ++count)
|
||||
{
|
||||
ptr = merge_adjacent_ranges(l, ptr,
|
||||
merge_sort(ptr, count, less), less);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename Less>
|
||||
node** merge_adjacent_ranges(node** first, node** second,
|
||||
node** third, Less less)
|
||||
{
|
||||
for(;;) {
|
||||
for(;;) {
|
||||
if(first == second) return third;
|
||||
if(less((*second)->value_, (*first)->value_)) break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, second, third);
|
||||
first = &(*first)->next_;
|
||||
|
||||
// Since the two ranges we just swapped, the order is now:
|
||||
// first...third...second
|
||||
|
||||
for(;;) {
|
||||
if(first == third) return second;
|
||||
if(!less((*first)->value_, (*third)->value_)) break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, third, second);
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
}
|
||||
|
||||
void swap_adjacent_ranges(node** first, node** second, node** third)
|
||||
{
|
||||
node* tmp = *first;
|
||||
*first = *second;
|
||||
*second = *third;
|
||||
*third = tmp;
|
||||
if(!*second) data_.last_ptr_ = second;
|
||||
}
|
||||
list_data(list_data const&);
|
||||
list_data& operator=(list_data const&);
|
||||
};
|
||||
|
||||
template <typename T> class list_iterator
|
||||
{
|
||||
friend class list_const_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
list_iterator() : ptr_(0) {}
|
||||
explicit list_iterator(node* x) : ptr_(x) {}
|
||||
|
||||
T& operator*() const { return ptr_->value_; }
|
||||
T* operator->() const { return &ptr_->value_; }
|
||||
list_iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
list_iterator operator++(int)
|
||||
{
|
||||
list_iterator tmp = *this;
|
||||
ptr_ = ptr_->next_;
|
||||
return tmp;
|
||||
}
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
};
|
||||
|
||||
template <typename T> class list_const_iterator
|
||||
{
|
||||
friend class list_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_iterator<T> iterator;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T const* pointer;
|
||||
typedef T const& reference;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
list_const_iterator() : ptr_(0) {}
|
||||
list_const_iterator(list_iterator<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return ptr_->value_; }
|
||||
T const* operator->() const { return &ptr_->value_; }
|
||||
|
||||
list_const_iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_const_iterator operator++(int)
|
||||
{
|
||||
list_const_iterator tmp = *this;
|
||||
ptr_ = ptr_->next_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T> class list
|
||||
{
|
||||
typedef test::test_detail::list_data<T> data;
|
||||
typedef test::test_detail::list_node<T> node;
|
||||
data data_;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const& const_reference;
|
||||
typedef unsigned int size_type;
|
||||
|
||||
typedef test::test_detail::list_iterator<T> iterator;
|
||||
typedef test::test_detail::list_const_iterator<T> const_iterator;
|
||||
|
||||
list() : data_() {}
|
||||
|
||||
list(list const& other) : data_() { insert(other.begin(), other.end()); }
|
||||
|
||||
template <class InputIterator>
|
||||
list(InputIterator i, InputIterator j) : data_()
|
||||
{
|
||||
insert(i, j);
|
||||
}
|
||||
|
||||
list& operator=(list const& other)
|
||||
{
|
||||
clear();
|
||||
insert(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(data_.first_); }
|
||||
iterator end() { return iterator(); }
|
||||
const_iterator begin() const { return iterator(data_.first_); }
|
||||
const_iterator end() const { return iterator(); }
|
||||
const_iterator cbegin() const { return iterator(data_.first_); }
|
||||
const_iterator cend() const { return iterator(); }
|
||||
|
||||
template <class InputIterator> void insert(InputIterator i, InputIterator j)
|
||||
{
|
||||
for (; i != j; ++i)
|
||||
push_back(*i);
|
||||
}
|
||||
|
||||
void push_front(value_type const& v)
|
||||
{
|
||||
data_.first_ = new node(v, data_.first_);
|
||||
if (!data_.size_)
|
||||
data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void push_back(value_type const& v)
|
||||
{
|
||||
*data_.last_ptr_ = new node(v);
|
||||
data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
while (data_.first_) {
|
||||
node* tmp = data_.first_;
|
||||
data_.first_ = data_.first_->next_;
|
||||
--data_.size_;
|
||||
delete tmp;
|
||||
}
|
||||
data_.last_ptr_ = &data_.first_;
|
||||
}
|
||||
|
||||
void erase(const_iterator i, const_iterator j)
|
||||
{
|
||||
node** ptr = &data_.first_;
|
||||
|
||||
while (*ptr != i.ptr_) {
|
||||
ptr = &(*ptr)->next_;
|
||||
}
|
||||
|
||||
while (*ptr != j.ptr_) {
|
||||
node* to_delete = *ptr;
|
||||
*ptr = (*ptr)->next_;
|
||||
--data_.size_;
|
||||
delete to_delete;
|
||||
}
|
||||
|
||||
if (!*ptr)
|
||||
data_.last_ptr_ = ptr;
|
||||
}
|
||||
|
||||
bool empty() const { return !data_.size_; }
|
||||
|
||||
size_type size() const { return data_.size_; }
|
||||
|
||||
void sort() { sort(std::less<T>()); }
|
||||
|
||||
template <typename Less> void sort(Less less = Less())
|
||||
{
|
||||
if (!empty())
|
||||
merge_sort(
|
||||
&data_.first_, (std::numeric_limits<size_type>::max)(), less);
|
||||
}
|
||||
|
||||
bool operator==(list const& y) const
|
||||
{
|
||||
return size() == y.size() && test::equal(begin(), end(), y.begin());
|
||||
}
|
||||
|
||||
bool operator!=(list const& y) const { return !(*this == y); }
|
||||
|
||||
private:
|
||||
template <typename Less>
|
||||
node** merge_sort(node** l, size_type recurse_limit, Less less)
|
||||
{
|
||||
node** ptr = &(*l)->next_;
|
||||
for (size_type count = 0; count < recurse_limit && *ptr; ++count) {
|
||||
ptr = merge_adjacent_ranges(l, ptr, merge_sort(ptr, count, less), less);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename Less>
|
||||
node** merge_adjacent_ranges(
|
||||
node** first, node** second, node** third, Less less)
|
||||
{
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
if (first == second)
|
||||
return third;
|
||||
if (less((*second)->value_, (*first)->value_))
|
||||
break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, second, third);
|
||||
first = &(*first)->next_;
|
||||
|
||||
// Since the two ranges we just swapped, the order is now:
|
||||
// first...third...second
|
||||
|
||||
for (;;) {
|
||||
if (first == third)
|
||||
return second;
|
||||
if (!less((*first)->value_, (*third)->value_))
|
||||
break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, third, second);
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
}
|
||||
|
||||
void swap_adjacent_ranges(node** first, node** second, node** third)
|
||||
{
|
||||
node* tmp = *first;
|
||||
*first = *second;
|
||||
*second = *third;
|
||||
*third = tmp;
|
||||
if (!*second)
|
||||
data_.last_ptr_ = second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,168 +6,184 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_MEMORY_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_MEMORY_HEADER
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <boost/mpl/apply.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/mpl/aux_/config/eti.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace test
|
||||
{
|
||||
namespace detail
|
||||
namespace test {
|
||||
namespace detail {
|
||||
struct memory_area
|
||||
{
|
||||
struct memory_area {
|
||||
void const* start;
|
||||
void const* end;
|
||||
void const* start;
|
||||
void const* end;
|
||||
|
||||
memory_area(void const* s, void const* e)
|
||||
: start(s), end(e)
|
||||
{
|
||||
BOOST_ASSERT(start != end);
|
||||
}
|
||||
};
|
||||
memory_area(void const* s, void const* e) : start(s), end(e)
|
||||
{
|
||||
BOOST_ASSERT(start != end);
|
||||
}
|
||||
};
|
||||
|
||||
struct memory_track {
|
||||
explicit memory_track(int tag = -1) :
|
||||
constructed_(0),
|
||||
tag_(tag) {}
|
||||
struct memory_track
|
||||
{
|
||||
explicit memory_track(int tag = -1) : constructed_(0), tag_(tag) {}
|
||||
|
||||
int constructed_;
|
||||
int tag_;
|
||||
};
|
||||
int constructed_;
|
||||
int tag_;
|
||||
};
|
||||
|
||||
// This is a bit dodgy as it defines overlapping
|
||||
// areas as 'equal', so this isn't a total ordering.
|
||||
// But it is for non-overlapping memory regions - which
|
||||
// is what'll be stored.
|
||||
//
|
||||
// All searches will be for areas entirely contained by
|
||||
// a member of the set - so it should find the area that contains
|
||||
// the region that is searched for.
|
||||
// This is a bit dodgy as it defines overlapping
|
||||
// areas as 'equal', so this isn't a total ordering.
|
||||
// But it is for non-overlapping memory regions - which
|
||||
// is what'll be stored.
|
||||
//
|
||||
// All searches will be for areas entirely contained by
|
||||
// a member of the set - so it should find the area that contains
|
||||
// the region that is searched for.
|
||||
|
||||
struct memory_area_compare {
|
||||
bool operator()(memory_area const& x, memory_area const& y) const {
|
||||
return x.end <= y.start;
|
||||
}
|
||||
};
|
||||
struct memory_area_compare
|
||||
{
|
||||
bool operator()(memory_area const& x, memory_area const& y) const
|
||||
{
|
||||
return x.end <= y.start;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Alloc>
|
||||
struct allocator_memory_type_gen {
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare,
|
||||
Alloc> type;
|
||||
};
|
||||
struct memory_tracker
|
||||
{
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare,
|
||||
std::allocator<std::pair<memory_area const, memory_track> > >
|
||||
allocated_memory_type;
|
||||
|
||||
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
|
||||
template <>
|
||||
struct allocator_memory_type_gen<int> {
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare>
|
||||
type;
|
||||
};
|
||||
#endif
|
||||
allocated_memory_type allocated_memory;
|
||||
unsigned int count_allocators;
|
||||
unsigned int count_allocations;
|
||||
unsigned int count_constructions;
|
||||
bool tracking_constructions;
|
||||
|
||||
template <class Alloc = std::allocator<int> >
|
||||
struct memory_tracker {
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
boost::unordered_detail::rebind_wrap<Alloc,
|
||||
std::pair<memory_area const, memory_track> >::type
|
||||
allocator_type;
|
||||
memory_tracker()
|
||||
: count_allocators(0), count_allocations(0), count_constructions(0),
|
||||
tracking_constructions(true)
|
||||
{
|
||||
}
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
allocator_memory_type_gen<allocator_type>::type
|
||||
allocated_memory_type;
|
||||
~memory_tracker() { BOOST_TEST(count_allocators == 0); }
|
||||
|
||||
allocated_memory_type allocated_memory;
|
||||
unsigned int count_allocators;
|
||||
unsigned int count_allocations;
|
||||
unsigned int count_constructions;
|
||||
void allocator_ref()
|
||||
{
|
||||
if (count_allocators == 0) {
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
}
|
||||
++count_allocators;
|
||||
}
|
||||
|
||||
memory_tracker() :
|
||||
count_allocators(0), count_allocations(0),
|
||||
count_constructions(0)
|
||||
{}
|
||||
void allocator_unref()
|
||||
{
|
||||
BOOST_TEST(count_allocators > 0);
|
||||
if (count_allocators > 0) {
|
||||
--count_allocators;
|
||||
if (count_allocators == 0) {
|
||||
bool no_allocations_left = (count_allocations == 0);
|
||||
bool no_constructions_left = (count_constructions == 0);
|
||||
bool allocated_memory_empty = allocated_memory.empty();
|
||||
|
||||
void allocator_ref()
|
||||
{
|
||||
if(count_allocators == 0) {
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
}
|
||||
++count_allocators;
|
||||
}
|
||||
// Clearing the data before the checks terminate the
|
||||
// tests.
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
|
||||
void allocator_unref()
|
||||
{
|
||||
BOOST_TEST(count_allocators > 0);
|
||||
if(count_allocators > 0) {
|
||||
--count_allocators;
|
||||
if(count_allocators == 0) {
|
||||
bool no_allocations_left = (count_allocations == 0);
|
||||
bool no_constructions_left = (count_constructions == 0);
|
||||
bool allocated_memory_empty = allocated_memory.empty();
|
||||
BOOST_TEST(no_allocations_left);
|
||||
BOOST_TEST(no_constructions_left);
|
||||
BOOST_TEST(allocated_memory_empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clearing the data before the checks terminate the
|
||||
// tests.
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
void track_allocate(void* ptr, std::size_t n, std::size_t size, int tag)
|
||||
{
|
||||
if (n == 0) {
|
||||
BOOST_ERROR("Allocating 0 length array.");
|
||||
} else {
|
||||
++count_allocations;
|
||||
allocated_memory.insert(std::pair<memory_area const, memory_track>(
|
||||
memory_area(ptr, (char*)ptr + n * size), memory_track(tag)));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_TEST(no_allocations_left);
|
||||
BOOST_TEST(no_constructions_left);
|
||||
BOOST_TEST(allocated_memory_empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag,
|
||||
bool check_tag_ = true)
|
||||
{
|
||||
allocated_memory_type::iterator pos =
|
||||
allocated_memory.find(memory_area(ptr, (char*)ptr + n * size));
|
||||
if (pos == allocated_memory.end()) {
|
||||
BOOST_ERROR("Deallocating unknown pointer.");
|
||||
} else {
|
||||
BOOST_TEST(pos->first.start == ptr);
|
||||
BOOST_TEST(pos->first.end == (char*)ptr + n * size);
|
||||
if (check_tag_)
|
||||
BOOST_TEST(pos->second.tag_ == tag);
|
||||
allocated_memory.erase(pos);
|
||||
}
|
||||
BOOST_TEST(count_allocations > 0);
|
||||
if (count_allocations > 0)
|
||||
--count_allocations;
|
||||
}
|
||||
|
||||
void track_allocate(void *ptr, std::size_t n, std::size_t size,
|
||||
int tag)
|
||||
{
|
||||
if(n == 0) {
|
||||
BOOST_ERROR("Allocating 0 length array.");
|
||||
}
|
||||
else {
|
||||
++count_allocations;
|
||||
allocated_memory.insert(
|
||||
std::pair<memory_area const, memory_track>(
|
||||
memory_area(ptr, (char*) ptr + n * size),
|
||||
memory_track(tag)));
|
||||
}
|
||||
}
|
||||
void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
{
|
||||
if (tracking_constructions) {
|
||||
++count_constructions;
|
||||
}
|
||||
}
|
||||
|
||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size,
|
||||
int tag)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
|
||||
allocated_memory.find(
|
||||
memory_area(ptr, (char*) ptr + n * size));
|
||||
if(pos == allocated_memory.end()) {
|
||||
BOOST_ERROR("Deallocating unknown pointer.");
|
||||
} else {
|
||||
BOOST_TEST(pos->first.start == ptr);
|
||||
BOOST_TEST(pos->first.end == (char*) ptr + n * size);
|
||||
BOOST_TEST(pos->second.tag_ == tag);
|
||||
allocated_memory.erase(pos);
|
||||
}
|
||||
BOOST_TEST(count_allocations > 0);
|
||||
if(count_allocations > 0) --count_allocations;
|
||||
}
|
||||
void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
{
|
||||
if (tracking_constructions) {
|
||||
BOOST_TEST(count_constructions > 0);
|
||||
if (count_constructions > 0)
|
||||
--count_constructions;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void track_construct(void* /*ptr*/, std::size_t /*size*/,
|
||||
int /*tag*/)
|
||||
{
|
||||
++count_constructions;
|
||||
}
|
||||
|
||||
void track_destroy(void* /*ptr*/, std::size_t /*size*/,
|
||||
int /*tag*/)
|
||||
{
|
||||
BOOST_TEST(count_constructions > 0);
|
||||
if(count_constructions > 0) --count_constructions;
|
||||
}
|
||||
};
|
||||
namespace detail {
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually required by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
test::detail::memory_tracker tracker;
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
struct disable_construction_tracking
|
||||
{
|
||||
bool old_value;
|
||||
|
||||
disable_construction_tracking()
|
||||
: old_value(detail::tracker.tracking_constructions)
|
||||
{
|
||||
test::detail::tracker.tracking_constructions = false;
|
||||
}
|
||||
|
||||
~disable_construction_tracking()
|
||||
{
|
||||
test::detail::tracker.tracking_constructions = old_value;
|
||||
}
|
||||
|
||||
private:
|
||||
disable_construction_tracking(disable_construction_tracking const&);
|
||||
disable_construction_tracking& operator=(
|
||||
disable_construction_tracking const&);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -8,74 +8,23 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace test
|
||||
{
|
||||
/*
|
||||
struct unordered_set_type { char x[100]; };
|
||||
struct unordered_multiset_type { char x[200]; };
|
||||
struct unordered_map_type { char x[300]; };
|
||||
struct unordered_multimap_type { char x[400]; };
|
||||
namespace test {
|
||||
template <class Container>
|
||||
struct is_set : public boost::is_same<typename Container::key_type,
|
||||
typename Container::value_type>
|
||||
{
|
||||
};
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
unordered_set_type container_type(
|
||||
boost::unordered_set<V, H, P, A> const*);
|
||||
template <class V, class H, class P, class A>
|
||||
unordered_multiset_type container_type(
|
||||
boost::unordered_multiset<V, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
unordered_map_type container_type(
|
||||
boost::unordered_map<K, M, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
unordered_multimap_type container_type(
|
||||
boost::unordered_multimap<K, M, H, P, A> const*);
|
||||
*/
|
||||
|
||||
template <class Container>
|
||||
struct is_set
|
||||
: public boost::is_same<
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type,
|
||||
BOOST_DEDUCED_TYPENAME Container::value_type> {};
|
||||
|
||||
template <class Container>
|
||||
struct is_map
|
||||
: public boost::mpl::not_<is_set<Container> > {};
|
||||
|
||||
struct yes_type { char x[100]; };
|
||||
struct no_type { char x[200]; };
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
yes_type has_unique_key_impl(
|
||||
boost::unordered_set<V, H, P, A> const*);
|
||||
template <class V, class H, class P, class A>
|
||||
no_type has_unique_key_impl(
|
||||
boost::unordered_multiset<V, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
yes_type has_unique_key_impl(
|
||||
boost::unordered_map<K, M, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
no_type has_unique_key_impl(
|
||||
boost::unordered_multimap<K, M, H, P, A> const*);
|
||||
|
||||
template <class Container>
|
||||
struct has_unique_keys
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value =
|
||||
sizeof(has_unique_key_impl((Container const*)0))
|
||||
== sizeof(yes_type));
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
struct has_equivalent_keys
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value =
|
||||
sizeof(has_unique_key_impl((Container const*)0))
|
||||
== sizeof(no_type));
|
||||
};
|
||||
template <class Container> struct has_unique_keys
|
||||
{
|
||||
static char flip(typename Container::iterator const&);
|
||||
static long flip(std::pair<typename Container::iterator, bool> const&);
|
||||
BOOST_STATIC_CONSTANT(bool,
|
||||
value = sizeof(long) ==
|
||||
sizeof(flip(
|
||||
((Container*)0)->insert(*(typename Container::value_type*)0))));
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
10
test/helpers/postfix.hpp
Normal file
10
test/helpers/postfix.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
// 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 this after the boost headers, but before other test headers.
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
@ -6,6 +6,6 @@
|
||||
#if defined(_WIN32_WCE)
|
||||
// The standard windows mobile headers trigger this warning so I disable it
|
||||
// before doing anything else.
|
||||
#pragma warning(disable:4201) // nonstandard extension used :
|
||||
#pragma warning(disable : 4201) // nonstandard extension used :
|
||||
// nameless struct/union
|
||||
#endif
|
||||
|
@ -6,108 +6,104 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER
|
||||
|
||||
#include "./list.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include "./generators.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/detail/select_type.hpp>
|
||||
|
||||
namespace test
|
||||
{
|
||||
typedef enum {
|
||||
default_generator,
|
||||
generate_collisions
|
||||
} random_generator;
|
||||
namespace test {
|
||||
template <class X> struct unordered_generator_set
|
||||
{
|
||||
typedef typename X::value_type value_type;
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator_set
|
||||
random_generator type_;
|
||||
|
||||
unordered_generator_set(random_generator type) : type_(type) {}
|
||||
|
||||
template <class T> void fill(T& x, std::size_t len)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
||||
value_type* value_ptr = 0;
|
||||
len += x.size();
|
||||
|
||||
random_generator type_;
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
value_type value = generate(value_ptr, type_);
|
||||
|
||||
unordered_generator_set(random_generator type)
|
||||
: type_(type) {}
|
||||
std::size_t count =
|
||||
type_ == generate_collisions ? random_value(5) + 1 : 1;
|
||||
|
||||
template <class T>
|
||||
void fill(T& x, std::size_t len) {
|
||||
value_type* value_ptr = 0;
|
||||
int* int_ptr = 0;
|
||||
|
||||
for(std::size_t i = 0; i < len; ++i) {
|
||||
value_type value = generate(value_ptr);
|
||||
|
||||
for(int count =
|
||||
type_ == generate_collisions ?
|
||||
generate(int_ptr) % 10 : 1;
|
||||
count; --count) {
|
||||
x.push_back(value);
|
||||
}
|
||||
}
|
||||
for (std::size_t j = 0; j < count; ++j) {
|
||||
x.push_back(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator_map
|
||||
template <class X> struct unordered_generator_map
|
||||
{
|
||||
typedef typename X::key_type key_type;
|
||||
typedef typename X::mapped_type mapped_type;
|
||||
|
||||
random_generator type_;
|
||||
|
||||
unordered_generator_map(random_generator type) : type_(type) {}
|
||||
|
||||
template <class T> void fill(T& x, std::size_t len)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::mapped_type mapped_type;
|
||||
key_type* key_ptr = 0;
|
||||
mapped_type* mapped_ptr = 0;
|
||||
|
||||
random_generator type_;
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
key_type key = generate(key_ptr, type_);
|
||||
|
||||
unordered_generator_map(random_generator type)
|
||||
: type_(type) {}
|
||||
std::size_t count =
|
||||
type_ == generate_collisions ? random_value(5) + 1 : 1;
|
||||
|
||||
template <class T>
|
||||
void fill(T& x, std::size_t len) {
|
||||
key_type* key_ptr = 0;
|
||||
mapped_type* mapped_ptr = 0;
|
||||
int* int_ptr = 0;
|
||||
|
||||
for(std::size_t i = 0; i < len; ++i) {
|
||||
key_type key = generate(key_ptr);
|
||||
|
||||
for(int count =
|
||||
type_ == generate_collisions ?
|
||||
generate(int_ptr) % 10 : 1;
|
||||
count; --count) {
|
||||
x.push_back(
|
||||
std::pair<key_type const, mapped_type>(
|
||||
key, generate(mapped_ptr)));
|
||||
}
|
||||
}
|
||||
for (std::size_t j = 0; j < count; ++j) {
|
||||
x.push_back(std::pair<key_type const, mapped_type>(
|
||||
key, generate(mapped_ptr, type_)));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator_base
|
||||
: public boost::mpl::if_<
|
||||
test::is_set<X>,
|
||||
test::unordered_generator_set<X>,
|
||||
test::unordered_generator_map<X> >
|
||||
template <class X>
|
||||
struct unordered_generator_base
|
||||
: public boost::detail::if_true<test::is_set<X>::value>::
|
||||
BOOST_NESTED_TEMPLATE then<test::unordered_generator_set<X>,
|
||||
test::unordered_generator_map<X> >
|
||||
{
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator : public unordered_generator_base<X>::type
|
||||
{
|
||||
typedef typename unordered_generator_base<X>::type base;
|
||||
|
||||
unordered_generator(random_generator const& type = default_generator)
|
||||
: base(type)
|
||||
{
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator : public unordered_generator_base<X>::type
|
||||
template <class X>
|
||||
struct random_values : public test::list<typename X::value_type>
|
||||
{
|
||||
random_values() {}
|
||||
|
||||
explicit random_values(std::size_t count,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME unordered_generator_base<X>::type base;
|
||||
fill(count, generator);
|
||||
}
|
||||
|
||||
unordered_generator(random_generator const& type = default_generator)
|
||||
: base(type) {}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct random_values
|
||||
: public test::list<BOOST_DEDUCED_TYPENAME X::value_type>
|
||||
void fill(std::size_t count,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
random_values(int count, test::random_generator const& generator =
|
||||
test::default_generator)
|
||||
{
|
||||
static test::unordered_generator<X> gen(generator);
|
||||
gen.fill(*this, count);
|
||||
}
|
||||
};
|
||||
test::unordered_generator<X> gen(generator);
|
||||
gen.fill(*this, count);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,38 +6,37 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER
|
||||
|
||||
#include "./equivalent.hpp"
|
||||
#include "./exception_test.hpp"
|
||||
#include "./list.hpp"
|
||||
#include <boost/config.hpp>
|
||||
#include <iterator>
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./equivalent.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./exception_test.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class X>
|
||||
class strong
|
||||
namespace test {
|
||||
template <class X> class strong
|
||||
{
|
||||
typedef test::list<typename X::value_type> values_type;
|
||||
values_type values_;
|
||||
unsigned int allocations_;
|
||||
|
||||
public:
|
||||
void store(X const& x, unsigned int allocations = 0)
|
||||
{
|
||||
typedef test::list<BOOST_DEDUCED_TYPENAME X::value_type> values_type;
|
||||
values_type values_;
|
||||
unsigned int allocations_;
|
||||
public:
|
||||
void store(X const& x, unsigned int allocations = 0) {
|
||||
DISABLE_EXCEPTIONS;
|
||||
values_.clear();
|
||||
values_.insert(x.cbegin(), x.cend());
|
||||
allocations_ = allocations;
|
||||
}
|
||||
DISABLE_EXCEPTIONS;
|
||||
values_.clear();
|
||||
values_.insert(x.cbegin(), x.cend());
|
||||
allocations_ = allocations;
|
||||
}
|
||||
|
||||
void test(X const& x, unsigned int allocations = 0) const {
|
||||
if(!(x.size() == values_.size() &&
|
||||
test::equal(x.cbegin(), x.cend(), values_.begin(),
|
||||
test::equivalent)))
|
||||
BOOST_ERROR("Strong exception safety failure.");
|
||||
if(allocations != allocations_)
|
||||
BOOST_ERROR("Strong exception failure: extra allocations.");
|
||||
}
|
||||
};
|
||||
void test(X const& x, unsigned int allocations = 0) const
|
||||
{
|
||||
if (!(x.size() == values_.size() && test::equal(x.cbegin(), x.cend(),
|
||||
values_.begin(), test::equivalent)))
|
||||
BOOST_ERROR("Strong exception safety failure.");
|
||||
if (allocations != allocations_)
|
||||
BOOST_ERROR("Strong exception failure: extra allocations.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,91 +6,196 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_TEST_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_TEST_HEADER
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#define UNORDERED_AUTO_TEST(x) \
|
||||
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base { \
|
||||
BOOST_PP_CAT(x, _type)() \
|
||||
: ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
|
||||
{ \
|
||||
::test::test_list::add_test(this); \
|
||||
} \
|
||||
void run(); \
|
||||
}; \
|
||||
BOOST_PP_CAT(x, _type) x; \
|
||||
void BOOST_PP_CAT(x, _type)::run() \
|
||||
#define UNORDERED_AUTO_TEST(x) \
|
||||
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base \
|
||||
{ \
|
||||
BOOST_PP_CAT(x, _type) \
|
||||
() : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
|
||||
{ \
|
||||
::test::get_state().add_test(this); \
|
||||
} \
|
||||
void run(); \
|
||||
}; \
|
||||
BOOST_PP_CAT(x, _type) x; \
|
||||
void BOOST_PP_CAT(x, _type)::run()
|
||||
|
||||
#define RUN_TESTS() int main(int, char**) \
|
||||
{ ::test::test_list::run_tests(); return boost::report_errors(); } \
|
||||
#define RUN_TESTS() \
|
||||
int main(int, char**) \
|
||||
{ \
|
||||
BOOST_UNORDERED_TEST_COMPILER_INFO() \
|
||||
::test::get_state().run_tests(); \
|
||||
return boost::report_errors(); \
|
||||
}
|
||||
|
||||
#define RUN_TESTS_QUIET() \
|
||||
int main(int, char**) \
|
||||
{ \
|
||||
BOOST_UNORDERED_TEST_COMPILER_INFO() \
|
||||
::test::get_state().run_tests(true); \
|
||||
return boost::report_errors(); \
|
||||
}
|
||||
|
||||
#define UNORDERED_SUB_TEST(x) \
|
||||
for (int UNORDERED_SUB_TEST_VALUE = ::test::get_state().start_sub_test(x); \
|
||||
UNORDERED_SUB_TEST_VALUE; \
|
||||
UNORDERED_SUB_TEST_VALUE = \
|
||||
::test::get_state().end_sub_test(x, UNORDERED_SUB_TEST_VALUE))
|
||||
|
||||
namespace test {
|
||||
struct registered_test_base {
|
||||
registered_test_base* next;
|
||||
char const* name;
|
||||
explicit registered_test_base(char const* n) : name(n) {}
|
||||
virtual void run() = 0;
|
||||
virtual ~registered_test_base() {}
|
||||
};
|
||||
|
||||
namespace test_list {
|
||||
static inline registered_test_base*& first() {
|
||||
static registered_test_base* ptr = 0;
|
||||
return ptr;
|
||||
}
|
||||
struct registered_test_base
|
||||
{
|
||||
registered_test_base* next;
|
||||
char const* name;
|
||||
explicit registered_test_base(char const* n) : name(n) {}
|
||||
virtual void run() = 0;
|
||||
virtual ~registered_test_base() {}
|
||||
};
|
||||
|
||||
static inline registered_test_base*& last() {
|
||||
static registered_test_base* ptr = 0;
|
||||
return ptr;
|
||||
}
|
||||
struct state
|
||||
{
|
||||
bool is_quiet;
|
||||
registered_test_base* first_test;
|
||||
registered_test_base* last_test;
|
||||
|
||||
static inline void add_test(registered_test_base* test) {
|
||||
if(last()) {
|
||||
last()->next = test;
|
||||
}
|
||||
else {
|
||||
first() = test;
|
||||
}
|
||||
state() : is_quiet(false), first_test(0), last_test(0) {}
|
||||
|
||||
last() = test;
|
||||
}
|
||||
|
||||
static inline void run_tests() {
|
||||
for(registered_test_base* i = first(); i; i = i->next) {
|
||||
std::cout<<"Running "<<i->name<<"\n"<<std::flush;
|
||||
i->run();
|
||||
std::cerr<<std::flush;
|
||||
std::cout<<std::flush;
|
||||
}
|
||||
}
|
||||
void add_test(registered_test_base* test)
|
||||
{
|
||||
if (last_test) {
|
||||
last_test->next = test;
|
||||
} else {
|
||||
first_test = test;
|
||||
}
|
||||
last_test = test;
|
||||
}
|
||||
|
||||
void run_tests(bool quiet = false)
|
||||
{
|
||||
is_quiet = quiet;
|
||||
|
||||
for (registered_test_base* i = first_test; i; i = i->next) {
|
||||
int error_count = boost::detail::test_errors();
|
||||
if (!quiet) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
i->run();
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush;
|
||||
if (quiet && error_count != boost::detail::test_errors()) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int start_sub_test(char const* name)
|
||||
{
|
||||
if (!is_quiet) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
// Add one because it's used as a loop condition.
|
||||
return boost::detail::test_errors() + 1;
|
||||
}
|
||||
|
||||
int end_sub_test(char const* name, int value)
|
||||
{
|
||||
if (is_quiet && value != boost::detail::test_errors() + 1) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the currnet translation unit's test state.
|
||||
static inline state& get_state()
|
||||
{
|
||||
static state instance;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/fold_left.hpp>
|
||||
#include <boost/preprocessor/seq/to_tuple.hpp>
|
||||
#include <boost/preprocessor/seq/seq.hpp>
|
||||
#if defined(__cplusplus)
|
||||
#define BOOST_UNORDERED_CPLUSPLUS __cplusplus
|
||||
#else
|
||||
#define BOOST_UNORDERED_CPLUSPLUS "(not defined)"
|
||||
#endif
|
||||
|
||||
#define BOOST_UNORDERED_TEST_COMPILER_INFO() \
|
||||
{ \
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
|
||||
<< "Compiler: " << BOOST_COMPILER << "\n" \
|
||||
<< "Library: " << BOOST_STDLIB << "\n" \
|
||||
<< "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \
|
||||
<< "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \
|
||||
<< BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \
|
||||
<< "BOOST_UNORDERED_EMPLACE_LIMIT: " << BOOST_UNORDERED_EMPLACE_LIMIT \
|
||||
<< "\n" \
|
||||
<< "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \
|
||||
<< BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \
|
||||
<< "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \
|
||||
<< BOOST_UNORDERED_CXX11_CONSTRUCTION << "\n\n" \
|
||||
<< std::flush; \
|
||||
}
|
||||
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/fold_left.hpp>
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/seq.hpp>
|
||||
#include <boost/preprocessor/seq/to_tuple.hpp>
|
||||
|
||||
// Run test with every combination of the parameters (a sequence of sequences)
|
||||
#define UNORDERED_TEST(name, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name)) parameters) \
|
||||
#define UNORDERED_TEST(name, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name))((1))parameters)
|
||||
|
||||
#define UNORDERED_TEST_OP(r, product) \
|
||||
UNORDERED_TEST_OP2( \
|
||||
BOOST_PP_SEQ_HEAD(product), \
|
||||
BOOST_PP_SEQ_TAIL(product)) \
|
||||
#define UNORDERED_TEST_REPEAT(name, n, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name))((n))parameters)
|
||||
|
||||
#define UNORDERED_TEST_OP2(name, params) \
|
||||
UNORDERED_AUTO_TEST( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) \
|
||||
{ \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
} \
|
||||
#define UNORDERED_TEST_OP(r, product) \
|
||||
UNORDERED_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product)))
|
||||
|
||||
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
|
||||
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) \
|
||||
#define UNORDERED_TEST_OP2(name, n, params) \
|
||||
UNORDERED_AUTO_TEST ( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) { \
|
||||
for (int i = 0; i < n; ++i) \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
}
|
||||
|
||||
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
|
||||
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem))
|
||||
|
||||
#define UNORDERED_MULTI_TEST(name, impl, parameters) \
|
||||
UNORDERED_MULTI_TEST_REPEAT(name, impl, 1, parameters)
|
||||
|
||||
#define UNORDERED_MULTI_TEST_REPEAT(name, impl, n, parameters) \
|
||||
UNORDERED_AUTO_TEST (name) { \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT( \
|
||||
UNORDERED_MULTI_TEST_OP, ((impl))((n))parameters) \
|
||||
}
|
||||
|
||||
#define UNORDERED_MULTI_TEST_OP(r, product) \
|
||||
UNORDERED_MULTI_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product)))
|
||||
|
||||
// Need to wrap UNORDERED_SUB_TEST in a block to avoid an msvc bug.
|
||||
// https://support.microsoft.com/en-gb/help/315481/bug-too-many-unnested-loops-incorrectly-causes-a-c1061-compiler-error-in-visual-c
|
||||
#define UNORDERED_MULTI_TEST_OP2(name, n, params) \
|
||||
{ \
|
||||
UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \
|
||||
{ \
|
||||
for (int i = 0; i < n; ++i) \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,170 +9,130 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include "../objects/fwd.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./helpers.hpp"
|
||||
#include "./equivalent.hpp"
|
||||
#include "./helpers.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class X>
|
||||
struct equals_to_compare2
|
||||
: public boost::mpl::identity<
|
||||
std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type> >
|
||||
{
|
||||
};
|
||||
namespace test {
|
||||
template <typename X> struct equals_to_compare
|
||||
{
|
||||
typedef std::less<typename X::first_argument_type> type;
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct equals_to_compare
|
||||
: public boost::mpl::eval_if<
|
||||
boost::is_same<X, test::equal_to>,
|
||||
boost::mpl::identity<test::less>,
|
||||
equals_to_compare2<X>
|
||||
>
|
||||
{
|
||||
};
|
||||
template <> struct equals_to_compare<test::equal_to>
|
||||
{
|
||||
typedef test::less type;
|
||||
};
|
||||
|
||||
template <class X1, class X2>
|
||||
void compare_range(X1 const& x1, X2 const& x2)
|
||||
template <class X1, class X2> void compare_range(X1 const& x1, X2 const& x2)
|
||||
{
|
||||
typedef test::list<typename X1::value_type> value_list;
|
||||
value_list values1(x1.begin(), x1.end());
|
||||
value_list values2(x2.begin(), x2.end());
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
}
|
||||
|
||||
template <class X1, class X2, class T>
|
||||
void compare_pairs(X1 const& x1, X2 const& x2, T*)
|
||||
{
|
||||
test::list<T> values1(x1.first, x1.second);
|
||||
test::list<T> values2(x2.first, x2.second);
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
}
|
||||
|
||||
template <typename X, bool is_set = test::is_set<X>::value,
|
||||
bool has_unique_keys = test::has_unique_keys<X>::value>
|
||||
struct ordered_base;
|
||||
|
||||
template <typename X> struct ordered_base<X, true, true>
|
||||
{
|
||||
typedef std::set<typename X::value_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <typename X> struct ordered_base<X, true, false>
|
||||
{
|
||||
typedef std::multiset<typename X::value_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <typename X> struct ordered_base<X, false, true>
|
||||
{
|
||||
typedef std::map<typename X::key_type, typename X::mapped_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <typename X> struct ordered_base<X, false, false>
|
||||
{
|
||||
typedef std::multimap<typename X::key_type, typename X::mapped_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <class X> class ordered : public ordered_base<X>::type
|
||||
{
|
||||
typedef typename ordered_base<X>::type base;
|
||||
|
||||
public:
|
||||
typedef typename base::key_compare key_compare;
|
||||
|
||||
ordered() : base() {}
|
||||
|
||||
explicit ordered(key_compare const& kc) : base(kc) {}
|
||||
|
||||
void compare(X const& x) { compare_range(x, *this); }
|
||||
|
||||
void compare_key(X const& x, typename X::value_type const& val)
|
||||
{
|
||||
typedef test::list<BOOST_DEDUCED_TYPENAME X1::value_type> value_list;
|
||||
value_list values1(x1.begin(), x1.end());
|
||||
value_list values2(x2.begin(), x2.end());
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
compare_pairs(x.equal_range(get_key<X>(val)),
|
||||
this->equal_range(get_key<X>(val)), (typename X::value_type*)0);
|
||||
}
|
||||
|
||||
template <class X1, class X2, class T>
|
||||
void compare_pairs(X1 const& x1, X2 const& x2, T*)
|
||||
template <class It> void insert_range(It b, It e)
|
||||
{
|
||||
test::list<T> values1(x1.first, x1.second);
|
||||
test::list<T> values2(x2.first, x2.second);
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(),
|
||||
values2.begin(), test::equivalent));
|
||||
while (b != e) {
|
||||
this->insert(*b);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct ordered_set : public
|
||||
boost::mpl::if_<
|
||||
test::has_unique_keys<X>,
|
||||
std::set<
|
||||
BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>,
|
||||
std::multiset<
|
||||
BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>
|
||||
> {};
|
||||
template <class Equals>
|
||||
typename equals_to_compare<Equals>::type create_compare(Equals const&)
|
||||
{
|
||||
typename equals_to_compare<Equals>::type x;
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
struct ordered_map : public
|
||||
boost::mpl::if_<
|
||||
test::has_unique_keys<X>,
|
||||
std::map<
|
||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||
BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>,
|
||||
std::multimap<
|
||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||
BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>
|
||||
> {};
|
||||
template <class X> ordered<X> create_ordered(X const& container)
|
||||
{
|
||||
return ordered<X>(create_compare(container.key_eq()));
|
||||
}
|
||||
|
||||
template <class X>
|
||||
struct ordered_base : public
|
||||
boost::mpl::eval_if<
|
||||
test::is_set<X>,
|
||||
test::ordered_set<X>,
|
||||
test::ordered_map<X>
|
||||
> {};
|
||||
|
||||
template <class X>
|
||||
class ordered : public ordered_base<X>::type
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME ordered_base<X>::type base;
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME base::key_compare key_compare;
|
||||
|
||||
ordered()
|
||||
: base()
|
||||
{}
|
||||
|
||||
explicit ordered(key_compare const& compare)
|
||||
: base(compare)
|
||||
{}
|
||||
|
||||
void compare(X const& x)
|
||||
{
|
||||
compare_range(x, *this);
|
||||
}
|
||||
|
||||
void compare_key(X const& x,
|
||||
BOOST_DEDUCED_TYPENAME X::value_type const& val)
|
||||
{
|
||||
compare_pairs(
|
||||
x.equal_range(get_key<X>(val)),
|
||||
this->equal_range(get_key<X>(val)),
|
||||
(BOOST_DEDUCED_TYPENAME X::value_type*) 0);
|
||||
}
|
||||
|
||||
template <class It>
|
||||
void insert_range(It begin, It end) {
|
||||
while(begin != end) {
|
||||
this->insert(*begin);
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Equals>
|
||||
BOOST_DEDUCED_TYPENAME
|
||||
equals_to_compare<Equals>::type create_compare(Equals const&)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<Equals>::type x;
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
ordered<X> create_ordered(X const& container)
|
||||
{
|
||||
return ordered<X>(create_compare(container.key_eq()));
|
||||
}
|
||||
|
||||
template <class X1, class X2>
|
||||
void check_container(X1 const& container, X2 const& values)
|
||||
{
|
||||
ordered<X1> tracker = create_ordered(container);
|
||||
tracker.insert_range(values.begin(), values.end());
|
||||
tracker.compare(container);
|
||||
}
|
||||
template <class X1, class X2>
|
||||
void check_container(X1 const& container, X2 const& values)
|
||||
{
|
||||
ordered<X1> tracker = create_ordered(container);
|
||||
tracker.insert_range(values.begin(), values.end());
|
||||
tracker.compare(container);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
344
test/objects/cxx11_allocator.hpp
Normal file
344
test/objects/cxx11_allocator.hpp
Normal file
@ -0,0 +1,344 @@
|
||||
|
||||
// Copyright 2006-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)
|
||||
|
||||
#if !defined(BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/memory.hpp"
|
||||
|
||||
namespace test {
|
||||
struct allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_select_on_copy = 0,
|
||||
is_propagate_on_swap = 0,
|
||||
is_propagate_on_assign = 0,
|
||||
is_propagate_on_move = 0,
|
||||
cxx11_construct = 0
|
||||
};
|
||||
};
|
||||
|
||||
struct allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_select_on_copy = 1,
|
||||
is_propagate_on_swap = 1,
|
||||
is_propagate_on_assign = 1,
|
||||
is_propagate_on_move = 1,
|
||||
cxx11_construct = 1
|
||||
};
|
||||
};
|
||||
|
||||
struct select_copy : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_select_on_copy = 1
|
||||
};
|
||||
};
|
||||
struct propagate_swap : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_swap = 1
|
||||
};
|
||||
};
|
||||
struct propagate_assign : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_assign = 1
|
||||
};
|
||||
};
|
||||
struct propagate_move : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_move = 1
|
||||
};
|
||||
};
|
||||
|
||||
struct no_select_copy : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_select_on_copy = 0
|
||||
};
|
||||
};
|
||||
struct no_propagate_swap : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_swap = 0
|
||||
};
|
||||
};
|
||||
struct no_propagate_assign : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_assign = 0
|
||||
};
|
||||
};
|
||||
struct no_propagate_move : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_move = 0
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Flag> struct swap_allocator_base
|
||||
{
|
||||
struct propagate_on_container_swap
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = Flag::is_propagate_on_swap
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Flag> struct assign_allocator_base
|
||||
{
|
||||
struct propagate_on_container_copy_assignment
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = Flag::is_propagate_on_assign
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Flag> struct move_allocator_base
|
||||
{
|
||||
struct propagate_on_container_move_assignment
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = Flag::is_propagate_on_move
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
namespace {
|
||||
// boostinspect:nounnamed
|
||||
bool force_equal_allocator_value = false;
|
||||
}
|
||||
|
||||
struct force_equal_allocator
|
||||
{
|
||||
bool old_value_;
|
||||
|
||||
explicit force_equal_allocator(bool value)
|
||||
: old_value_(force_equal_allocator_value)
|
||||
{
|
||||
force_equal_allocator_value = value;
|
||||
}
|
||||
|
||||
~force_equal_allocator() { force_equal_allocator_value = old_value_; }
|
||||
};
|
||||
|
||||
template <typename T> struct cxx11_allocator_base
|
||||
{
|
||||
int tag_;
|
||||
int selected_;
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
explicit cxx11_allocator_base(int t) : tag_(t), selected_(0)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <typename Y>
|
||||
cxx11_allocator_base(cxx11_allocator_base<Y> const& x)
|
||||
: tag_(x.tag_), selected_(x.selected_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
cxx11_allocator_base(cxx11_allocator_base const& x)
|
||||
: tag_(x.tag_), selected_(x.selected_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
~cxx11_allocator_base() { detail::tracker.allocator_unref(); }
|
||||
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, void const*)
|
||||
{
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
// Only checking tags when propagating swap.
|
||||
// Note that tags will be tested
|
||||
// properly in the normal allocator.
|
||||
detail::tracker.track_deallocate(
|
||||
(void*)p, n, sizeof(T), tag_, !force_equal_allocator_value);
|
||||
::operator delete((void*)p);
|
||||
}
|
||||
|
||||
void construct(T* p, T const& t)
|
||||
{
|
||||
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
|
||||
new (p) T(t);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <typename... Args>
|
||||
void construct(T* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
|
||||
new (p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p)
|
||||
{
|
||||
detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
}
|
||||
|
||||
size_type max_size() const
|
||||
{
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Flags = propagate_swap, typename Enable = void>
|
||||
struct cxx11_allocator;
|
||||
|
||||
template <typename T, typename Flags>
|
||||
struct cxx11_allocator<T, Flags,
|
||||
typename boost::disable_if_c<Flags::is_select_on_copy>::type>
|
||||
: public cxx11_allocator_base<T>,
|
||||
public swap_allocator_base<Flags>,
|
||||
public assign_allocator_base<Flags>,
|
||||
public move_allocator_base<Flags>,
|
||||
Flags
|
||||
{
|
||||
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000)
|
||||
template <typename U> struct rebind
|
||||
{
|
||||
typedef cxx11_allocator<U, Flags> other;
|
||||
};
|
||||
#endif
|
||||
|
||||
explicit cxx11_allocator(int t = 0) : cxx11_allocator_base<T>(t) {}
|
||||
|
||||
template <typename Y>
|
||||
cxx11_allocator(cxx11_allocator<Y, Flags> const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
}
|
||||
|
||||
cxx11_allocator(cxx11_allocator const& x) : cxx11_allocator_base<T>(x) {}
|
||||
|
||||
// When not propagating swap, allocators are always equal
|
||||
// to avoid undefined behaviour.
|
||||
bool operator==(cxx11_allocator const& x) const
|
||||
{
|
||||
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||
}
|
||||
|
||||
bool operator!=(cxx11_allocator const& x) const { return !(*this == x); }
|
||||
};
|
||||
|
||||
template <typename T, typename Flags>
|
||||
struct cxx11_allocator<T, Flags,
|
||||
typename boost::enable_if_c<Flags::is_select_on_copy>::type>
|
||||
: public cxx11_allocator_base<T>,
|
||||
public swap_allocator_base<Flags>,
|
||||
public assign_allocator_base<Flags>,
|
||||
public move_allocator_base<Flags>,
|
||||
Flags
|
||||
{
|
||||
cxx11_allocator select_on_container_copy_construction() const
|
||||
{
|
||||
cxx11_allocator tmp(*this);
|
||||
++tmp.selected_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000)
|
||||
template <typename U> struct rebind
|
||||
{
|
||||
typedef cxx11_allocator<U, Flags> other;
|
||||
};
|
||||
#endif
|
||||
|
||||
explicit cxx11_allocator(int t = 0) : cxx11_allocator_base<T>(t) {}
|
||||
|
||||
template <typename Y>
|
||||
cxx11_allocator(cxx11_allocator<Y, Flags> const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
}
|
||||
|
||||
cxx11_allocator(cxx11_allocator const& x) : cxx11_allocator_base<T>(x) {}
|
||||
|
||||
// When not propagating swap, allocators are always equal
|
||||
// to avoid undefined behaviour.
|
||||
bool operator==(cxx11_allocator const& x) const
|
||||
{
|
||||
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||
}
|
||||
|
||||
bool operator!=(cxx11_allocator const& x) const { return !(*this == x); }
|
||||
};
|
||||
|
||||
template <typename T, typename Flags>
|
||||
bool equivalent_impl(cxx11_allocator<T, Flags> const& x,
|
||||
cxx11_allocator<T, Flags> const& y, test::derived_type)
|
||||
{
|
||||
return x.tag_ == y.tag_;
|
||||
}
|
||||
|
||||
// Function to check how many times an allocator has been selected,
|
||||
// return 0 for other allocators.
|
||||
|
||||
struct convert_from_anything
|
||||
{
|
||||
template <typename T> convert_from_anything(T const&) {}
|
||||
};
|
||||
|
||||
inline int selected_count(convert_from_anything) { return 0; }
|
||||
|
||||
template <typename T, typename Flags>
|
||||
int selected_count(cxx11_allocator<T, Flags> const& x)
|
||||
{
|
||||
return x.selected_;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -6,13 +6,12 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER
|
||||
|
||||
namespace test
|
||||
{
|
||||
class object;
|
||||
class hash;
|
||||
class less;
|
||||
class equal_to;
|
||||
template <class T> class allocator;
|
||||
namespace test {
|
||||
class object;
|
||||
class hash;
|
||||
class less;
|
||||
class equal_to;
|
||||
template <class T> class allocator;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -10,313 +10,616 @@
|
||||
#if !defined(BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER)
|
||||
#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
|
||||
|
||||
#include <boost/move/move.hpp>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
namespace test
|
||||
{
|
||||
namespace minimal
|
||||
{
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, == 1500)
|
||||
#define BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED 1
|
||||
#else
|
||||
#define BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED 0
|
||||
#endif
|
||||
|
||||
namespace test {
|
||||
namespace minimal {
|
||||
class destructible;
|
||||
class copy_constructible;
|
||||
class copy_constructible_equality_comparable;
|
||||
class default_copy_constructible;
|
||||
class default_assignable;
|
||||
class assignable;
|
||||
|
||||
struct ampersand_operator_used
|
||||
{
|
||||
ampersand_operator_used() { BOOST_TEST(false); }
|
||||
};
|
||||
|
||||
template <class T> class hash;
|
||||
template <class T> class equal_to;
|
||||
template <class T> class ptr;
|
||||
template <class T> class const_ptr;
|
||||
template <class T> class allocator;
|
||||
template <class T> class cxx11_allocator;
|
||||
|
||||
struct constructor_param
|
||||
{
|
||||
operator int() const { return 0; }
|
||||
};
|
||||
|
||||
class destructible
|
||||
{
|
||||
public:
|
||||
destructible(constructor_param const&) {}
|
||||
~destructible() {}
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
destructible(destructible const&);
|
||||
destructible& operator=(destructible const&);
|
||||
};
|
||||
|
||||
class copy_constructible
|
||||
{
|
||||
public:
|
||||
static copy_constructible create() { return copy_constructible(); }
|
||||
copy_constructible(copy_constructible const&) {}
|
||||
~copy_constructible() {}
|
||||
copy_constructible(constructor_param const&) {}
|
||||
copy_constructible(copy_constructible const&) {}
|
||||
~copy_constructible() {}
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
copy_constructible& operator=(copy_constructible const&);
|
||||
copy_constructible() {}
|
||||
copy_constructible& operator=(copy_constructible const&);
|
||||
copy_constructible() {}
|
||||
};
|
||||
|
||||
class copy_constructible_equality_comparable
|
||||
{
|
||||
public:
|
||||
static copy_constructible_equality_comparable create() {
|
||||
return copy_constructible_equality_comparable();
|
||||
}
|
||||
copy_constructible_equality_comparable(constructor_param const&) {}
|
||||
|
||||
copy_constructible_equality_comparable(
|
||||
copy_constructible_equality_comparable const&)
|
||||
{
|
||||
}
|
||||
copy_constructible_equality_comparable(
|
||||
copy_constructible_equality_comparable const&)
|
||||
{
|
||||
}
|
||||
|
||||
~copy_constructible_equality_comparable()
|
||||
{
|
||||
}
|
||||
~copy_constructible_equality_comparable() {}
|
||||
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
copy_constructible_equality_comparable& operator=(
|
||||
copy_constructible_equality_comparable const&);
|
||||
copy_constructible_equality_comparable() {}
|
||||
copy_constructible_equality_comparable& operator=(
|
||||
copy_constructible_equality_comparable const&);
|
||||
copy_constructible_equality_comparable() {}
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
bool operator==(
|
||||
copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
bool operator==(copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(
|
||||
copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
bool operator!=(copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
class default_copy_constructible
|
||||
class default_assignable
|
||||
{
|
||||
public:
|
||||
static default_copy_constructible create()
|
||||
{
|
||||
return default_copy_constructible();
|
||||
}
|
||||
default_assignable(constructor_param const&) {}
|
||||
|
||||
default_copy_constructible()
|
||||
{
|
||||
}
|
||||
default_assignable() {}
|
||||
|
||||
default_copy_constructible(default_copy_constructible const&)
|
||||
{
|
||||
}
|
||||
default_assignable(default_assignable const&) {}
|
||||
|
||||
~default_copy_constructible()
|
||||
{
|
||||
}
|
||||
private:
|
||||
default_copy_constructible& operator=(
|
||||
default_copy_constructible const&);
|
||||
default_assignable& operator=(default_assignable const&) { return *this; }
|
||||
|
||||
~default_assignable() {}
|
||||
|
||||
void dummy_member() const {}
|
||||
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class assignable
|
||||
{
|
||||
public:
|
||||
static assignable create() { return assignable(); }
|
||||
assignable(assignable const&) {}
|
||||
assignable& operator=(assignable const&) { return *this; }
|
||||
~assignable() {}
|
||||
assignable(constructor_param const&) {}
|
||||
assignable(assignable const&) {}
|
||||
assignable& operator=(assignable const&) { return *this; }
|
||||
~assignable() {}
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
assignable() {}
|
||||
assignable() {}
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class hash
|
||||
struct movable_init
|
||||
{
|
||||
public:
|
||||
static hash create() { return hash<T>(); }
|
||||
hash() {}
|
||||
hash(hash const&) {}
|
||||
hash& operator=(hash const&) { return *this; }
|
||||
~hash() {}
|
||||
|
||||
std::size_t operator()(T const&) const { return 0; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class equal_to
|
||||
class movable1
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable1)
|
||||
|
||||
public:
|
||||
movable1(constructor_param const&) {}
|
||||
movable1() {}
|
||||
explicit movable1(movable_init) {}
|
||||
movable1(BOOST_RV_REF(movable1)) {}
|
||||
movable1& operator=(BOOST_RV_REF(movable1)) { return *this; }
|
||||
~movable1() {}
|
||||
void dummy_member() const {}
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
class movable2
|
||||
{
|
||||
public:
|
||||
static equal_to create() { return equal_to<T>(); }
|
||||
equal_to() {}
|
||||
equal_to(equal_to const&) {}
|
||||
equal_to& operator=(equal_to const&) { return *this; }
|
||||
~equal_to() {}
|
||||
movable2(constructor_param const&) {}
|
||||
explicit movable2(movable_init) {}
|
||||
movable2(movable2&&) {}
|
||||
~movable2() {}
|
||||
movable2& operator=(movable2&&) { return *this; }
|
||||
void dummy_member() const {}
|
||||
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
private:
|
||||
movable2() {}
|
||||
movable2(movable2 const&);
|
||||
movable2& operator=(movable2 const&);
|
||||
};
|
||||
#else
|
||||
typedef movable1 movable2;
|
||||
#endif
|
||||
|
||||
template <class T> class hash
|
||||
{
|
||||
public:
|
||||
hash(constructor_param const&) {}
|
||||
hash() {}
|
||||
hash(hash const&) {}
|
||||
hash& operator=(hash const&) { return *this; }
|
||||
~hash() {}
|
||||
|
||||
std::size_t operator()(T const&) const { return 0; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> class equal_to
|
||||
{
|
||||
public:
|
||||
equal_to(constructor_param const&) {}
|
||||
equal_to() {}
|
||||
equal_to(equal_to const&) {}
|
||||
equal_to& operator=(equal_to const&) { return *this; }
|
||||
~equal_to() {}
|
||||
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> class ptr;
|
||||
template <class T> class const_ptr;
|
||||
|
||||
template <class T>
|
||||
class ptr
|
||||
struct void_ptr
|
||||
{
|
||||
friend class allocator<T>;
|
||||
friend class const_ptr<T>;
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T> friend class ptr;
|
||||
|
||||
T* ptr_;
|
||||
|
||||
ptr(T* x) : ptr_(x) {}
|
||||
public:
|
||||
ptr() : ptr_(0) {}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
ptr& operator++() { ++ptr_; return *this; }
|
||||
ptr operator++(int) { ptr tmp(*this); ++ptr_; return tmp; }
|
||||
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
|
||||
bool operator==(const_ptr<T> const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(const_ptr<T> const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(const_ptr<T> const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(const_ptr<T> const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(const_ptr<T> const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(const_ptr<T> const& x) const { return ptr_ >= x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class const_ptr
|
||||
{
|
||||
friend class allocator<T>;
|
||||
|
||||
T const* ptr_;
|
||||
|
||||
const_ptr(T const* ptr) : ptr_(ptr) {}
|
||||
public:
|
||||
const_ptr() : ptr_(0) {}
|
||||
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return *ptr_; }
|
||||
T const* operator->() const { return ptr_; }
|
||||
const_ptr& operator++() { ++ptr_; return *this; }
|
||||
const_ptr operator++(int) { const_ptr tmp(*this); ++ptr_; return tmp; }
|
||||
const_ptr operator+(std::ptrdiff_t s) const
|
||||
{ return const_ptr(ptr_ + s); }
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T const& operator[](int s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(ptr<T> const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(ptr<T> const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(ptr<T> const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(ptr<T> const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(ptr<T> const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(ptr<T> const& x) const { return ptr_ >= x.ptr_; }
|
||||
|
||||
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class allocator
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef ptr<T> pointer;
|
||||
typedef const_ptr<T> const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind { typedef allocator<U> other; };
|
||||
|
||||
allocator() {}
|
||||
template <class Y> allocator(allocator<Y> const&) {}
|
||||
allocator(allocator const&) {}
|
||||
~allocator() {}
|
||||
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
pointer allocate(size_type n, const_ptr<Y> u)
|
||||
{
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type)
|
||||
{
|
||||
::operator delete((void*) p.ptr_);
|
||||
}
|
||||
|
||||
void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); }
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
||||
new((void*)p.ptr_) T(std::forward<Args>(args)...);
|
||||
}
|
||||
private:
|
||||
#endif
|
||||
|
||||
void destroy(pointer p) { ((T*)p.ptr_)->~T(); }
|
||||
void* ptr_;
|
||||
|
||||
size_type max_size() const { return 1000; }
|
||||
public:
|
||||
void_ptr() : ptr_(0) {}
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
|
||||
BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||
public: allocator& operator=(allocator const&) { return *this;}
|
||||
template <typename T> explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
class void_const_ptr
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T> friend class const_ptr;
|
||||
|
||||
private:
|
||||
#endif
|
||||
|
||||
void* ptr_;
|
||||
|
||||
public:
|
||||
void_const_ptr() : ptr_(0) {}
|
||||
|
||||
template <typename T>
|
||||
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_)
|
||||
{
|
||||
}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T> class ptr
|
||||
{
|
||||
friend class allocator<T>;
|
||||
friend class const_ptr<T>;
|
||||
friend struct void_ptr;
|
||||
|
||||
T* ptr_;
|
||||
|
||||
ptr(T* x) : ptr_(x) {}
|
||||
|
||||
public:
|
||||
ptr() : ptr_(0) {}
|
||||
explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
ptr& operator++()
|
||||
{
|
||||
++ptr_;
|
||||
return *this;
|
||||
}
|
||||
ptr operator++(int)
|
||||
{
|
||||
ptr tmp(*this);
|
||||
++ptr_;
|
||||
return tmp;
|
||||
}
|
||||
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p)
|
||||
{
|
||||
return ptr<T>(s + p.ptr_);
|
||||
}
|
||||
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> class const_ptr
|
||||
{
|
||||
friend class allocator<T>;
|
||||
friend struct const_void_ptr;
|
||||
|
||||
T const* ptr_;
|
||||
|
||||
const_ptr(T const* ptr) : ptr_(ptr) {}
|
||||
|
||||
public:
|
||||
const_ptr() : ptr_(0) {}
|
||||
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*)x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return *ptr_; }
|
||||
T const* operator->() const { return ptr_; }
|
||||
const_ptr& operator++()
|
||||
{
|
||||
++ptr_;
|
||||
return *this;
|
||||
}
|
||||
const_ptr operator++(int)
|
||||
{
|
||||
const_ptr tmp(*this);
|
||||
++ptr_;
|
||||
return tmp;
|
||||
}
|
||||
const_ptr operator+(std::ptrdiff_t s) const
|
||||
{
|
||||
return const_ptr(ptr_ + s);
|
||||
}
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
|
||||
{
|
||||
return ptr<T>(s + p.ptr_);
|
||||
}
|
||||
T const& operator[](int s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> class allocator
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef void_ptr void_pointer;
|
||||
typedef void_const_ptr const_void_pointer;
|
||||
typedef ptr<T> pointer;
|
||||
typedef const_ptr<T> const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind
|
||||
{
|
||||
typedef allocator<U> other;
|
||||
};
|
||||
|
||||
allocator() {}
|
||||
template <class Y> allocator(allocator<Y> const&) {}
|
||||
allocator(allocator const&) {}
|
||||
~allocator() {}
|
||||
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
template <class Y> pointer allocate(size_type n, const_ptr<Y>)
|
||||
{
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type)
|
||||
{
|
||||
::operator delete((void*)p.ptr_);
|
||||
}
|
||||
|
||||
void construct(T* p, T const& t) { new ((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p) { p->~T(); }
|
||||
|
||||
size_type max_size() const { return 1000; }
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
|
||||
BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||
public:
|
||||
allocator& operator=(allocator const&) { return *this; }
|
||||
#else
|
||||
private: allocator& operator=(allocator const&);
|
||||
private:
|
||||
allocator& operator=(allocator const&);
|
||||
#endif
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> class allocator<T const>
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef void_ptr void_pointer;
|
||||
typedef void_const_ptr const_void_pointer;
|
||||
// Maybe these two should be const_ptr<T>
|
||||
typedef ptr<T const> pointer;
|
||||
typedef const_ptr<T const> const_pointer;
|
||||
typedef T const& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T const value_type;
|
||||
|
||||
template <class U> struct rebind
|
||||
{
|
||||
typedef allocator<U> other;
|
||||
};
|
||||
|
||||
allocator() {}
|
||||
template <class Y> allocator(allocator<Y> const&) {}
|
||||
allocator(allocator const&) {}
|
||||
~allocator() {}
|
||||
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
return pointer(static_cast<T const*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
template <class Y> pointer allocate(size_type n, const_ptr<Y>)
|
||||
{
|
||||
return pointer(static_cast<T const*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type)
|
||||
{
|
||||
::operator delete((void*)p.ptr_);
|
||||
}
|
||||
|
||||
void construct(T const* p, T const& t) { new ((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class... Args>
|
||||
void construct(T const* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T const* p) { p->~T(); }
|
||||
|
||||
size_type max_size() const { return 1000; }
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
|
||||
BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||
public:
|
||||
allocator& operator=(allocator const&) { return *this; }
|
||||
#else
|
||||
private:
|
||||
allocator& operator=(allocator const&);
|
||||
#endif
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline bool operator==(allocator<T> const&, allocator<T> const&)
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool operator!=(allocator<T> const&, allocator<T> const&)
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T> void swap(allocator<T>&, allocator<T>&) {}
|
||||
|
||||
// C++11 allocator
|
||||
//
|
||||
// Not a fully minimal C++11 allocator, just what I support. Hopefully will
|
||||
// cut down further in the future.
|
||||
|
||||
template <class T> class cxx11_allocator
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
// template <class U> struct rebind { typedef cxx11_allocator<U> other; };
|
||||
|
||||
cxx11_allocator() {}
|
||||
template <class Y> cxx11_allocator(cxx11_allocator<Y> const&) {}
|
||||
cxx11_allocator(cxx11_allocator const&) {}
|
||||
~cxx11_allocator() {}
|
||||
|
||||
T* address(T& r) { return &r; }
|
||||
T const* address(T const& r) { return &r; }
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
|
||||
template <class Y> T* allocate(std::size_t n, const_ptr<Y>)
|
||||
{
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) { ::operator delete((void*)p); }
|
||||
|
||||
void construct(T* p, T const& t) { new ((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p) { p->~T(); }
|
||||
|
||||
std::size_t max_size() const { return 1000u; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline bool operator==(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void swap(allocator<T>&, allocator<T>&)
|
||||
inline bool operator!=(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> void swap(cxx11_allocator<T>&, cxx11_allocator<T>&) {}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
namespace boost {
|
||||
#else
|
||||
namespace test {
|
||||
namespace minimal {
|
||||
namespace minimal {
|
||||
#endif
|
||||
std::size_t hash_value(
|
||||
test::minimal::copy_constructible_equality_comparable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
std::size_t hash_value(test::minimal::copy_constructible_equality_comparable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
}}
|
||||
#else
|
||||
}
|
||||
}
|
||||
#else
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
@ -6,317 +6,695 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_OBJECTS_HEADER
|
||||
|
||||
#include "../helpers/count.hpp"
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/memory.hpp"
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/count.hpp"
|
||||
#include "../helpers/memory.hpp"
|
||||
#include <map>
|
||||
|
||||
namespace test
|
||||
{
|
||||
// Note that the default hash function will work for any equal_to (but not
|
||||
// very well).
|
||||
class object;
|
||||
class hash;
|
||||
class less;
|
||||
class equal_to;
|
||||
template <class T> class allocator;
|
||||
object generate(object const*);
|
||||
namespace test {
|
||||
// Note that the default hash function will work for any equal_to (but not
|
||||
// very well).
|
||||
class object;
|
||||
class movable;
|
||||
class implicitly_convertible;
|
||||
class hash;
|
||||
class less;
|
||||
class equal_to;
|
||||
template <class T> class allocator1;
|
||||
template <class T> class allocator2;
|
||||
object generate(object const*, random_generator);
|
||||
movable generate(movable const*, random_generator);
|
||||
implicitly_convertible generate(
|
||||
implicitly_convertible const*, random_generator);
|
||||
|
||||
class object : globally_counted_object
|
||||
inline void ignore_variable(void const*) {}
|
||||
|
||||
class object : private counted_object
|
||||
{
|
||||
friend class hash;
|
||||
friend class equal_to;
|
||||
friend class less;
|
||||
int tag1_, tag2_;
|
||||
|
||||
public:
|
||||
explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
|
||||
|
||||
~object()
|
||||
{
|
||||
friend class hash;
|
||||
friend class equal_to;
|
||||
friend class less;
|
||||
int tag1_, tag2_;
|
||||
public:
|
||||
explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
|
||||
|
||||
~object() {
|
||||
tag1_ = -1;
|
||||
tag2_ = -1;
|
||||
}
|
||||
|
||||
friend bool operator==(object const& x1, object const& x2) {
|
||||
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
|
||||
}
|
||||
|
||||
friend bool operator!=(object const& x1, object const& x2) {
|
||||
return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
|
||||
}
|
||||
|
||||
friend bool operator<(object const& x1, object const& x2) {
|
||||
return x1.tag1_ < x2.tag1_ ||
|
||||
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
|
||||
}
|
||||
|
||||
friend object generate(object const*) {
|
||||
int* x = 0;
|
||||
return object(generate(x), generate(x));
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, object const& o)
|
||||
{
|
||||
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
|
||||
}
|
||||
};
|
||||
|
||||
class hash
|
||||
{
|
||||
int type_;
|
||||
public:
|
||||
explicit hash(int t = 0) : type_(t) {}
|
||||
|
||||
std::size_t operator()(object const& x) const {
|
||||
switch(type_) {
|
||||
case 1:
|
||||
return x.tag1_;
|
||||
case 2:
|
||||
return x.tag2_;
|
||||
default:
|
||||
return x.tag1_ + x.tag2_;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x) const {
|
||||
return x;
|
||||
}
|
||||
|
||||
friend bool operator==(hash const& x1, hash const& x2) {
|
||||
return x1.type_ == x2.type_;
|
||||
}
|
||||
|
||||
friend bool operator!=(hash const& x1, hash const& x2) {
|
||||
return x1.type_ != x2.type_;
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t hash_value(test::object const& x) {
|
||||
return hash()(x);
|
||||
tag1_ = -1;
|
||||
tag2_ = -1;
|
||||
}
|
||||
|
||||
class less
|
||||
friend bool operator==(object const& x1, object const& x2)
|
||||
{
|
||||
int type_;
|
||||
public:
|
||||
explicit less(int t = 0) : type_(t) {}
|
||||
|
||||
bool operator()(object const& x1, object const& x2) const {
|
||||
switch(type_) {
|
||||
case 1:
|
||||
return x1.tag1_ < x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ < x2.tag2_;
|
||||
default:
|
||||
return x1 < x2;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x1, int x2) const {
|
||||
return x1 < x2;
|
||||
}
|
||||
|
||||
friend bool operator==(less const& x1, less const& x2) {
|
||||
return x1.type_ == x2.type_;
|
||||
}
|
||||
};
|
||||
|
||||
class equal_to
|
||||
{
|
||||
int type_;
|
||||
public:
|
||||
explicit equal_to(int t = 0) : type_(t) {}
|
||||
|
||||
bool operator()(object const& x1, object const& x2) const {
|
||||
switch(type_) {
|
||||
case 1:
|
||||
return x1.tag1_ == x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ == x2.tag2_;
|
||||
default:
|
||||
return x1 == x2;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x1, int x2) const {
|
||||
return x1 == x2;
|
||||
}
|
||||
|
||||
friend bool operator==(equal_to const& x1, equal_to const& x2) {
|
||||
return x1.type_ == x2.type_;
|
||||
}
|
||||
|
||||
friend bool operator!=(equal_to const& x1, equal_to const& x2) {
|
||||
return x1.type_ != x2.type_;
|
||||
}
|
||||
|
||||
friend less create_compare(equal_to x) {
|
||||
return less(x.type_);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
test::detail::memory_tracker<std::allocator<int> > tracker;
|
||||
}
|
||||
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class allocator
|
||||
friend bool operator!=(object const& x1, object const& x2)
|
||||
{
|
||||
# ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
public:
|
||||
# else
|
||||
template <class> friend class allocator;
|
||||
# endif
|
||||
int tag_;
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
|
||||
}
|
||||
|
||||
template <class U> struct rebind { typedef allocator<U> other; };
|
||||
friend bool operator<(object const& x1, object const& x2)
|
||||
{
|
||||
return x1.tag1_ < x2.tag1_ ||
|
||||
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
|
||||
}
|
||||
|
||||
explicit allocator(int t = 0) : tag_(t)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <class Y> allocator(allocator<Y> const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
friend object generate(object const*, random_generator g)
|
||||
{
|
||||
int* x = 0;
|
||||
return object(generate(x, g), generate(x, g));
|
||||
}
|
||||
|
||||
allocator(allocator const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
friend std::ostream& operator<<(std::ostream& out, object const& o)
|
||||
{
|
||||
return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
|
||||
}
|
||||
};
|
||||
|
||||
~allocator()
|
||||
{
|
||||
detail::tracker.allocator_unref();
|
||||
}
|
||||
class movable : private counted_object
|
||||
{
|
||||
friend class hash;
|
||||
friend class equal_to;
|
||||
friend class less;
|
||||
int tag1_, tag2_;
|
||||
|
||||
pointer address(reference r)
|
||||
{
|
||||
return pointer(&r);
|
||||
}
|
||||
BOOST_COPYABLE_AND_MOVABLE(movable)
|
||||
public:
|
||||
explicit movable(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
|
||||
|
||||
const_pointer address(const_reference r)
|
||||
{
|
||||
return const_pointer(&r);
|
||||
}
|
||||
movable(movable const& x)
|
||||
: counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
}
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
movable(BOOST_RV_REF(movable) x)
|
||||
: counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
x.tag1_ = -1;
|
||||
x.tag2_ = -1;
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, void const* u)
|
||||
{
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
movable& operator=(BOOST_COPY_ASSIGN_REF(movable) x) // Copy assignment
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
tag1_ = x.tag1_;
|
||||
tag2_ = x.tag2_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
|
||||
::operator delete((void*) p);
|
||||
}
|
||||
movable& operator=(BOOST_RV_REF(movable) x) // Move assignment
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
tag1_ = x.tag1_;
|
||||
tag2_ = x.tag2_;
|
||||
x.tag1_ = -1;
|
||||
x.tag2_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void construct(pointer p, T const& t) {
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(t);
|
||||
}
|
||||
~movable()
|
||||
{
|
||||
tag1_ = -1;
|
||||
tag2_ = -1;
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(std::forward<Args>(args)...);
|
||||
}
|
||||
friend bool operator==(movable const& x1, movable const& x2)
|
||||
{
|
||||
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
|
||||
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
|
||||
}
|
||||
|
||||
friend bool operator!=(movable const& x1, movable const& x2)
|
||||
{
|
||||
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
|
||||
return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
|
||||
}
|
||||
|
||||
friend bool operator<(movable const& x1, movable const& x2)
|
||||
{
|
||||
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
|
||||
return x1.tag1_ < x2.tag1_ ||
|
||||
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
|
||||
}
|
||||
|
||||
friend movable generate(movable const*, random_generator g)
|
||||
{
|
||||
int* x = 0;
|
||||
return movable(generate(x, g), generate(x, g));
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, movable const& o)
|
||||
{
|
||||
return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
|
||||
}
|
||||
};
|
||||
|
||||
class implicitly_convertible : private counted_object
|
||||
{
|
||||
int tag1_, tag2_;
|
||||
|
||||
public:
|
||||
explicit implicitly_convertible(int t1 = 0, int t2 = 0)
|
||||
: tag1_(t1), tag2_(t2)
|
||||
{
|
||||
}
|
||||
|
||||
operator object() const { return object(tag1_, tag2_); }
|
||||
|
||||
operator movable() const { return movable(tag1_, tag2_); }
|
||||
|
||||
friend implicitly_convertible generate(
|
||||
implicitly_convertible const*, random_generator g)
|
||||
{
|
||||
int* x = 0;
|
||||
return implicitly_convertible(generate(x, g), generate(x, g));
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(
|
||||
std::ostream& out, implicitly_convertible const& o)
|
||||
{
|
||||
return out << "(" << o.tag1_ << "," << o.tag2_ << ")";
|
||||
}
|
||||
};
|
||||
|
||||
// Note: This is a deliberately bad hash function.
|
||||
class hash
|
||||
{
|
||||
int type_;
|
||||
|
||||
public:
|
||||
hash() : type_(0) {}
|
||||
|
||||
explicit hash(int t) : type_(t) {}
|
||||
|
||||
std::size_t operator()(object const& x) const
|
||||
{
|
||||
int result;
|
||||
switch (type_) {
|
||||
case 1:
|
||||
result = x.tag1_;
|
||||
break;
|
||||
case 2:
|
||||
result = x.tag2_;
|
||||
break;
|
||||
default:
|
||||
result = x.tag1_ + x.tag2_;
|
||||
}
|
||||
return static_cast<std::size_t>(result);
|
||||
}
|
||||
|
||||
std::size_t operator()(movable const& x) const
|
||||
{
|
||||
int result;
|
||||
switch (type_) {
|
||||
case 1:
|
||||
result = x.tag1_;
|
||||
break;
|
||||
case 2:
|
||||
result = x.tag2_;
|
||||
break;
|
||||
default:
|
||||
result = x.tag1_ + x.tag2_;
|
||||
}
|
||||
return static_cast<std::size_t>(result);
|
||||
}
|
||||
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
int result;
|
||||
switch (type_) {
|
||||
case 1:
|
||||
result = x;
|
||||
break;
|
||||
case 2:
|
||||
result = x * 7;
|
||||
break;
|
||||
default:
|
||||
result = x * 256;
|
||||
}
|
||||
return static_cast<std::size_t>(result);
|
||||
}
|
||||
|
||||
friend bool operator==(hash const& x1, hash const& x2)
|
||||
{
|
||||
return x1.type_ == x2.type_;
|
||||
}
|
||||
|
||||
friend bool operator!=(hash const& x1, hash const& x2)
|
||||
{
|
||||
return x1.type_ != x2.type_;
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t hash_value(test::object const& x) { return hash()(x); }
|
||||
|
||||
std::size_t hash_value(test::movable const& x) { return hash()(x); }
|
||||
|
||||
class less
|
||||
{
|
||||
int type_;
|
||||
|
||||
public:
|
||||
explicit less(int t = 0) : type_(t) {}
|
||||
|
||||
bool operator()(object const& x1, object const& x2) const
|
||||
{
|
||||
switch (type_) {
|
||||
case 1:
|
||||
return x1.tag1_ < x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ < x2.tag2_;
|
||||
default:
|
||||
return x1 < x2;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator()(movable const& x1, movable const& x2) const
|
||||
{
|
||||
switch (type_) {
|
||||
case 1:
|
||||
return x1.tag1_ < x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ < x2.tag2_;
|
||||
default:
|
||||
return x1 < x2;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x1, int x2) const { return x1 < x2; }
|
||||
|
||||
friend bool operator==(less const& x1, less const& x2)
|
||||
{
|
||||
return x1.type_ == x2.type_;
|
||||
}
|
||||
};
|
||||
|
||||
class equal_to
|
||||
{
|
||||
int type_;
|
||||
|
||||
public:
|
||||
equal_to() : type_(0) {}
|
||||
|
||||
explicit equal_to(int t) : type_(t) {}
|
||||
|
||||
bool operator()(object const& x1, object const& x2) const
|
||||
{
|
||||
switch (type_) {
|
||||
case 1:
|
||||
return x1.tag1_ == x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ == x2.tag2_;
|
||||
default:
|
||||
return x1 == x2;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator()(movable const& x1, movable const& x2) const
|
||||
{
|
||||
switch (type_) {
|
||||
case 1:
|
||||
return x1.tag1_ == x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ == x2.tag2_;
|
||||
default:
|
||||
return x1 == x2;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x1, int x2) const { return x1 == x2; }
|
||||
|
||||
friend bool operator==(equal_to const& x1, equal_to const& x2)
|
||||
{
|
||||
return x1.type_ == x2.type_;
|
||||
}
|
||||
|
||||
friend bool operator!=(equal_to const& x1, equal_to const& x2)
|
||||
{
|
||||
return x1.type_ != x2.type_;
|
||||
}
|
||||
|
||||
friend less create_compare(equal_to x) { return less(x.type_); }
|
||||
};
|
||||
|
||||
// allocator1 only has the old fashioned 'construct' method and has
|
||||
// a few less typedefs. allocator2 uses a custom pointer class.
|
||||
|
||||
template <class T> class allocator1
|
||||
{
|
||||
public:
|
||||
int tag_;
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind
|
||||
{
|
||||
typedef allocator1<U> other;
|
||||
};
|
||||
|
||||
allocator1() : tag_(0) { detail::tracker.allocator_ref(); }
|
||||
|
||||
explicit allocator1(int t) : tag_(t) { detail::tracker.allocator_ref(); }
|
||||
|
||||
template <class Y> allocator1(allocator1<Y> const& x) : tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
allocator1(allocator1 const& x) : tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
~allocator1() { detail::tracker.allocator_unref(); }
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n, void const*)
|
||||
{
|
||||
T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
detail::tracker.track_deallocate((void*)p, n, sizeof(T), tag_);
|
||||
::operator delete((void*)p);
|
||||
}
|
||||
|
||||
#if BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
template <typename U, typename... Args> void construct(U* p, Args&&... args)
|
||||
{
|
||||
detail::tracker.track_construct((void*)p, sizeof(U), tag_);
|
||||
new (p) U(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename U> void destroy(U* p)
|
||||
{
|
||||
detail::tracker.track_destroy((void*)p, sizeof(U), tag_);
|
||||
p->~U();
|
||||
|
||||
// Work around MSVC buggy unused parameter warning.
|
||||
ignore_variable(&p);
|
||||
}
|
||||
#else
|
||||
private:
|
||||
// I'm going to claim in the documentation that construct/destroy
|
||||
// is never used when C++11 support isn't available, so might as
|
||||
// well check that in the text.
|
||||
// TODO: Or maybe just disallow them for values?
|
||||
template <typename U> void construct(U* p);
|
||||
template <typename U, typename A0> void construct(U* p, A0 const&);
|
||||
template <typename U, typename A0, typename A1>
|
||||
void construct(U* p, A0 const&, A1 const&);
|
||||
template <typename U, typename A0, typename A1, typename A2>
|
||||
void construct(U* p, A0 const&, A1 const&, A2 const&);
|
||||
template <typename U> void destroy(U* p);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
void destroy(pointer p) {
|
||||
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
}
|
||||
bool operator==(allocator1 const& x) const { return tag_ == x.tag_; }
|
||||
|
||||
size_type max_size() const {
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
bool operator!=(allocator1 const& x) const { return tag_ != x.tag_; }
|
||||
|
||||
bool operator==(allocator const& x) const
|
||||
{
|
||||
return tag_ == x.tag_;
|
||||
}
|
||||
enum
|
||||
{
|
||||
is_select_on_copy = false,
|
||||
is_propagate_on_swap = false,
|
||||
is_propagate_on_assign = false,
|
||||
is_propagate_on_move = false
|
||||
};
|
||||
};
|
||||
|
||||
bool operator!=(allocator const& x) const
|
||||
{
|
||||
return tag_ != x.tag_;
|
||||
}
|
||||
template <class T> class ptr;
|
||||
template <class T> class const_ptr;
|
||||
|
||||
struct void_ptr
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T> friend class ptr;
|
||||
|
||||
private:
|
||||
#endif
|
||||
|
||||
void* ptr_;
|
||||
|
||||
public:
|
||||
void_ptr() : ptr_(0) {}
|
||||
|
||||
template <typename T> explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
class void_const_ptr
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T> friend class const_ptr;
|
||||
|
||||
private:
|
||||
#endif
|
||||
|
||||
void* ptr_;
|
||||
|
||||
public:
|
||||
void_const_ptr() : ptr_(0) {}
|
||||
|
||||
template <typename T>
|
||||
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_)
|
||||
{
|
||||
}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T> class ptr
|
||||
{
|
||||
friend class allocator2<T>;
|
||||
friend class const_ptr<T>;
|
||||
friend struct void_ptr;
|
||||
|
||||
T* ptr_;
|
||||
|
||||
ptr(T* x) : ptr_(x) {}
|
||||
|
||||
public:
|
||||
ptr() : ptr_(0) {}
|
||||
explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
ptr& operator++()
|
||||
{
|
||||
++ptr_;
|
||||
return *this;
|
||||
}
|
||||
ptr operator++(int)
|
||||
{
|
||||
ptr tmp(*this);
|
||||
++ptr_;
|
||||
return tmp;
|
||||
}
|
||||
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr<T>(s + p.ptr_); }
|
||||
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T> class const_ptr
|
||||
{
|
||||
friend class allocator2<T>;
|
||||
friend struct const_void_ptr;
|
||||
|
||||
T const* ptr_;
|
||||
|
||||
const_ptr(T const* ptr) : ptr_(ptr) {}
|
||||
|
||||
public:
|
||||
const_ptr() : ptr_(0) {}
|
||||
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*)x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return *ptr_; }
|
||||
T const* operator->() const { return ptr_; }
|
||||
const_ptr& operator++()
|
||||
{
|
||||
++ptr_;
|
||||
return *this;
|
||||
}
|
||||
const_ptr operator++(int)
|
||||
{
|
||||
const_ptr tmp(*this);
|
||||
++ptr_;
|
||||
return tmp;
|
||||
}
|
||||
const_ptr operator+(std::ptrdiff_t s) const { return const_ptr(ptr_ + s); }
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
|
||||
{
|
||||
return ptr<T>(s + p.ptr_);
|
||||
}
|
||||
T const& operator[](int s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T> class allocator2
|
||||
{
|
||||
#ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
public:
|
||||
#else
|
||||
template <class> friend class allocator2;
|
||||
#endif
|
||||
int tag_;
|
||||
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef void_ptr void_pointer;
|
||||
typedef void_const_ptr const_void_pointer;
|
||||
typedef ptr<T> pointer;
|
||||
typedef const_ptr<T> const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind
|
||||
{
|
||||
typedef allocator2<U> other;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(allocator<T> const& x, allocator<T> const& y,
|
||||
test::derived_type)
|
||||
allocator2() : tag_(0) { detail::tracker.allocator_ref(); }
|
||||
|
||||
explicit allocator2(int t) : tag_(t) { detail::tracker.allocator_ref(); }
|
||||
|
||||
template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_)
|
||||
{
|
||||
return x == y;
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(__GNUC__, < 3)
|
||||
void swap(test::object& x, test::object& y) {
|
||||
test::object tmp;
|
||||
tmp = x;
|
||||
x = y;
|
||||
y = tmp;
|
||||
allocator2(allocator2 const& x) : tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
void swap(test::hash& x, test::hash& y) {
|
||||
test::hash tmp;
|
||||
tmp = x;
|
||||
x = y;
|
||||
y = tmp;
|
||||
~allocator2() { detail::tracker.allocator_unref(); }
|
||||
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)p.ptr_, n, sizeof(T), tag_);
|
||||
return p;
|
||||
}
|
||||
|
||||
void swap(test::less& x, test::less& y) {
|
||||
test::less tmp;
|
||||
tmp = x;
|
||||
x = y;
|
||||
y = tmp;
|
||||
pointer allocate(size_type n, void const*)
|
||||
{
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void swap(test::equal_to& x, test::equal_to& y) {
|
||||
test::equal_to tmp;
|
||||
tmp = x;
|
||||
x = y;
|
||||
y = tmp;
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
detail::tracker.track_deallocate((void*)p.ptr_, n, sizeof(T), tag_);
|
||||
::operator delete((void*)p.ptr_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void swap(test::allocator<T>& x, test::allocator<T>& y) {
|
||||
test::allocator<T> tmp;
|
||||
tmp = x;
|
||||
x = y;
|
||||
y = tmp;
|
||||
void construct(T* p, T const& t)
|
||||
{
|
||||
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
|
||||
new (p) T(t);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
|
||||
new (p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p)
|
||||
{
|
||||
detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
}
|
||||
|
||||
size_type max_size() const
|
||||
{
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
|
||||
bool operator==(allocator2 const& x) const { return tag_ == x.tag_; }
|
||||
|
||||
bool operator!=(allocator2 const& x) const { return tag_ != x.tag_; }
|
||||
|
||||
enum
|
||||
{
|
||||
is_select_on_copy = false,
|
||||
is_propagate_on_swap = false,
|
||||
is_propagate_on_assign = false,
|
||||
is_propagate_on_move = false
|
||||
};
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(
|
||||
allocator1<T> const& x, allocator1<T> const& y, test::derived_type)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(
|
||||
allocator2<T> const& x, allocator2<T> const& y, test::derived_type)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,47 +0,0 @@
|
||||
|
||||
# Copyright 2006-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)
|
||||
|
||||
import testing ;
|
||||
|
||||
project unordered-test/unordered
|
||||
: requirements
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>gcc:<define>_GLIBCXX_DEBUG
|
||||
<toolset>darwin:<define>_GLIBCXX_DEBUG
|
||||
<toolset>msvc:<warnings-as-errors>on
|
||||
#<toolset>gcc:<warnings-as-errors>on
|
||||
#<toolset>darwin:<warnings-as-errors>on
|
||||
;
|
||||
|
||||
test-suite unordered
|
||||
:
|
||||
[ run fwd_set_test.cpp ]
|
||||
[ run fwd_map_test.cpp ]
|
||||
[ run compile_set.cpp ]
|
||||
[ run compile_map.cpp ]
|
||||
[ run link_test_1.cpp link_test_2.cpp ]
|
||||
[ run incomplete_test.cpp ]
|
||||
[ run simple_tests.cpp ]
|
||||
[ run equivalent_keys_tests.cpp ]
|
||||
[ run constructor_tests.cpp ]
|
||||
[ run copy_tests.cpp ]
|
||||
[ run move_tests.cpp : : : <test-info>always_show_run_output ]
|
||||
[ run assign_tests.cpp ]
|
||||
[ run insert_tests.cpp ]
|
||||
[ run insert_stable_tests.cpp ]
|
||||
[ run unnecessary_copy_tests.cpp ]
|
||||
[ run erase_tests.cpp ]
|
||||
[ run erase_equiv_tests.cpp ]
|
||||
[ run find_tests.cpp ]
|
||||
[ run at_tests.cpp ]
|
||||
[ run bucket_tests.cpp ]
|
||||
[ run load_factor_tests.cpp ]
|
||||
[ run rehash_tests.cpp ]
|
||||
[ run equality_tests.cpp ]
|
||||
[ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 ]
|
||||
;
|
288
test/unordered/allocator_traits.cpp
Normal file
288
test/unordered/allocator_traits.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
|
||||
// Copyright 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)
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
|
||||
// Boilerplate
|
||||
|
||||
#define ALLOCATOR_METHODS(name) \
|
||||
template <typename U> struct rebind \
|
||||
{ \
|
||||
typedef name<U> other; \
|
||||
}; \
|
||||
\
|
||||
name() {} \
|
||||
template <typename Y> name(name<Y> const&) {} \
|
||||
T* address(T& r) { return &r; } \
|
||||
T const* address(T const& r) { return &r; } \
|
||||
T* allocate(std::size_t n) \
|
||||
{ \
|
||||
return static_cast<T*>(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
T* allocate(std::size_t n, void const*) \
|
||||
{ \
|
||||
return static_cast<T*>(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
void deallocate(T* p, std::size_t) { ::operator delete((void*)p); } \
|
||||
void construct(T* p, T const& t) { new (p) T(t); } \
|
||||
void destroy(T* p) { p->~T(); } \
|
||||
std::size_t max_size() const \
|
||||
{ \
|
||||
return (std::numeric_limits<std::size_t>::max)(); \
|
||||
} \
|
||||
bool operator==(name<T> const&) const { return true; } \
|
||||
bool operator!=(name<T> const&) const { return false; } \
|
||||
/**/
|
||||
|
||||
#define ALLOCATOR_METHODS_TYPEDEFS(name) \
|
||||
template <typename U> struct rebind \
|
||||
{ \
|
||||
typedef name<U> other; \
|
||||
}; \
|
||||
\
|
||||
name() {} \
|
||||
template <typename Y> name(name<Y> const&) {} \
|
||||
pointer address(T& r) { return &r; } \
|
||||
const_pointer address(T const& r) { return &r; } \
|
||||
pointer allocate(std::size_t n) \
|
||||
{ \
|
||||
return pointer(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
pointer allocate(std::size_t n, void const*) \
|
||||
{ \
|
||||
return pointer(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
void deallocate(pointer p, std::size_t) { ::operator delete((void*)p); } \
|
||||
void construct(T* p, T const& t) { new (p) T(t); } \
|
||||
void destroy(T* p) { p->~T(); } \
|
||||
size_type max_size() const \
|
||||
{ \
|
||||
return (std::numeric_limits<size_type>::max)(); \
|
||||
} \
|
||||
bool operator==(name<T> const&) { return true; } \
|
||||
bool operator!=(name<T> const&) { return false; } \
|
||||
/**/
|
||||
|
||||
struct yes_type
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = true
|
||||
};
|
||||
};
|
||||
struct no_type
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = false
|
||||
};
|
||||
};
|
||||
|
||||
// For tracking calls...
|
||||
|
||||
static int selected;
|
||||
void reset() { selected = 0; }
|
||||
|
||||
template <typename Allocator> int call_select()
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<Allocator> traits;
|
||||
Allocator a;
|
||||
|
||||
reset();
|
||||
BOOST_TEST(traits::select_on_container_copy_construction(a) == a);
|
||||
return selected;
|
||||
}
|
||||
|
||||
// Empty allocator test
|
||||
|
||||
template <typename T> struct empty_allocator
|
||||
{
|
||||
typedef T value_type;
|
||||
ALLOCATOR_METHODS(empty_allocator)
|
||||
};
|
||||
|
||||
void test_empty_allocator()
|
||||
{
|
||||
typedef empty_allocator<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
#else
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 0);
|
||||
}
|
||||
|
||||
// allocator 1
|
||||
|
||||
template <typename T> struct allocator1
|
||||
{
|
||||
typedef T value_type;
|
||||
ALLOCATOR_METHODS(allocator1)
|
||||
|
||||
typedef yes_type propagate_on_container_copy_assignment;
|
||||
typedef yes_type propagate_on_container_move_assignment;
|
||||
typedef yes_type propagate_on_container_swap;
|
||||
typedef yes_type is_always_equal;
|
||||
|
||||
allocator1<T> select_on_container_copy_construction() const
|
||||
{
|
||||
++selected;
|
||||
return allocator1<T>();
|
||||
}
|
||||
};
|
||||
|
||||
void test_allocator1()
|
||||
{
|
||||
typedef allocator1<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
#else
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
}
|
||||
|
||||
// allocator 2
|
||||
|
||||
template <typename Alloc> struct allocator2_base
|
||||
{
|
||||
Alloc select_on_container_copy_construction() const
|
||||
{
|
||||
++selected;
|
||||
return Alloc();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct allocator2 : allocator2_base<allocator2<T> >
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
ALLOCATOR_METHODS(allocator2)
|
||||
|
||||
typedef no_type propagate_on_container_copy_assignment;
|
||||
typedef no_type propagate_on_container_move_assignment;
|
||||
typedef no_type propagate_on_container_swap;
|
||||
typedef no_type is_always_equal;
|
||||
};
|
||||
|
||||
void test_allocator2()
|
||||
{
|
||||
typedef allocator2<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(!traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
}
|
||||
|
||||
// allocator 3
|
||||
|
||||
template <typename T> struct ptr
|
||||
{
|
||||
T* value_;
|
||||
|
||||
ptr(void* v) : value_((T*)v) {}
|
||||
T& operator*() const { return *value_; }
|
||||
};
|
||||
|
||||
template <> struct ptr<void>
|
||||
{
|
||||
void* value_;
|
||||
ptr(void* v) : value_(v) {}
|
||||
};
|
||||
|
||||
template <> struct ptr<const void>
|
||||
{
|
||||
void const* value_;
|
||||
ptr(void const* v) : value_(v) {}
|
||||
};
|
||||
|
||||
template <typename T> struct allocator3
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef ptr<T> pointer;
|
||||
typedef ptr<T const> const_pointer;
|
||||
typedef unsigned short size_type;
|
||||
|
||||
int x; // Just to make it non-empty, so that is_always_equal is false.
|
||||
|
||||
ALLOCATOR_METHODS_TYPEDEFS(allocator3)
|
||||
|
||||
typedef yes_type propagate_on_container_copy_assignment;
|
||||
typedef no_type propagate_on_container_move_assignment;
|
||||
|
||||
allocator3<T> select_on_container_copy_construction() const
|
||||
{
|
||||
++selected;
|
||||
return allocator3<T>();
|
||||
}
|
||||
};
|
||||
|
||||
void test_allocator3()
|
||||
{
|
||||
typedef allocator3<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::size_type, unsigned short>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, ptr<int> >::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, ptr<int const> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(!traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_empty_allocator();
|
||||
test_allocator1();
|
||||
test_allocator2();
|
||||
test_allocator3();
|
||||
return boost::report_errors();
|
||||
}
|
@ -3,122 +3,271 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include "../objects/cxx11_allocator.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace assign_tests {
|
||||
|
||||
test::seed_t seed(96785);
|
||||
test::seed_t initialize_seed(96785);
|
||||
|
||||
template <class T>
|
||||
void assign_tests1(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
template <class T> void assign_tests1(T*, test::random_generator generator)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
|
||||
std::cerr<<"assign_tests1.1\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.1\n";
|
||||
{
|
||||
T x;
|
||||
x = x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
test::check_instances check_;
|
||||
|
||||
T x;
|
||||
x = x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests1.2\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n";
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
test::check_instances check_;
|
||||
|
||||
test::ordered<T> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
|
||||
x = x;
|
||||
tracker.compare(x);
|
||||
test::ordered<T> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
T y;
|
||||
y.max_load_factor(x.max_load_factor() / 20);
|
||||
y = x;
|
||||
tracker.compare(y);
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
x = x;
|
||||
tracker.compare(x);
|
||||
|
||||
T y;
|
||||
y.max_load_factor(x.max_load_factor() / 20);
|
||||
float mlf = x.max_load_factor();
|
||||
y = x;
|
||||
tracker.compare(x);
|
||||
tracker.compare(y);
|
||||
BOOST_TEST(x.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.load_factor() <= y.max_load_factor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void assign_tests2(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||
template <class T> void assign_tests2(T*, test::random_generator generator)
|
||||
{
|
||||
typename T::hasher hf1(1);
|
||||
typename T::hasher hf2(2);
|
||||
typename T::key_equal eq1(1);
|
||||
typename T::key_equal eq2(2);
|
||||
typename T::allocator_type al1(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
std::cerr<<"assign_tests2.1\n";
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.0 - empty container\n";
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x2, v);
|
||||
test::check_instances check_;
|
||||
|
||||
T x1(0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x1, x2);
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.2\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1\n";
|
||||
{
|
||||
test::random_values<T> v1(100, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x1, v);
|
||||
test::check_container(x2, v);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1a\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(0, generator);
|
||||
test::random_values<T> v2(1000, generator);
|
||||
T x1(0, hf2, eq2);
|
||||
T x2(v2.begin(), v2.end(), 0, hf1, eq1);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq2));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq2));
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.2\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(100, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
} else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.3\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
test::random_values<T> v1(100, generator), v2(1000, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
} else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
UNORDERED_TEST(assign_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.4\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
UNORDERED_TEST(assign_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
test::random_values<T> v1(1000, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
} else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
UNORDERED_AUTO_TEST(assign_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_set_prop_assign;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_multiset_prop_assign;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_map_prop_assign;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_multimap_prop_assign;
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_set_no_prop_assign;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_multiset_no_prop_assign;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_map_no_prop_assign;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_multimap_no_prop_assign;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
template <typename T> bool is_propagate(T*)
|
||||
{
|
||||
return T::allocator_type::is_propagate_on_assign;
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (check_traits) {
|
||||
BOOST_TEST(!is_propagate(test_set));
|
||||
BOOST_TEST(is_propagate(test_set_prop_assign));
|
||||
BOOST_TEST(!is_propagate(test_set_no_prop_assign));
|
||||
}
|
||||
|
||||
UNORDERED_TEST(assign_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap)(
|
||||
test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(
|
||||
test_multimap_prop_assign)(test_set_no_prop_assign)(
|
||||
test_multiset_no_prop_assign)(test_map_no_prop_assign)(
|
||||
test_multimap_no_prop_assign))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
assign_tests2, ((test_set)(test_multiset)(test_map)(test_multimap)(
|
||||
test_set_prop_assign)(test_multiset_prop_assign)(
|
||||
test_map_prop_assign)(test_multimap_prop_assign)(
|
||||
test_set_no_prop_assign)(test_multiset_no_prop_assign)(
|
||||
test_map_no_prop_assign)(test_multimap_no_prop_assign))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST (assign_default_initializer_list) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
|
||||
std::initializer_list<std::pair<int const, int> > init;
|
||||
boost::unordered_map<int, int> x1;
|
||||
x1[25] = 3;
|
||||
@ -126,27 +275,23 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) {
|
||||
BOOST_TEST(!x1.empty());
|
||||
x1 = init;
|
||||
BOOST_TEST(x1.empty());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
|
||||
!defined(BOOST_NO_INITIALIZER_LISTS)
|
||||
|
||||
UNORDERED_AUTO_TEST(assign_initializer_list)
|
||||
{
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
UNORDERED_AUTO_TEST (assign_initializer_list) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
|
||||
|
||||
boost::unordered_set<int> x;
|
||||
x.insert(10);
|
||||
x.insert(20);
|
||||
x = { 1, 2, -10 };
|
||||
x = {1, 2, -10};
|
||||
BOOST_TEST(x.find(10) == x.end());
|
||||
BOOST_TEST(x.find(-10) != x.end());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,32 +3,65 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace at_tests {
|
||||
|
||||
UNORDERED_AUTO_TEST(at_tests) {
|
||||
UNORDERED_AUTO_TEST (at_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
|
||||
|
||||
boost::unordered_map<std::string, int> x;
|
||||
typedef boost::unordered_map<std::string, int>::iterator iterator;
|
||||
boost::unordered_map<std::string, int> const& x_const(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check empty container" << std::endl;
|
||||
|
||||
try {
|
||||
x.at("one");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
|
||||
try {
|
||||
x_const.at("one");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl;
|
||||
|
||||
x["one"] = 1;
|
||||
x["two"] = 2;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check existing elements" << std::endl;
|
||||
|
||||
BOOST_TEST(x.at("one") == 1);
|
||||
BOOST_TEST(x.at("two") == 2);
|
||||
BOOST_TEST(x_const.at("one") == 1);
|
||||
BOOST_TEST(x_const.at("two") == 2);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check missing element" << std::endl;
|
||||
|
||||
try {
|
||||
x.at("three");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
x.at("three");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
catch(std::out_of_range) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
x_const.at("three");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,10 +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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <algorithm>
|
||||
#include "../objects/test.hpp"
|
||||
@ -14,72 +17,78 @@
|
||||
#include "../helpers/helpers.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#endif
|
||||
|
||||
namespace bucket_tests {
|
||||
|
||||
test::seed_t seed(54635);
|
||||
test::seed_t initialize_seed(54635);
|
||||
|
||||
template <class X>
|
||||
void tests(X* = 0, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator;
|
||||
template <class X> void tests(X*, test::random_generator generator)
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
typedef typename X::size_type size_type;
|
||||
typedef typename X::const_local_iterator const_local_iterator;
|
||||
test::random_values<X> v(1000, generator);
|
||||
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
BOOST_TEST(x.bucket_count() < x.max_bucket_count());
|
||||
std::cerr<<x.bucket_count()<<"<"<<x.max_bucket_count()<<"\n";
|
||||
BOOST_TEST(x.bucket_count() <= x.max_bucket_count());
|
||||
if (!(x.bucket_count() <= x.max_bucket_count())) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x.bucket_count()
|
||||
<< "<=" << x.max_bucket_count() << "\n";
|
||||
}
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator
|
||||
it = v.begin(), end = v.end(); it != end; ++it)
|
||||
{
|
||||
size_type bucket = x.bucket(test::get_key<X>(*it));
|
||||
for (typename test::random_values<X>::const_iterator it = v.begin(),
|
||||
end = v.end();
|
||||
it != end; ++it) {
|
||||
size_type bucket = x.bucket(test::get_key<X>(*it));
|
||||
|
||||
BOOST_TEST(bucket < x.bucket_count());
|
||||
if(bucket < x.max_bucket_count()) {
|
||||
// lit? lend?? I need a new naming scheme.
|
||||
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
|
||||
while(lit != lend
|
||||
&& test::get_key<X>(*it) != test::get_key<X>(*lit))
|
||||
{
|
||||
++lit;
|
||||
}
|
||||
BOOST_TEST(lit != lend);
|
||||
BOOST_TEST(bucket < x.bucket_count());
|
||||
if (bucket < x.bucket_count()) {
|
||||
// lit? lend?? I need a new naming scheme.
|
||||
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
|
||||
while (lit != lend && test::get_key<X>(*it) != test::get_key<X>(*lit)) {
|
||||
++lit;
|
||||
}
|
||||
BOOST_TEST(lit != lend);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_type i = 0; i < x.bucket_count(); ++i) {
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x.begin(i), x.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x.cbegin(i), x.cend(i))));
|
||||
X const& x_ref = x;
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x_ref.begin(i), x_ref.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x_ref.cbegin(i), x_ref.cend(i))));
|
||||
for (size_type i = 0; i < x.bucket_count(); ++i) {
|
||||
BOOST_TEST(x.bucket_size(i) ==
|
||||
static_cast<size_type>(std::distance(x.begin(i), x.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) ==
|
||||
static_cast<size_type>(std::distance(x.cbegin(i), x.cend(i))));
|
||||
X const& x_ref = x;
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
|
||||
x_ref.begin(i), x_ref.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
|
||||
x_ref.cbegin(i), x_ref.cend(i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_multimap_std_alloc;
|
||||
|
||||
UNORDERED_TEST(tests, ((test_set)(test_multiset)(test_map)(test_multimap)))
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(tests,
|
||||
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(
|
||||
test_multimap))((default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -6,172 +6,243 @@
|
||||
// This test creates the containers with members that meet their minimum
|
||||
// requirements. Makes sure everything compiles and is defined correctly.
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <iostream>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/minimal.hpp"
|
||||
#include "./compile_tests.hpp"
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::default_copy_constructible,
|
||||
#define INSTANTIATE(type) \
|
||||
template class boost::unordered::detail::instantiate_##type
|
||||
|
||||
INSTANTIATE(map)<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multimap)<int const, int const, boost::hash<int>,
|
||||
std::equal_to<int>, test::minimal::allocator<int> >;
|
||||
|
||||
INSTANTIATE(
|
||||
map)<test::minimal::assignable const, test::minimal::default_assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multimap)<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
typedef std::pair<test::minimal::assignable const, test::minimal::assignable>
|
||||
value_type;
|
||||
value_type value(x, x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
template class boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
|
||||
container_test(int_map, std::pair<int const, int>(0, 0));
|
||||
container_test(int_map2, std::pair<int const, int>(0, 0));
|
||||
container_test(map, value);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_multimap2;
|
||||
|
||||
boost::unordered_multimap<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multimap;
|
||||
|
||||
container_test(int_multimap, std::pair<int const, int>(0, 0));
|
||||
container_test(int_multimap2, std::pair<int const, int>(0, 0));
|
||||
container_test(multimap, value);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
typedef std::pair<test::minimal::copy_constructible_equality_comparable const,
|
||||
test::minimal::copy_constructible_equality_comparable>
|
||||
value_type;
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_map<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
|
||||
equality_test(int_map);
|
||||
equality_test(int_map2);
|
||||
equality_test(map);
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_multimap2;
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multimap;
|
||||
|
||||
equality_test(int_multimap);
|
||||
equality_test(int_multimap2);
|
||||
equality_test(multimap);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
std::pair<int const, int> map_value(0, 0);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<int, int> map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
map2;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, value, value);
|
||||
unordered_copyable_test(map, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map, value, value);
|
||||
|
||||
unordered_unique_test(map2, map_value);
|
||||
unordered_map_test(map2, value, value);
|
||||
unordered_copyable_test(map2, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map2, value, value);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
multimap2;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, value, value);
|
||||
unordered_copyable_test(multimap, value, map_value, hash, equal_to);
|
||||
|
||||
unordered_equivalent_test(multimap2, map_value);
|
||||
unordered_map_test(multimap2, value, value);
|
||||
unordered_copyable_test(multimap2, value, map_value, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
typedef std::pair<test::minimal::assignable const, test::minimal::assignable>
|
||||
map_value_type;
|
||||
map_value_type map_value(assignable, assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map;
|
||||
|
||||
UNORDERED_AUTO_TEST(test0)
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, assignable, assignable);
|
||||
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
|
||||
unordered_map_member_test(map, map_value);
|
||||
|
||||
boost::unordered_map<test::minimal::assignable,
|
||||
test::minimal::default_assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map2;
|
||||
|
||||
test::minimal::default_assignable default_assignable;
|
||||
|
||||
unordered_map_functions(map2, assignable, default_assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
multimap;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, assignable, assignable);
|
||||
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
|
||||
unordered_map_member_test(multimap, map_value);
|
||||
}
|
||||
|
||||
// Test for ambiguity when using key convertible from iterator
|
||||
// See LWG2059
|
||||
|
||||
struct lwg2059_key
|
||||
{
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
test::minimal::copy_constructible> value_type;
|
||||
value_type value(
|
||||
test::minimal::assignable::create(),
|
||||
test::minimal::copy_constructible::create());
|
||||
int value;
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
template <typename T> lwg2059_key(T v) : value(v) {}
|
||||
};
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > map;
|
||||
|
||||
container_test(int_map, std::pair<int const, int>(0, 0));
|
||||
container_test(map, value);
|
||||
|
||||
std::cout<<"Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > multimap;
|
||||
|
||||
container_test(int_multimap, std::pair<int const, int>(0, 0));
|
||||
container_test(multimap, value);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_tests) {
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
test::minimal::copy_constructible> value_type;
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > map;
|
||||
|
||||
equality_test(int_map);
|
||||
equality_test(map);
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > multimap;
|
||||
|
||||
equality_test(int_multimap);
|
||||
equality_test(multimap);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test1) {
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
std::pair<int const, int> map_value(0, 0);
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<int, int> map;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, value, value);
|
||||
unordered_test(map, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map, value, value);
|
||||
|
||||
std::cout<<"Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> multimap;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, value, value);
|
||||
unordered_test(multimap, value, map_value, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test2)
|
||||
std::size_t hash_value(lwg2059_key x)
|
||||
{
|
||||
test::minimal::assignable assignable
|
||||
= test::minimal::assignable::create();
|
||||
test::minimal::copy_constructible copy_constructible
|
||||
= test::minimal::copy_constructible::create();
|
||||
test::minimal::hash<test::minimal::assignable> hash
|
||||
= test::minimal::hash<test::minimal::assignable>::create();
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to
|
||||
= test::minimal::equal_to<test::minimal::assignable>::create();
|
||||
return static_cast<std::size_t>(x.value);
|
||||
}
|
||||
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
test::minimal::copy_constructible> map_value_type;
|
||||
map_value_type map_value(assignable, copy_constructible);
|
||||
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
UNORDERED_AUTO_TEST (lwg2059) {
|
||||
{
|
||||
boost::unordered_map<lwg2059_key, int> x;
|
||||
x.emplace(lwg2059_key(10), 5);
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > map;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, assignable, copy_constructible);
|
||||
unordered_test(map, assignable, map_value, hash, equal_to);
|
||||
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::default_copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > map2;
|
||||
|
||||
test::minimal::default_copy_constructible default_copy_constructible;
|
||||
|
||||
unordered_map_functions(map2, assignable, default_copy_constructible);
|
||||
|
||||
std::cout<<"Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > multimap;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, assignable, copy_constructible);
|
||||
unordered_test(multimap, assignable, map_value, hash, equal_to);
|
||||
{
|
||||
boost::unordered_multimap<lwg2059_key, int> x;
|
||||
x.emplace(lwg2059_key(10), 5);
|
||||
x.erase(x.begin());
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -6,138 +6,308 @@
|
||||
// This test creates the containers with members that meet their minimum
|
||||
// requirements. Makes sure everything compiles and is defined correctly.
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <iostream>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/minimal.hpp"
|
||||
#include "./compile_tests.hpp"
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class boost::unordered_set<
|
||||
test::minimal::assignable,
|
||||
#define INSTANTIATE(type) \
|
||||
template class boost::unordered::detail::instantiate_##type
|
||||
|
||||
INSTANTIATE(set)<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multiset)<int const, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
INSTANTIATE(set)<test::minimal::assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multiset)<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<int> int_set;
|
||||
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
boost::unordered_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
template class boost::unordered_multiset<
|
||||
test::minimal::assignable,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
|
||||
container_test(int_set, 0);
|
||||
container_test(int_set2, 0);
|
||||
container_test(set, assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_multiset2;
|
||||
|
||||
boost::unordered_multiset<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
multiset;
|
||||
|
||||
UNORDERED_AUTO_TEST(test0)
|
||||
{
|
||||
test::minimal::assignable assignable = test::minimal::assignable::create();
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
boost::unordered_set<int> int_set;
|
||||
boost::unordered_set<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > set;
|
||||
|
||||
container_test(int_set, 0);
|
||||
container_test(set, assignable);
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
boost::unordered_multiset<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > multiset;
|
||||
|
||||
container_test(int_multiset, 0);
|
||||
container_test(multiset, assignable);
|
||||
container_test(int_multiset, 0);
|
||||
container_test(int_multiset2, 0);
|
||||
container_test(multiset, assignable);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_tests) {
|
||||
typedef test::minimal::assignable value_type;
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
typedef test::minimal::copy_constructible_equality_comparable value_type;
|
||||
|
||||
boost::unordered_set<int> int_set;
|
||||
boost::unordered_set<int> int_set;
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > set;
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
equality_test(int_set);
|
||||
equality_test(set);
|
||||
boost::unordered_set<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
set;
|
||||
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
equality_test(int_set);
|
||||
equality_test(int_set2);
|
||||
equality_test(set);
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > multiset;
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
equality_test(int_multiset);
|
||||
equality_test(multiset);
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_multiset2;
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multiset;
|
||||
|
||||
equality_test(int_multiset);
|
||||
equality_test(int_multiset2);
|
||||
equality_test(multiset);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test1)
|
||||
{
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set." << std::endl;
|
||||
|
||||
boost::unordered_set<int> set;
|
||||
|
||||
unordered_unique_test(set, value);
|
||||
unordered_set_test(set, value);
|
||||
unordered_test(set, value, value, hash, equal_to);
|
||||
boost::unordered_set<int> set;
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
set2;
|
||||
|
||||
boost::unordered_multiset<int> multiset;
|
||||
|
||||
unordered_equivalent_test(multiset, value);
|
||||
unordered_set_test(multiset, value);
|
||||
unordered_test(multiset, value, value, hash, equal_to);
|
||||
unordered_unique_test(set, value);
|
||||
unordered_set_test(set, value);
|
||||
unordered_copyable_test(set, value, value, hash, equal_to);
|
||||
|
||||
unordered_unique_test(set2, value);
|
||||
unordered_set_test(set2, value);
|
||||
unordered_copyable_test(set2, value, value, hash, equal_to);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl;
|
||||
|
||||
boost::unordered_multiset<int> multiset;
|
||||
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
multiset2;
|
||||
|
||||
unordered_equivalent_test(multiset, value);
|
||||
unordered_set_test(multiset, value);
|
||||
unordered_copyable_test(multiset, value, value, hash, equal_to);
|
||||
|
||||
unordered_equivalent_test(multiset2, value);
|
||||
unordered_set_test(multiset2, value);
|
||||
unordered_copyable_test(multiset2, value, value, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test2)
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
|
||||
unordered_unique_test(set, assignable);
|
||||
unordered_set_test(set, assignable);
|
||||
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
|
||||
unordered_set_member_test(set, assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
multiset;
|
||||
|
||||
unordered_equivalent_test(multiset, assignable);
|
||||
unordered_set_test(multiset, assignable);
|
||||
unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
|
||||
unordered_set_member_test(multiset, assignable);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (movable1_tests) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::movable1 movable1(x);
|
||||
test::minimal::hash<test::minimal::movable1> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable1> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> >
|
||||
set;
|
||||
|
||||
// unordered_unique_test(set, movable1);
|
||||
unordered_set_test(set, movable1);
|
||||
unordered_movable_test(set, movable1, movable1, hash, equal_to);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> >
|
||||
multiset;
|
||||
|
||||
// unordered_equivalent_test(multiset, movable1);
|
||||
unordered_set_test(multiset, movable1);
|
||||
unordered_movable_test(multiset, movable1, movable1, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (movable2_tests) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::movable2 movable2(x);
|
||||
test::minimal::hash<test::minimal::movable2> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable2> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> >
|
||||
set;
|
||||
|
||||
// unordered_unique_test(set, movable2);
|
||||
unordered_set_test(set, movable2);
|
||||
unordered_movable_test(set, movable2, movable2, hash, equal_to);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> >
|
||||
multiset;
|
||||
|
||||
// unordered_equivalent_test(multiset, movable2);
|
||||
unordered_set_test(multiset, movable2);
|
||||
unordered_movable_test(multiset, movable2, movable2, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (destructible_tests) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::destructible destructible(x);
|
||||
test::minimal::hash<test::minimal::destructible> hash(x);
|
||||
test::minimal::equal_to<test::minimal::destructible> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> >
|
||||
set;
|
||||
|
||||
unordered_destructible_test(set);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> >
|
||||
multiset;
|
||||
|
||||
unordered_destructible_test(multiset);
|
||||
}
|
||||
|
||||
// Test for ambiguity when using key convertible from iterator
|
||||
// See LWG2059
|
||||
|
||||
struct lwg2059_key
|
||||
{
|
||||
test::minimal::assignable assignable
|
||||
= test::minimal::assignable::create();
|
||||
test::minimal::copy_constructible copy_constructible
|
||||
= test::minimal::copy_constructible::create();
|
||||
test::minimal::hash<test::minimal::assignable> hash
|
||||
= test::minimal::hash<test::minimal::assignable>::create();
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to
|
||||
= test::minimal::equal_to<test::minimal::assignable>::create();
|
||||
int value;
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
template <typename T> lwg2059_key(T v) : value(v) {}
|
||||
};
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > set;
|
||||
std::size_t hash_value(lwg2059_key x)
|
||||
{
|
||||
return static_cast<std::size_t>(x.value);
|
||||
}
|
||||
|
||||
unordered_unique_test(set, assignable);
|
||||
unordered_set_test(set, assignable);
|
||||
unordered_test(set, assignable, assignable, hash, equal_to);
|
||||
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
UNORDERED_AUTO_TEST (lwg2059) {
|
||||
{
|
||||
boost::unordered_set<lwg2059_key> x;
|
||||
x.emplace(lwg2059_key(10));
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > multiset;
|
||||
|
||||
unordered_equivalent_test(multiset, assignable);
|
||||
unordered_set_test(multiset, assignable);
|
||||
unordered_test(multiset, assignable, assignable, hash, equal_to);
|
||||
{
|
||||
boost::unordered_multiset<lwg2059_key> x;
|
||||
x.emplace(lwg2059_key(10));
|
||||
x.erase(x.begin());
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,15 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2006-2010 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
@ -15,392 +18,429 @@
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace constructor_tests {
|
||||
|
||||
test::seed_t seed(356730);
|
||||
test::seed_t initialize_seed(356730);
|
||||
|
||||
template <class T>
|
||||
void constructor_tests1(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||
template <class T>
|
||||
void constructor_tests1(T*, test::random_generator generator)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
typename T::allocator_type al;
|
||||
|
||||
std::cerr<<"Construct 1\n";
|
||||
UNORDERED_SUB_TEST("Construct 1")
|
||||
{
|
||||
T x(0, hf, eq);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 2\n";
|
||||
UNORDERED_SUB_TEST("Construct 2")
|
||||
{
|
||||
T x(100, hf);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(100, hf);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 3\n";
|
||||
UNORDERED_SUB_TEST("Construct 3")
|
||||
{
|
||||
T x(2000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 2000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(2000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 2000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 4\n";
|
||||
UNORDERED_SUB_TEST("Construct 4")
|
||||
{
|
||||
T x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
T x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 5\n";
|
||||
UNORDERED_SUB_TEST("Construct 5")
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 6\n";
|
||||
UNORDERED_SUB_TEST("Construct 6")
|
||||
{
|
||||
test::random_values<T> v(10, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(10, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 7\n";
|
||||
UNORDERED_SUB_TEST("Construct 7")
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 100);
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 100);
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 8\n";
|
||||
UNORDERED_SUB_TEST("Construct 8")
|
||||
{
|
||||
test::random_values<T> v(1, generator);
|
||||
T x(v.begin(), v.end());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1, generator);
|
||||
T x(v.begin(), v.end());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 9\n";
|
||||
UNORDERED_SUB_TEST("Construct 9")
|
||||
{
|
||||
T x(0, hf, eq, al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq, al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 10\n";
|
||||
UNORDERED_SUB_TEST("Construct 10")
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 11\n";
|
||||
UNORDERED_SUB_TEST("Construct 11")
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void constructor_tests2(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||
template <class T>
|
||||
void constructor_tests2(T*, test::random_generator const& generator)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::hasher hf1(1);
|
||||
typename T::hasher hf2(2);
|
||||
typename T::key_equal eq;
|
||||
typename T::key_equal eq1(1);
|
||||
typename T::key_equal eq2(2);
|
||||
typename T::allocator_type al;
|
||||
typename T::allocator_type al1(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
std::cerr<<"Construct 1\n";
|
||||
UNORDERED_SUB_TEST("Construct 1")
|
||||
{
|
||||
T x(10000, hf1, eq1);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
T x(10000, hf1, eq1);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 2\n";
|
||||
UNORDERED_SUB_TEST("Construct 2")
|
||||
{
|
||||
T x(100, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
T x(100, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 3\n";
|
||||
UNORDERED_SUB_TEST("Construct 3")
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 4\n";
|
||||
UNORDERED_SUB_TEST("Construct 4")
|
||||
{
|
||||
test::random_values<T> v(5, generator);
|
||||
T x(v.begin(), v.end(), 1000, hf1);
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(5, generator);
|
||||
T x(v.begin(), v.end(), 1000, hf1);
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
|
||||
std::cerr<<"Construct 5\n";
|
||||
UNORDERED_SUB_TEST("Construct 5")
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
||||
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
||||
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 6\n";
|
||||
UNORDERED_SUB_TEST("Construct 6")
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf, eq);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf, eq);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 7\n";
|
||||
UNORDERED_SUB_TEST("Construct 7")
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf2, eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf2, eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 8 - from input iterator\n";
|
||||
UNORDERED_SUB_TEST("Construct 8 - from input iterator")
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
v_begin = v.begin(), v_end = v.end();
|
||||
T x(test::input_iterator(v_begin),
|
||||
test::input_iterator(v_end), 0, hf1, eq1);
|
||||
BOOST_DEDUCED_TYPENAME T::const_iterator
|
||||
x_begin = x.begin(), x_end = x.end();
|
||||
T y(test::input_iterator(x_begin),
|
||||
test::input_iterator(x_end), 0, hf2, eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 9\n";
|
||||
{
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(50);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.max_load_factor(10);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.insert(v.begin(), v.end());
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
typename test::random_values<T>::const_iterator v_begin = v.begin(),
|
||||
v_end = v.end();
|
||||
T x(test::input_iterator(v_begin), test::input_iterator(v_end), 0, hf1,
|
||||
eq1);
|
||||
typename T::const_iterator x_begin = x.begin(), x_end = x.end();
|
||||
T y(test::input_iterator(x_begin), test::input_iterator(x_end), 0, hf2,
|
||||
eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
std::initializer_list<BOOST_DEDUCED_TYPENAME T::value_type> list;
|
||||
|
||||
std::cerr<<"Initializer list construct 1\n";
|
||||
UNORDERED_SUB_TEST("Construct 8.5 - from copy iterator")
|
||||
{
|
||||
T x(list);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(test::copy_iterator(v.begin()), test::copy_iterator(v.end()), 0, hf1,
|
||||
eq1);
|
||||
T y(test::copy_iterator(x.begin()), test::copy_iterator(x.end()), 0, hf2,
|
||||
eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 2\n";
|
||||
UNORDERED_SUB_TEST("Construct 9")
|
||||
{
|
||||
T x(list, 1000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(50);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.max_load_factor(10);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.insert(v.begin(), v.end());
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 3\n";
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
std::initializer_list<typename T::value_type> list;
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 1")
|
||||
{
|
||||
T x(list, 10, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 4\n";
|
||||
UNORDERED_SUB_TEST("Initializer list construct 2")
|
||||
{
|
||||
T x(list, 10, hf1, eq1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 1000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 5\n";
|
||||
UNORDERED_SUB_TEST("Initializer list construct 3")
|
||||
{
|
||||
T x(list, 10, hf1, eq1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 4")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, eq1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 5")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, eq1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void map_constructor_test(T* = 0,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map_constructor_test\n";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void map_constructor_test(T*, test::random_generator const& generator)
|
||||
{
|
||||
typedef test::list<
|
||||
std::pair<
|
||||
BOOST_DEDUCED_TYPENAME T::key_type,
|
||||
BOOST_DEDUCED_TYPENAME T::mapped_type
|
||||
>
|
||||
> list;
|
||||
std::pair<typename T::key_type, typename T::mapped_type> >
|
||||
list;
|
||||
test::random_values<T> v(1000, generator);
|
||||
list l(v.begin(), v.end());
|
||||
T x(l.begin(), l.end());
|
||||
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_multimap;
|
||||
|
||||
UNORDERED_TEST(constructor_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(constructor_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(constructor_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(map_constructor_test,
|
||||
((test_map)(test_multimap))
|
||||
)
|
||||
UNORDERED_TEST(constructor_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
UNORDERED_TEST(map_constructor_test,
|
||||
((test_map_std_alloc)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_AUTO_TEST(test_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST (test_default_initializer_list) {
|
||||
std::initializer_list<int> init;
|
||||
boost::unordered_set<int> x1 = init;
|
||||
BOOST_TEST(x1.empty());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
|
||||
!defined(BOOST_NO_INITIALIZER_LISTS)
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(test_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
boost::unordered_set<int> x1 = { 2, 10, 45, -5 };
|
||||
UNORDERED_AUTO_TEST (test_initializer_list) {
|
||||
boost::unordered_set<int> x1 = {2, 10, 45, -5};
|
||||
BOOST_TEST(x1.find(10) != x1.end());
|
||||
BOOST_TEST(x1.find(46) == x1.end());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
RUN_TESTS_QUIET()
|
||||
|
@ -3,149 +3,207 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include "../objects/cxx11_allocator.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
test::seed_t seed(9063);
|
||||
test::seed_t initialize_seed(9063);
|
||||
|
||||
namespace copy_tests
|
||||
{
|
||||
namespace copy_tests {
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests1(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||
template <class T>
|
||||
void copy_construct_tests1(T*, test::random_generator const& generator)
|
||||
{
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
typename T::allocator_type al;
|
||||
|
||||
{
|
||||
T x;
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
|
||||
T x;
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(v.begin(), v.end());
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
test::random_values<T> v(1000, generator);
|
||||
|
||||
T x(v.begin(), v.end());
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
// In this test I drop the original containers max load factor, so it
|
||||
// is much lower than the load factor. The hash table is not allowed
|
||||
// to rehash, but the destination container should probably allocate
|
||||
// enough buckets to decrease the load factor appropriately.
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
x.max_load_factor(x.load_factor() / 4);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
// This isn't guaranteed:
|
||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
|
||||
// In this test I drop the original containers max load factor, so it
|
||||
// is much lower than the load factor. The hash table is not allowed
|
||||
// to rehash, but the destination container should probably allocate
|
||||
// enough buckets to decrease the load factor appropriately.
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
x.max_load_factor(x.load_factor() / 4);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
// This isn't guaranteed:
|
||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests2(T* ptr,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
copy_construct_tests1(ptr);
|
||||
template <class T>
|
||||
void copy_construct_tests2(T*, test::random_generator const& generator)
|
||||
{
|
||||
typename T::hasher hf(1);
|
||||
typename T::key_equal eq(1);
|
||||
typename T::allocator_type al(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
{
|
||||
T x(10000, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(10000, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
T x(1000, hf, eq, al);
|
||||
T y(x, al2);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(1000, hf, eq, al);
|
||||
T y(x, al2);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
test::random_values<T> v(1000, generator);
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v(500, generator);
|
||||
test::check_instances check_;
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al2);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
test::random_values<T> v(500, generator);
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al2);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_set_select_copy;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_multiset_select_copy;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_map_select_copy;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_multimap_select_copy;
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
)
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_set_no_select_copy;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_multiset_no_select_copy;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_map_no_select_copy;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_multimap_no_select_copy;
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(
|
||||
test_multiset_select_copy)(test_map_select_copy)(
|
||||
test_multimap_select_copy)(test_set_no_select_copy)(
|
||||
test_multiset_no_select_copy)(test_map_no_select_copy)(
|
||||
test_multimap_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(
|
||||
test_multiset_select_copy)(test_map_select_copy)(
|
||||
test_multimap_select_copy)(test_set_no_select_copy)(
|
||||
test_multiset_no_select_copy)(test_map_no_select_copy)(
|
||||
test_multimap_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
352
test/unordered/deduction_tests.cpp
Normal file
352
test/unordered/deduction_tests.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
|
||||
// Copyright 2017-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)
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
struct hash_equals
|
||||
{
|
||||
template <typename T> bool operator()(T const& x) const
|
||||
{
|
||||
boost::hash<T> hf;
|
||||
return hf(x);
|
||||
}
|
||||
|
||||
template <typename T> bool operator()(T const& x, T const& y) const
|
||||
{
|
||||
std::equal_to<T> eq;
|
||||
return eq(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct test_allocator
|
||||
{
|
||||
typedef T value_type;
|
||||
test_allocator() = default;
|
||||
template <typename T2> test_allocator(test_allocator<T2> const&) {}
|
||||
T* allocate(std::size_t n) const { return (T*)malloc(sizeof(T) * n); }
|
||||
void deallocate(T* ptr, std::size_t) const { free(ptr); }
|
||||
bool operator==(test_allocator const&) { return true; }
|
||||
bool operator!=(test_allocator const&) { return false; }
|
||||
};
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES: "
|
||||
<< BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES << std::endl;
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
std::vector<std::pair<int, int> > x;
|
||||
x.push_back(std::make_pair(1, 3));
|
||||
x.push_back(std::make_pair(5, 10));
|
||||
test_allocator<std::pair<const int, int> > pair_allocator;
|
||||
hash_equals f;
|
||||
|
||||
// unordered_map
|
||||
|
||||
/*
|
||||
template<class InputIterator,
|
||||
class Hash = hash<iter_key_t<InputIterator>>,
|
||||
class Pred = equal_to<iter_key_t<InputIterator>>,
|
||||
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
|
||||
unordered_map(InputIterator, InputIterator, typename see below::size_type =
|
||||
see below,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
Hash, Pred,
|
||||
Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end());
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_map<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous:
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0, std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_map<int, int, std::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class Key, class T, class Hash = hash<Key>,
|
||||
class Pred = equal_to<Key>, class Allocator = allocator<pair<const
|
||||
Key, T>>>
|
||||
unordered_map(initializer_list<pair<const Key, T>>,
|
||||
typename see below::size_type = see below, Hash = Hash(),
|
||||
Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_map<Key, T, Hash, Pred, Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1, 2)});
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_map<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>(), std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m(
|
||||
{std::pair<int const, int>(1, 2)}, 0, f, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_map<int, int, hash_equals, hash_equals,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, typename see below::size_type,
|
||||
Allocator)
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
hash<iter_key_t<InputIterator>>,
|
||||
equal_to<iter_key_t<InputIterator>>,
|
||||
Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0u, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
hash<iter_key_t<InputIterator>>,
|
||||
equal_to<iter_key_t<InputIterator>>,
|
||||
Allocator>;
|
||||
*/
|
||||
|
||||
/* No constructor:
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, typename see below::size_type,
|
||||
Hash, Allocator)
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
Hash,
|
||||
equal_to<iter_key_t<InputIterator>>, Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0u, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_map<int, int,
|
||||
hash_equals, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class Key, class T, typename Allocator>
|
||||
unordered_map(initializer_list<pair<const Key, T>>, typename see
|
||||
below::size_type,
|
||||
Allocator)
|
||||
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class Key, class T, typename Allocator>
|
||||
unordered_map(initializer_list<pair<const Key, T>>, Allocator)
|
||||
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1, 2)}, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class Key, class T, class Hash, class Allocator>
|
||||
unordered_map(initializer_list<pair<const Key, T>>, typename see
|
||||
below::size_type, Hash,
|
||||
Allocator)
|
||||
-> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0, f,
|
||||
pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
// unordered_multimap
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end());
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_multimap<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous:
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1, 2)});
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_multimap<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>(), std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(
|
||||
{std::pair<int const, int>(1, 2)}, 0, f, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_multimap<int, int, hash_equals, hash_equals,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0u, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/* No constructor:
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0u, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_multimap<int, int,
|
||||
hash_equals, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0,
|
||||
pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(
|
||||
{std::pair<int const, int>(1, 2)}, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0, f,
|
||||
pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
}
|
101
test/unordered/detail_tests.cpp
Normal file
101
test/unordered/detail_tests.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <map>
|
||||
|
||||
// Pretty inefficient, but the test is fast enough.
|
||||
// Might be too slow if we had larger primes?
|
||||
bool is_prime(std::size_t x)
|
||||
{
|
||||
if (x == 2) {
|
||||
return true;
|
||||
} else if (x == 1 || x % 2 == 0) {
|
||||
return false;
|
||||
} else {
|
||||
// y*y <= x had rounding errors, so instead use y <= (x/y).
|
||||
for (std::size_t y = 3; y <= (x / y); y += 2) {
|
||||
if (x % y == 0) {
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void test_next_prime(std::size_t value)
|
||||
{
|
||||
std::size_t x = boost::unordered::detail::next_prime(value);
|
||||
BOOST_TEST(is_prime(x));
|
||||
BOOST_TEST(x >= value);
|
||||
}
|
||||
|
||||
void test_prev_prime(std::size_t value)
|
||||
{
|
||||
std::size_t x = boost::unordered::detail::prev_prime(value);
|
||||
BOOST_TEST(is_prime(x));
|
||||
BOOST_TEST(x <= value);
|
||||
if (x > value) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x << "," << value << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (next_prime_test) {
|
||||
BOOST_TEST(!is_prime(0));
|
||||
BOOST_TEST(!is_prime(1));
|
||||
BOOST_TEST(is_prime(2));
|
||||
BOOST_TEST(is_prime(3));
|
||||
BOOST_TEST(is_prime(13));
|
||||
BOOST_TEST(!is_prime(4));
|
||||
BOOST_TEST(!is_prime(100));
|
||||
|
||||
BOOST_TEST(boost::unordered::detail::next_prime(0) > 0);
|
||||
|
||||
// test_prev_prime doesn't work for values less than 17.
|
||||
// Which should be okay, unless an allocator has a really tiny
|
||||
// max_size?
|
||||
const std::size_t min_prime = 17;
|
||||
|
||||
// test_next_prime doesn't work for values greater than this,
|
||||
// which might be a problem if you've got terrabytes of memory?
|
||||
// I seriously doubt the container would work well at such sizes
|
||||
// regardless.
|
||||
const std::size_t max_prime = 4294967291ul;
|
||||
|
||||
std::size_t i;
|
||||
|
||||
BOOST_TEST(is_prime(min_prime));
|
||||
BOOST_TEST(is_prime(max_prime));
|
||||
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
if (i < min_prime) {
|
||||
BOOST_TEST(boost::unordered::detail::prev_prime(i) == min_prime);
|
||||
} else {
|
||||
test_prev_prime(i);
|
||||
}
|
||||
test_next_prime(i);
|
||||
}
|
||||
|
||||
std::size_t last = i - 1;
|
||||
for (; i > last; last = i, i += i / 5) {
|
||||
if (i > max_prime) {
|
||||
BOOST_TEST(boost::unordered::detail::next_prime(i) == max_prime);
|
||||
} else {
|
||||
test_next_prime(i);
|
||||
}
|
||||
test_prev_prime(i);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
514
test/unordered/emplace_tests.cpp
Normal file
514
test/unordered/emplace_tests.cpp
Normal file
@ -0,0 +1,514 @@
|
||||
//
|
||||
// Copyright 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/count.hpp"
|
||||
#include <string>
|
||||
|
||||
// Test that various emplace methods work with different numbers of
|
||||
// arguments.
|
||||
|
||||
namespace emplace_tests {
|
||||
// Constructible with 2 to 10 arguments
|
||||
struct emplace_value : private test::counted_object
|
||||
{
|
||||
typedef int A0;
|
||||
typedef std::string A1;
|
||||
typedef char A2;
|
||||
typedef int A3;
|
||||
typedef int A4;
|
||||
typedef int A5;
|
||||
typedef int A6;
|
||||
typedef int A7;
|
||||
typedef int A8;
|
||||
typedef int A9;
|
||||
|
||||
int arg_count;
|
||||
|
||||
A0 a0;
|
||||
A1 a1;
|
||||
A2 a2;
|
||||
A3 a3;
|
||||
A4 a4;
|
||||
A5 a5;
|
||||
A6 a6;
|
||||
A7 a7;
|
||||
A8 a8;
|
||||
A9 a9;
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1) : arg_count(2), a0(b0), a1(b1) {}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2)
|
||||
: arg_count(3), a0(b0), a1(b1), a2(b2)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3)
|
||||
: arg_count(4), a0(b0), a1(b1), a2(b2), a3(b3)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(
|
||||
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3, A4 const& b4)
|
||||
: arg_count(5), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5)
|
||||
: arg_count(6), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6)
|
||||
: arg_count(7), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7)
|
||||
: arg_count(8), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6),
|
||||
a7(b7)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7, A8 const& b8)
|
||||
: arg_count(9), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6),
|
||||
a7(b7), a8(b8)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7, A8 const& b8,
|
||||
A9 const& b9)
|
||||
: arg_count(10), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6),
|
||||
a7(b7), a8(b8), a9(b9)
|
||||
{
|
||||
}
|
||||
|
||||
friend std::size_t hash_value(emplace_value const& x)
|
||||
{
|
||||
std::size_t r1 = 23894278u;
|
||||
if (x.arg_count >= 1)
|
||||
boost::hash_combine(r1, x.a0);
|
||||
if (x.arg_count >= 2)
|
||||
boost::hash_combine(r1, x.a1);
|
||||
if (x.arg_count >= 3)
|
||||
boost::hash_combine(r1, x.a2);
|
||||
if (x.arg_count >= 4)
|
||||
boost::hash_combine(r1, x.a3);
|
||||
if (x.arg_count >= 5)
|
||||
boost::hash_combine(r1, x.a4);
|
||||
if (x.arg_count >= 6)
|
||||
boost::hash_combine(r1, x.a5);
|
||||
if (x.arg_count >= 7)
|
||||
boost::hash_combine(r1, x.a6);
|
||||
if (x.arg_count >= 8)
|
||||
boost::hash_combine(r1, x.a7);
|
||||
if (x.arg_count >= 9)
|
||||
boost::hash_combine(r1, x.a8);
|
||||
if (x.arg_count >= 10)
|
||||
boost::hash_combine(r1, x.a9);
|
||||
return r1;
|
||||
}
|
||||
|
||||
friend bool operator==(emplace_value const& x, emplace_value const& y)
|
||||
{
|
||||
if (x.arg_count != y.arg_count) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 1 && x.a0 != y.a0) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 2 && x.a1 != y.a1) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 3 && x.a2 != y.a2) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 4 && x.a3 != y.a3) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 5 && x.a4 != y.a4) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 6 && x.a5 != y.a5) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 7 && x.a6 != y.a6) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 8 && x.a7 != y.a7) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 9 && x.a8 != y.a8) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 10 && x.a9 != y.a9) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
emplace_value();
|
||||
emplace_value(emplace_value const&);
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_set) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_set<emplace_value, boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
iterator i1;
|
||||
return_type r1, r2;
|
||||
|
||||
// 2 args
|
||||
|
||||
emplace_value v1(10, "x");
|
||||
r1 = x.emplace(10, std::string("x"));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(*r1.first == v1);
|
||||
BOOST_TEST(r1.first == x.find(v1));
|
||||
BOOST_TEST_EQ(check_.instances(), 2);
|
||||
BOOST_TEST_EQ(check_.constructions(), 2);
|
||||
|
||||
// 3 args
|
||||
|
||||
emplace_value v2(3, "foo", 'a');
|
||||
r1 = x.emplace(3, "foo", 'a');
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(*r1.first == v2);
|
||||
BOOST_TEST(r1.first == x.find(v2));
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
// 7 args with hint + duplicate
|
||||
|
||||
emplace_value v3(25, "something", 'z', 4, 5, 6, 7);
|
||||
i1 = x.emplace_hint(r1.first, 25, "something", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(*i1 == v3);
|
||||
BOOST_TEST(i1 == x.find(v3));
|
||||
BOOST_TEST_EQ(check_.instances(), 6);
|
||||
BOOST_TEST_EQ(check_.constructions(), 6);
|
||||
|
||||
r2 = x.emplace(25, "something", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(!r2.second);
|
||||
BOOST_TEST(i1 == r2.first);
|
||||
// The container has to construct an object in order to check
|
||||
// whether it can emplace, so there's an extra cosntruction
|
||||
// here.
|
||||
BOOST_TEST_EQ(check_.instances(), 6);
|
||||
BOOST_TEST_EQ(check_.constructions(), 7);
|
||||
|
||||
// 10 args + hint duplicate
|
||||
|
||||
std::string s1;
|
||||
emplace_value v4(10, s1, 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
r1 = x.emplace(10, s1, 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
BOOST_TEST_EQ(x.size(), 4u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(*r1.first == v4);
|
||||
BOOST_TEST(r1.first == x.find(v4));
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 9);
|
||||
|
||||
BOOST_TEST(
|
||||
r1.first == x.emplace_hint(r1.first, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST(
|
||||
r1.first == x.emplace_hint(r2.first, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST(
|
||||
r1.first == x.emplace_hint(x.end(), 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 12);
|
||||
|
||||
BOOST_TEST_EQ(x.size(), 4u);
|
||||
BOOST_TEST(x.count(v1) == 1);
|
||||
BOOST_TEST(x.count(v2) == 1);
|
||||
BOOST_TEST(x.count(v3) == 1);
|
||||
BOOST_TEST(x.count(v4) == 1);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_multiset) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_multiset<emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
container x(10);
|
||||
iterator i1, i2;
|
||||
|
||||
// 2 args.
|
||||
|
||||
emplace_value v1(10, "x");
|
||||
i1 = x.emplace(10, std::string("x"));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(i1 == x.find(v1));
|
||||
BOOST_TEST_EQ(check_.instances(), 2);
|
||||
BOOST_TEST_EQ(check_.constructions(), 2);
|
||||
|
||||
// 4 args + duplicate
|
||||
|
||||
emplace_value v2(4, "foo", 'a', 15);
|
||||
i1 = x.emplace(4, "foo", 'a', 15);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(i1 == x.find(v2));
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
i2 = x.emplace(4, "foo", 'a', 15);
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(*i1 == *i2);
|
||||
BOOST_TEST(x.count(*i1) == 2);
|
||||
BOOST_TEST_EQ(check_.instances(), 5);
|
||||
BOOST_TEST_EQ(check_.constructions(), 5);
|
||||
|
||||
// 7 args + duplicate using hint.
|
||||
|
||||
emplace_value v3(7, "", 'z', 4, 5, 6, 7);
|
||||
i1 = x.emplace(7, "", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 4u);
|
||||
BOOST_TEST_EQ(i1->a2, 'z');
|
||||
BOOST_TEST(x.count(*i1) == 1);
|
||||
BOOST_TEST(i1 == x.find(v3));
|
||||
BOOST_TEST_EQ(check_.instances(), 7);
|
||||
BOOST_TEST_EQ(check_.constructions(), 7);
|
||||
|
||||
i2 = x.emplace_hint(i1, 7, "", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 5u);
|
||||
BOOST_TEST(*i1 == *i2);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(x.count(*i1) == 2);
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 8);
|
||||
|
||||
// 10 args with bad hint + duplicate
|
||||
|
||||
emplace_value v4(10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
i1 = x.emplace_hint(i2, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
BOOST_TEST_EQ(x.size(), 6u);
|
||||
BOOST_TEST_EQ(i1->arg_count, 10);
|
||||
BOOST_TEST(i1 == x.find(v4));
|
||||
BOOST_TEST_EQ(check_.instances(), 10);
|
||||
BOOST_TEST_EQ(check_.constructions(), 10);
|
||||
|
||||
i2 = x.emplace_hint(x.end(), 10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
BOOST_TEST_EQ(x.size(), 7u);
|
||||
BOOST_TEST(*i1 == *i2);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(x.count(*i1) == 2);
|
||||
BOOST_TEST_EQ(check_.instances(), 11);
|
||||
BOOST_TEST_EQ(check_.constructions(), 11);
|
||||
|
||||
BOOST_TEST_EQ(x.count(v1), 1u);
|
||||
BOOST_TEST_EQ(x.count(v2), 2u);
|
||||
BOOST_TEST_EQ(x.count(v3), 2u);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_map) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_map<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
return_type r1, r2;
|
||||
|
||||
// 5/8 args + duplicate
|
||||
|
||||
emplace_value k1(5, "", 'b', 4, 5);
|
||||
emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8);
|
||||
r1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(x.find(k1) == r1.first);
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
r2 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(!r2.second);
|
||||
BOOST_TEST(r1.first == r2.first);
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
// constructions could possibly be 5 if the implementation only
|
||||
// constructed the key.
|
||||
BOOST_TEST_EQ(check_.constructions(), 6);
|
||||
|
||||
// 9/3 args + duplicates with hints, different mapped value.
|
||||
|
||||
emplace_value k2(9, "", 'b', 4, 5, 6, 7, 8, 9);
|
||||
emplace_value m2(3, "aaa", 'm');
|
||||
r1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(3, "aaa", 'm'));
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(r1.first->first.arg_count == 9);
|
||||
BOOST_TEST(r1.first->second.arg_count == 3);
|
||||
BOOST_TEST(x.find(k2) == r1.first);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 10);
|
||||
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(r1.first, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(15, "jkjk")));
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(r2.first, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(275, "xxx", 'm', 6)));
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(x.end(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(-10, "blah blah", '\0')));
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 16);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_multimap) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_multimap<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
container x(10);
|
||||
iterator i1, i2, i3, i4;
|
||||
|
||||
// 5/8 args + duplicate
|
||||
|
||||
emplace_value k1(5, "", 'b', 4, 5);
|
||||
emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8);
|
||||
i1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(x.find(k1) == i1);
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
emplace_value m1a(8, "xxx", 'z', 4, 5, 6, 7, 8);
|
||||
i2 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(i1->second == m1);
|
||||
BOOST_TEST(i2->second == m1a);
|
||||
BOOST_TEST_EQ(check_.instances(), 7);
|
||||
BOOST_TEST_EQ(check_.constructions(), 7);
|
||||
|
||||
// 9/3 args + duplicates with hints, different mapped value.
|
||||
|
||||
emplace_value k2(9, "", 'b', 4, 5, 6, 7, 8, 9);
|
||||
emplace_value m2(3, "aaa", 'm');
|
||||
i1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(3, "aaa", 'm'));
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(i1->first.arg_count == 9);
|
||||
BOOST_TEST(i1->second.arg_count == 3);
|
||||
BOOST_TEST_EQ(check_.instances(), 11);
|
||||
BOOST_TEST_EQ(check_.constructions(), 11);
|
||||
|
||||
emplace_value m2a(15, "jkjk");
|
||||
i2 = x.emplace_hint(i2, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(15, "jkjk"));
|
||||
emplace_value m2b(275, "xxx", 'm', 6);
|
||||
i3 = x.emplace_hint(i1, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(275, "xxx", 'm', 6));
|
||||
emplace_value m2c(-10, "blah blah", '\0');
|
||||
i4 = x.emplace_hint(x.end(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(-10, "blah blah", '\0'));
|
||||
BOOST_TEST_EQ(x.size(), 6u);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
BOOST_TEST_EQ(check_.instances(), 20);
|
||||
BOOST_TEST_EQ(check_.constructions(), 20);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (try_emplace) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_map<int, emplace_value> container;
|
||||
typedef container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
return_type r1, r2, r3;
|
||||
|
||||
int k1 = 3;
|
||||
emplace_value m1(414, "grr");
|
||||
r1 = x.try_emplace(3, 414, "grr");
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(r1.first->first == k1);
|
||||
BOOST_TEST(r1.first->second == m1);
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST_EQ(check_.instances(), 2);
|
||||
BOOST_TEST_EQ(check_.constructions(), 2);
|
||||
|
||||
int k2 = 10;
|
||||
emplace_value m2(25, "", 'z');
|
||||
r2 = x.try_emplace(10, 25, std::string(""), 'z');
|
||||
BOOST_TEST(r2.second);
|
||||
BOOST_TEST(r2.first->first == k2);
|
||||
BOOST_TEST(r2.first->second == m2);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
|
||||
r3 = x.try_emplace(k2, 68, "jfeoj", 'p', 49309, 2323);
|
||||
BOOST_TEST(!r3.second);
|
||||
BOOST_TEST(r3.first == r2.first);
|
||||
BOOST_TEST(r3.first->second == m2);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
BOOST_TEST(r2.first == x.try_emplace(r2.first, k2, 808709, "what"));
|
||||
BOOST_TEST(
|
||||
r2.first ==
|
||||
x.try_emplace(r2.first, k2, 10, "xxx", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST(r2.first->second == m2);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
@ -3,169 +3,154 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <boost/preprocessor/seq.hpp>
|
||||
#include <list>
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
namespace equality_tests
|
||||
{
|
||||
struct mod_compare
|
||||
namespace equality_tests {
|
||||
struct mod_compare
|
||||
{
|
||||
bool alt_hash_;
|
||||
|
||||
explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {}
|
||||
|
||||
bool operator()(int x, int y) const { return x % 1000 == y % 1000; }
|
||||
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
bool alt_hash_;
|
||||
|
||||
explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {}
|
||||
|
||||
bool operator()(int x, int y) const
|
||||
{
|
||||
return x % 1000 == y % 1000;
|
||||
}
|
||||
|
||||
int operator()(int x) const
|
||||
{
|
||||
return alt_hash_ ? x % 250 : (x + 5) % 250;
|
||||
}
|
||||
};
|
||||
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_set<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
return alt_hash_ ? static_cast<std::size_t>(x % 250)
|
||||
: static_cast<std::size_t>((x + 5) % 250);
|
||||
}
|
||||
};
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multiset<int, mod_compare, mod_compare> \
|
||||
set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_set<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_map<int, int, mod_compare, mod_compare> \
|
||||
map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multiset<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multimap<int, int, mod_compare, mod_compare> \
|
||||
map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_map<int, int, mod_compare, mod_compare> map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multimap<int, int, mod_compare, mod_compare> map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_SET_INSERT(r, set, item) set.insert(item);
|
||||
#define UNORDERED_MAP_INSERT(r, map, item) \
|
||||
map.insert(std::pair<int const, int> BOOST_PP_SEQ_TO_TUPLE(item));
|
||||
#define UNORDERED_MAP_INSERT(r, map, item) \
|
||||
map.insert(std::pair<int const, int> BOOST_PP_SEQ_TO_TUPLE(item));
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_size_tests)
|
||||
{
|
||||
boost::unordered_set<int> x1, x2;
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
UNORDERED_AUTO_TEST (equality_size_tests) {
|
||||
boost::unordered_set<int> x1, x2;
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x1.insert(1);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
|
||||
x2.insert(1);
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x2.insert(2);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_key_value_tests)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2))
|
||||
UNORDERED_EQUALITY_SET_TEST((2), ==, (2))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_collision_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1), !=, (501))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(251), !=, (1)(501))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((251)(1))((1)(1)), !=, ((501)(1))((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(501), ==, (1)(501))
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1)(501), ==, (501)(1))
|
||||
}
|
||||
x1.insert(1);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_group_size_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(10)(20)(20), !=, (10)(10)(20))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((10)(1))((20)(1))((20)(1)), !=,
|
||||
((10)(1))((20)(1))((10)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((20)(1))((10)(1))((10)(1)), ==,
|
||||
((10)(1))((20)(1))((10)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_map_value_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), ==, ((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(2))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||
}
|
||||
x2.insert(1);
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_predicate_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1), ==, (1001))
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1)))
|
||||
}
|
||||
x2.insert(2);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
}
|
||||
|
||||
// Test that equality still works when the two containers have
|
||||
// different hash functions but the same equality predicate.
|
||||
UNORDERED_AUTO_TEST (equality_key_value_tests) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2))
|
||||
UNORDERED_EQUALITY_SET_TEST((2), ==, (2))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_different_hash_test)
|
||||
{
|
||||
typedef boost::unordered_set<int, mod_compare, mod_compare> set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(1); set2.insert(2);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(2); set2.insert(1);
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(10); set2.insert(20);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(20); set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
}
|
||||
UNORDERED_AUTO_TEST (equality_collision_test) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (501))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1)(251), !=, (1)(501))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((251)(1))((1)(1)), !=, ((501)(1))((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1)(501), ==, (1)(501))
|
||||
UNORDERED_EQUALITY_SET_TEST((1)(501), ==, (501)(1))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_group_size_test) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((10)(20)(20), !=, (10)(10)(20))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((10)(1))((20)(1))((20)(1)), !=, ((10)(1))((20)(1))((10)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((20)(1))((10)(1))((10)(1)), ==, ((10)(1))((20)(1))((10)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_map_value_test) {
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1)), ==, ((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(2))((1)(1)), ==, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(2))((1)(1)), !=, ((1)(1))((1)(3)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_predicate_test) {
|
||||
UNORDERED_EQUALITY_SET_TEST((1), !=, (1001))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_multiple_group_test) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(1)(1)(1001)(2001)(2001)(2)(1002)(3)(1003)(2003), ==,
|
||||
(3)(1003)(2003)(1002)(2)(2001)(2001)(1)(1001)(1)(1))
|
||||
}
|
||||
|
||||
// Test that equality still works when the two containers have
|
||||
// different hash functions but the same equality predicate.
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_different_hash_test) {
|
||||
typedef boost::unordered_set<int, mod_compare, mod_compare> set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(1);
|
||||
set2.insert(2);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(2);
|
||||
set2.insert(1);
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(10);
|
||||
set2.insert(20);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(20);
|
||||
set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,10 +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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
@ -14,71 +17,61 @@
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template <class Container, class Iterator>
|
||||
void test_equal_insertion(Iterator begin, Iterator end)
|
||||
{
|
||||
typedef test::ordered<Container> tracker;
|
||||
typedef test::ordered<Container> tracker;
|
||||
|
||||
Container x1;
|
||||
tracker x2 = test::create_ordered(x1);
|
||||
Container x1;
|
||||
tracker x2 = test::create_ordered(x1);
|
||||
|
||||
for(Iterator it = begin; it != end; ++it) {
|
||||
x1.insert(*it);
|
||||
x2.insert(*it);
|
||||
x2.compare_key(x1, *it);
|
||||
}
|
||||
for (Iterator it = begin; it != end; ++it) {
|
||||
x1.insert(*it);
|
||||
x2.insert(*it);
|
||||
x2.compare_key(x1, *it);
|
||||
}
|
||||
|
||||
x2.compare(x1);
|
||||
test::check_equivalent_keys(x1);
|
||||
x2.compare(x1);
|
||||
test::check_equivalent_keys(x1);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(set_tests)
|
||||
{
|
||||
int values[][5] = {
|
||||
{1},
|
||||
{54, 23},
|
||||
{-13, 65},
|
||||
{77, 77},
|
||||
{986, 25, 986}
|
||||
};
|
||||
UNORDERED_AUTO_TEST (set_tests) {
|
||||
int values[][5] = {{1}, {54, 23}, {-13, 65}, {77, 77}, {986, 25, 986}};
|
||||
|
||||
typedef boost::unordered_set<int> set;
|
||||
typedef boost::unordered_multiset<int> multiset;
|
||||
typedef boost::unordered_set<int> set;
|
||||
typedef boost::unordered_multiset<int> multiset;
|
||||
|
||||
test_equal_insertion<set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<set>(values[1], values[1] + 2);
|
||||
test_equal_insertion<set>(values[2], values[2] + 2);
|
||||
test_equal_insertion<set>(values[3], values[3] + 2);
|
||||
test_equal_insertion<set>(values[4], values[4] + 3);
|
||||
test_equal_insertion<set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<set>(values[1], values[1] + 2);
|
||||
test_equal_insertion<set>(values[2], values[2] + 2);
|
||||
test_equal_insertion<set>(values[3], values[3] + 2);
|
||||
test_equal_insertion<set>(values[4], values[4] + 3);
|
||||
|
||||
test_equal_insertion<multiset>(values[0], values[0] + 1);
|
||||
test_equal_insertion<multiset>(values[1], values[1] + 2);
|
||||
test_equal_insertion<multiset>(values[2], values[2] + 2);
|
||||
test_equal_insertion<multiset>(values[3], values[3] + 2);
|
||||
test_equal_insertion<multiset>(values[4], values[4] + 3);
|
||||
test_equal_insertion<multiset>(values[0], values[0] + 1);
|
||||
test_equal_insertion<multiset>(values[1], values[1] + 2);
|
||||
test_equal_insertion<multiset>(values[2], values[2] + 2);
|
||||
test_equal_insertion<multiset>(values[3], values[3] + 2);
|
||||
test_equal_insertion<multiset>(values[4], values[4] + 3);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(map_tests)
|
||||
{
|
||||
typedef test::list<std::pair<int const, int> > values_type;
|
||||
values_type v[5];
|
||||
v[0].push_back(std::pair<int const, int>(1,1));
|
||||
v[1].push_back(std::pair<int const, int>(28,34));
|
||||
v[1].push_back(std::pair<int const, int>(16,58));
|
||||
v[1].push_back(std::pair<int const, int>(-124, 62));
|
||||
v[2].push_back(std::pair<int const, int>(432,12));
|
||||
v[2].push_back(std::pair<int const, int>(9,13));
|
||||
v[2].push_back(std::pair<int const, int>(432,24));
|
||||
UNORDERED_AUTO_TEST (map_tests) {
|
||||
typedef test::list<std::pair<int const, int> > values_type;
|
||||
values_type v[5];
|
||||
v[0].push_back(std::pair<int const, int>(1, 1));
|
||||
v[1].push_back(std::pair<int const, int>(28, 34));
|
||||
v[1].push_back(std::pair<int const, int>(16, 58));
|
||||
v[1].push_back(std::pair<int const, int>(-124, 62));
|
||||
v[2].push_back(std::pair<int const, int>(432, 12));
|
||||
v[2].push_back(std::pair<int const, int>(9, 13));
|
||||
v[2].push_back(std::pair<int const, int>(432, 24));
|
||||
|
||||
for(int i = 0; i < 5; ++i)
|
||||
test_equal_insertion<boost::unordered_map<int, int> >(
|
||||
v[i].begin(), v[i].end());
|
||||
for (int i = 0; i < 5; ++i)
|
||||
test_equal_insertion<boost::unordered_map<int, int> >(
|
||||
v[i].begin(), v[i].end());
|
||||
|
||||
for(int i2 = 0; i2 < 5; ++i2)
|
||||
test_equal_insertion<boost::unordered_multimap<int, int> >(
|
||||
v[i2].begin(), v[i2].end());
|
||||
for (int i2 = 0; i2 < 5; ++i2)
|
||||
test_equal_insertion<boost::unordered_multimap<int, int> >(
|
||||
v[i2].begin(), v[i2].end());
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -6,188 +6,212 @@
|
||||
// The code for erasing elements from containers with equivalent keys is very
|
||||
// hairy with several tricky edge cases - so explicitly test each one.
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/list.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <boost/next_prior.hpp>
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#endif
|
||||
|
||||
struct write_pair_type
|
||||
{
|
||||
template <class X1, class X2>
|
||||
void operator()(std::pair<X1, X2> const& x) const
|
||||
{
|
||||
std::cout<<"("<<x.first<<","<<x.second<<")";
|
||||
}
|
||||
template <class X1, class X2>
|
||||
void operator()(std::pair<X1, X2> const& x) const
|
||||
{
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "(" << x.first << "," << x.second << ")";
|
||||
}
|
||||
} write_pair;
|
||||
|
||||
template <class Container>
|
||||
void write_container(Container const& x)
|
||||
template <class Container> void write_container(Container const& x)
|
||||
{
|
||||
std::for_each(x.begin(), x.end(), write_pair);
|
||||
std::cout<<"\n";
|
||||
std::for_each(x.begin(), x.end(), write_pair);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
// Make everything collide - for testing erase in a single bucket.
|
||||
struct collision_hash
|
||||
{
|
||||
int operator()(int) const { return 0; }
|
||||
std::size_t operator()(int) const { return 0; }
|
||||
};
|
||||
|
||||
// For testing erase in 2 buckets.
|
||||
struct collision2_hash
|
||||
{
|
||||
int operator()(int x) const { return x & 1; }
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
return static_cast<std::size_t>(x & 1);
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision_hash, std::equal_to<int>,
|
||||
test::allocator<std::pair<int const, int> > > collide_map;
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision2_hash, std::equal_to<int>,
|
||||
test::allocator<std::pair<int const, int> > > collide_map2;
|
||||
// For testing erase in lots of buckets.
|
||||
struct collision3_hash
|
||||
{
|
||||
std::size_t operator()(int x) const { return static_cast<std::size_t>(x); }
|
||||
};
|
||||
|
||||
typedef boost::unordered_multimap<int, int, collision_hash, std::equal_to<int>,
|
||||
test::allocator1<std::pair<int const, int> > >
|
||||
collide_map;
|
||||
typedef boost::unordered_multimap<int, int, collision2_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > >
|
||||
collide_map2;
|
||||
typedef boost::unordered_multimap<int, int, collision3_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > >
|
||||
collide_map3;
|
||||
typedef collide_map::value_type collide_value;
|
||||
typedef test::list<collide_value> collide_list;
|
||||
|
||||
UNORDERED_AUTO_TEST(empty_range_tests)
|
||||
{
|
||||
collide_map x;
|
||||
x.erase(x.begin(), x.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
x.erase(x.end(), x.end());
|
||||
UNORDERED_AUTO_TEST (empty_range_tests) {
|
||||
collide_map x;
|
||||
x.erase(x.begin(), x.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
x.erase(x.end(), x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(single_item_tests)
|
||||
{
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1,1));
|
||||
UNORDERED_AUTO_TEST (single_item_tests) {
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1, 1));
|
||||
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.end(), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (two_equivalent_item_tests) {
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1, 1));
|
||||
init.push_back(collide_value(1, 2));
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
x.erase(x.end(), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
{
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1,1));
|
||||
init.push_back(collide_value(1,2));
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = test::next(x.begin())->second;
|
||||
x.erase(x.begin(), test::next(x.begin()));
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 &&
|
||||
x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = boost::next(x.begin())->second;
|
||||
x.erase(x.begin(), boost::next(x.begin()));
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
}
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = x.begin()->second;
|
||||
x.erase(boost::next(x.begin()), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
}
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = x.begin()->second;
|
||||
x.erase(test::next(x.begin()), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 &&
|
||||
x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
// More automated tests...
|
||||
|
||||
template<class Range1, class Range2>
|
||||
template <class Range1, class Range2>
|
||||
bool compare(Range1 const& x, Range2 const& y)
|
||||
{
|
||||
collide_list a(x.begin(), x.end());
|
||||
collide_list b(y.begin(), y.end());
|
||||
a.sort();
|
||||
b.sort();
|
||||
return a == b;
|
||||
collide_list a(x.begin(), x.end());
|
||||
collide_list b(y.begin(), y.end());
|
||||
a.sort();
|
||||
b.sort();
|
||||
return a == b;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
bool general_erase_range_test(Container& x, std::size_t start, std::size_t end)
|
||||
{
|
||||
collide_list l(x.begin(), x.end());
|
||||
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));
|
||||
x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end));
|
||||
return compare(l, x);
|
||||
collide_list l(x.begin(), x.end());
|
||||
|
||||
l.erase(test::next(l.begin(), start), test::next(l.begin(), end));
|
||||
x.erase(test::next(x.begin(), start), test::next(x.begin(), end));
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
return compare(l, x);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void erase_subrange_tests(Container const& x)
|
||||
template <class Container> void erase_subrange_tests(Container const& x)
|
||||
{
|
||||
for(std::size_t length = 0; length < x.size(); ++length) {
|
||||
for(std::size_t position = 0; position < x.size() - length; ++position)
|
||||
{
|
||||
Container y(x);
|
||||
collide_list init(y.begin(), y.end());
|
||||
if(!general_erase_range_test(y, position, position + length)) {
|
||||
BOOST_ERROR("general_erase_range_test failed.");
|
||||
std::cout<<"Erase: ["<<position<<","<<position + length<<")\n";
|
||||
write_container(init);
|
||||
write_container(y);
|
||||
}
|
||||
}
|
||||
for (std::size_t length = 0; length < x.size(); ++length) {
|
||||
for (std::size_t position = 0; position < x.size() - length; ++position) {
|
||||
Container y(x);
|
||||
collide_list init(y.begin(), y.end());
|
||||
if (!general_erase_range_test(y, position, position + length)) {
|
||||
BOOST_ERROR("general_erase_range_test failed.");
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase: [" << position << ","
|
||||
<< position + length << ")\n";
|
||||
write_container(init);
|
||||
write_container(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void x_by_y_erase_range_tests(Container*, int values, int duplicates)
|
||||
{
|
||||
Container y;
|
||||
Container y;
|
||||
|
||||
for(int i = 0; i < values; ++i) {
|
||||
for(int j = 0; j < duplicates; ++j) {
|
||||
y.insert(collide_value(i, j));
|
||||
}
|
||||
for (int i = 0; i < values; ++i) {
|
||||
for (int j = 0; j < duplicates; ++j) {
|
||||
y.insert(collide_value(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout<<"Values: "<<values<<", Duplicates: "<<duplicates<<"\n";
|
||||
erase_subrange_tests(y);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Values: " << values
|
||||
<< ", Duplicates: " << duplicates << "\n";
|
||||
erase_subrange_tests(y);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void exhaustive_erase_tests(Container* x, int num_values,
|
||||
int num_duplicated)
|
||||
void exhaustive_erase_tests(Container* x, int num_values, int num_duplicated)
|
||||
{
|
||||
for(int i = 0; i < num_values; ++i) {
|
||||
for(int j = 0; j < num_duplicated; ++j) {
|
||||
x_by_y_erase_range_tests(x, i, j);
|
||||
}
|
||||
for (int i = 0; i < num_values; ++i) {
|
||||
for (int j = 0; j < num_duplicated; ++j) {
|
||||
x_by_y_erase_range_tests(x, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(exhaustive_collide_tests)
|
||||
{
|
||||
std::cout<<"exhaustive_collide_tests:\n";
|
||||
collide_map m;
|
||||
exhaustive_erase_tests((collide_map*) 0, 4, 4);
|
||||
std::cout<<"\n";
|
||||
UNORDERED_AUTO_TEST (exhaustive_collide_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide_tests:\n";
|
||||
collide_map m;
|
||||
exhaustive_erase_tests((collide_map*)0, 4, 4);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(exhaustive_collide2_tests)
|
||||
{
|
||||
std::cout<<"exhaustive_collide2_tests:\n";
|
||||
exhaustive_erase_tests((collide_map2*) 0, 8, 4);
|
||||
std::cout<<"\n";
|
||||
UNORDERED_AUTO_TEST (exhaustive_collide2_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide2_tests:\n";
|
||||
exhaustive_erase_tests((collide_map2*)0, 8, 4);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (exhaustive_collide3_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide3_tests:\n";
|
||||
exhaustive_erase_tests((collide_map3*)0, 8, 4);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,203 +3,265 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <boost/next_prior.hpp>
|
||||
#include "../objects/test.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <iostream>
|
||||
namespace erase_tests {
|
||||
|
||||
namespace erase_tests
|
||||
{
|
||||
test::seed_t initialize_seed(85638);
|
||||
|
||||
test::seed_t seed(85638);
|
||||
template <class Container>
|
||||
void erase_tests1(Container*, test::random_generator generator)
|
||||
{
|
||||
typedef typename Container::iterator iterator;
|
||||
typedef typename Container::const_iterator c_iterator;
|
||||
|
||||
template <class Container>
|
||||
void erase_tests1(Container*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"Erase by key.\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase by key.\n";
|
||||
{
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator
|
||||
it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
std::size_t count = x.count(test::get_key<Container>(*it));
|
||||
std::size_t old_size = x.size();
|
||||
BOOST_TEST(count == x.erase(test::get_key<Container>(*it)));
|
||||
BOOST_TEST(x.size() == old_size - count);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == 0);
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
}
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
int iterations = 0;
|
||||
for (typename test::random_values<Container>::iterator it = v.begin();
|
||||
it != v.end(); ++it) {
|
||||
std::size_t count = x.count(test::get_key<Container>(*it));
|
||||
std::size_t old_size = x.size();
|
||||
BOOST_TEST(count == x.erase(test::get_key<Container>(*it)));
|
||||
BOOST_TEST(x.size() == old_size - count);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == 0);
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr<<"erase(begin()).\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(begin()).\n";
|
||||
{
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_DEDUCED_TYPENAME Container::iterator
|
||||
pos = x.erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(pos == x.begin());
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
test::check_instances check_;
|
||||
|
||||
std::cerr<<"erase(random position).\n";
|
||||
{
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
int index = rand() % (int) x.size();
|
||||
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
|
||||
if(index == 0) {
|
||||
prev = pos = x.begin();
|
||||
}
|
||||
else {
|
||||
prev = boost::next(x.begin(), index - 1);
|
||||
pos = boost::next(prev);
|
||||
}
|
||||
next = boost::next(pos);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_TEST(next == x.erase(pos));
|
||||
--size;
|
||||
if(size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() :
|
||||
next == boost::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"erase(ranges).\n";
|
||||
{
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
|
||||
std::size_t size = x.size();
|
||||
|
||||
// I'm actually stretching it a little here, as the standard says it
|
||||
// returns 'the iterator immediately following the erase elements'
|
||||
// and if nothing is erased, then there's nothing to follow. But I
|
||||
// think this is the only sensible option...
|
||||
BOOST_TEST(x.erase(x.end(), x.end()) == x.end());
|
||||
BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin());
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
typename Container::key_type key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
iterator pos = x.erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(pos == x.begin());
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"erase_return_void(begin()).\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
std::size_t index = test::random_value(x.size());
|
||||
c_iterator prev, pos, next;
|
||||
if (index == 0) {
|
||||
prev = pos = x.begin();
|
||||
} else {
|
||||
prev = test::next(x.begin(), index - 1);
|
||||
pos = test::next(prev);
|
||||
}
|
||||
next = test::next(pos);
|
||||
typename Container::key_type key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_TEST(count > 0);
|
||||
BOOST_TEST(next == x.erase(pos));
|
||||
--size;
|
||||
if (size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
if (x.count(key) != count - 1) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => " << x.count(key)
|
||||
<< std::endl;
|
||||
}
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(ranges).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
|
||||
std::size_t size = x.size();
|
||||
|
||||
// I'm actually stretching it a little here, as the standard says it
|
||||
// returns 'the iterator immediately following the erase elements'
|
||||
// and if nothing is erased, then there's nothing to follow. But I
|
||||
// think this is the only sensible option...
|
||||
BOOST_TEST(x.erase(x.end(), x.end()) == x.end());
|
||||
BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin());
|
||||
BOOST_TEST(x.size() == size);
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random ranges).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
Container x;
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
x.erase_return_void(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
x.insert(v.begin(), v.end());
|
||||
|
||||
// Note that erase only invalidates the erased iterators.
|
||||
std::vector<c_iterator> iterators;
|
||||
for (c_iterator it = x.cbegin(); it != x.cend(); ++it) {
|
||||
iterators.push_back(it);
|
||||
}
|
||||
iterators.push_back(x.cend());
|
||||
|
||||
while (iterators.size() > 1) {
|
||||
std::size_t start = test::random_value(iterators.size());
|
||||
std::size_t length = test::random_value(iterators.size() - start);
|
||||
x.erase(iterators[start], iterators[start + length]);
|
||||
iterators.erase(test::next(iterators.begin(), start),
|
||||
test::next(iterators.begin(), start + length));
|
||||
|
||||
BOOST_TEST(x.size() == iterators.size() - 1);
|
||||
typename std::vector<c_iterator>::const_iterator i2 =
|
||||
iterators.begin();
|
||||
for (c_iterator i1 = x.cbegin(); i1 != x.cend(); ++i1) {
|
||||
BOOST_TEST(i1 == *i2);
|
||||
++i2;
|
||||
}
|
||||
BOOST_TEST(x.cend() == *i2);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr<<"erase_return_void(random position).\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(begin()).\n";
|
||||
{
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
int index = rand() % (int) x.size();
|
||||
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
|
||||
if(index == 0) {
|
||||
prev = pos = x.begin();
|
||||
}
|
||||
else {
|
||||
prev = boost::next(x.begin(), index - 1);
|
||||
pos = boost::next(prev);
|
||||
}
|
||||
next = boost::next(pos);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
x.erase_return_void(pos);
|
||||
--size;
|
||||
if(size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() :
|
||||
next == boost::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
typename Container::key_type key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
x.quick_erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
std::size_t index = test::random_value(x.size());
|
||||
typename Container::const_iterator prev, pos, next;
|
||||
if (index == 0) {
|
||||
prev = pos = x.begin();
|
||||
} else {
|
||||
prev = test::next(x.begin(), index - 1);
|
||||
pos = test::next(prev);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
next = test::next(pos);
|
||||
typename Container::key_type key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_TEST(count > 0);
|
||||
x.quick_erase(pos);
|
||||
--size;
|
||||
if (size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
if (x.count(key) != count - 1) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => " << x.count(key)
|
||||
<< std::endl;
|
||||
}
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
|
||||
std::cerr<<"clear().\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "clear().\n";
|
||||
{
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
x.clear();
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
x.clear();
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
}
|
||||
|
||||
std::cerr<<"\n";
|
||||
}
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(erase_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(
|
||||
erase_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
133
test/unordered/extract_tests.cpp
Normal file
133
test/unordered/extract_tests.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
// Copyright 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
namespace extract_tests {
|
||||
|
||||
test::seed_t initialize_seed(85638);
|
||||
|
||||
template <class Container>
|
||||
void extract_tests1(Container*, test::random_generator generator)
|
||||
{
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Extract by key.\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
int iterations = 0;
|
||||
for (typename test::random_values<Container>::iterator it = v.begin();
|
||||
it != v.end(); ++it) {
|
||||
std::size_t count = x.count(test::get_key<Container>(*it));
|
||||
std::size_t old_size = x.size();
|
||||
std::size_t new_count = count ? count - 1 : count;
|
||||
std::size_t new_size = count ? old_size - 1 : old_size;
|
||||
typename Container::node_type n =
|
||||
x.extract(test::get_key<Container>(*it));
|
||||
BOOST_TEST((n ? true : false) == (count ? true : false));
|
||||
BOOST_TEST(x.size() == new_size);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == new_count);
|
||||
if (!new_count) {
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
} else {
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) != x.end());
|
||||
}
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(begin()).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
typename Container::key_type key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
typename Container::node_type n = x.extract(x.begin());
|
||||
BOOST_TEST(n);
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
using namespace std;
|
||||
int index = rand() % (int)x.size();
|
||||
typename Container::const_iterator prev, pos, next;
|
||||
if (index == 0) {
|
||||
prev = pos = x.begin();
|
||||
} else {
|
||||
prev = test::next(x.begin(), index - 1);
|
||||
pos = test::next(prev);
|
||||
}
|
||||
next = test::next(pos);
|
||||
typename Container::key_type key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
typename Container::node_type n = x.extract(pos);
|
||||
BOOST_TEST(n);
|
||||
--size;
|
||||
if (size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(
|
||||
extract_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
@ -3,163 +3,155 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
|
||||
namespace find_tests
|
||||
{
|
||||
namespace find_tests {
|
||||
|
||||
test::seed_t seed(78937);
|
||||
test::seed_t initialize_seed(78937);
|
||||
|
||||
template <class X>
|
||||
void find_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
template <class X> void find_tests1(X*, test::random_generator generator)
|
||||
{
|
||||
typedef typename X::iterator iterator;
|
||||
|
||||
{
|
||||
test::random_values<X> v(500, generator);
|
||||
X x(v.begin(), v.end());
|
||||
X const& x_const = x;
|
||||
test::ordered<X> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
test::check_instances check_;
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::ordered<X>::const_iterator it1 =
|
||||
tracker.begin(); it1 != tracker.end(); ++it1)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it1);
|
||||
iterator pos = x.find(key);
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator
|
||||
const_pos = x_const.find(key);
|
||||
BOOST_TEST(pos != x.end() &&
|
||||
x.key_eq()(key, test::get_key<X>(*pos)));
|
||||
BOOST_TEST(const_pos != x_const.end() &&
|
||||
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
|
||||
test::random_values<X> v(500, generator);
|
||||
X x(v.begin(), v.end());
|
||||
X const& x_const = x;
|
||||
test::ordered<X> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
BOOST_TEST(x.count(key) == tracker.count(key));
|
||||
for (typename test::ordered<X>::const_iterator it1 = tracker.begin();
|
||||
it1 != tracker.end(); ++it1) {
|
||||
typename X::key_type key = test::get_key<X>(*it1);
|
||||
typename X::const_iterator const_pos = x_const.find(key);
|
||||
iterator pos = x.find(key);
|
||||
BOOST_TEST(const_pos != x_const.end());
|
||||
BOOST_TEST(const_pos != x_const.end() &&
|
||||
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
|
||||
BOOST_TEST(pos != x.end());
|
||||
BOOST_TEST(pos != x.end() && x.key_eq()(key, test::get_key<X>(*pos)));
|
||||
|
||||
test::compare_pairs(x.equal_range(key),
|
||||
tracker.equal_range(key),
|
||||
(BOOST_DEDUCED_TYPENAME X::value_type*) 0);
|
||||
test::compare_pairs(x_const.equal_range(key),
|
||||
tracker.equal_range(key),
|
||||
(BOOST_DEDUCED_TYPENAME X::value_type*) 0);
|
||||
}
|
||||
|
||||
test::random_values<X> v2(500, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator it2 =
|
||||
v2.begin(); it2 != v2.end(); ++it2)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it2);
|
||||
if(tracker.find(test::get_key<X>(key)) == tracker.end())
|
||||
{
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x_const.find(key) == x_const.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
BOOST_TEST(x.count(key) == tracker.count(key));
|
||||
|
||||
test::compare_pairs(x.equal_range(key), tracker.equal_range(key),
|
||||
(typename X::value_type*)0);
|
||||
test::compare_pairs(x_const.equal_range(key), tracker.equal_range(key),
|
||||
(typename X::value_type*)0);
|
||||
}
|
||||
|
||||
test::random_values<X> v2(500, generator);
|
||||
for (typename test::random_values<X>::const_iterator it2 = v2.begin();
|
||||
it2 != v2.end(); ++it2) {
|
||||
typename X::key_type key = test::get_key<X>(*it2);
|
||||
if (tracker.find(test::get_key<X>(key)) == tracker.end()) {
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x_const.find(key) == x_const.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
X x;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<X> v2(5, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator it3 =
|
||||
v2.begin(); it3 != v2.end(); ++it3)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it3);
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
X x;
|
||||
|
||||
test::random_values<X> v2(5, generator);
|
||||
for (typename test::random_values<X>::const_iterator it3 = v2.begin();
|
||||
it3 != v2.end(); ++it3) {
|
||||
typename X::key_type key = test::get_key<X>(*it3);
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct compatible_key
|
||||
{
|
||||
struct compatible_key
|
||||
{
|
||||
test::object o_;
|
||||
|
||||
compatible_key(test::object const& o) : o_(o) {}
|
||||
};
|
||||
|
||||
struct compatible_hash
|
||||
{
|
||||
compatible_key(test::object const& o) : o_(o) {}
|
||||
};
|
||||
|
||||
struct compatible_hash
|
||||
{
|
||||
test::hash hash_;
|
||||
|
||||
std::size_t operator()(compatible_key const& k) const {
|
||||
return hash_(k.o_);
|
||||
std::size_t operator()(compatible_key const& k) const
|
||||
{
|
||||
return hash_(k.o_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct compatible_predicate
|
||||
{
|
||||
struct compatible_predicate
|
||||
{
|
||||
test::equal_to equal_;
|
||||
|
||||
bool operator()(compatible_key const& k1, compatible_key const& k2) const {
|
||||
return equal_(k1.o_, k2.o_);
|
||||
bool operator()(compatible_key const& k1, compatible_key const& k2) const
|
||||
{
|
||||
return equal_(k1.o_, k2.o_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <class X>
|
||||
void find_compatible_keys_test(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
value_iterator;
|
||||
template <class X>
|
||||
void find_compatible_keys_test(X*, test::random_generator generator)
|
||||
{
|
||||
typedef typename test::random_values<X>::iterator value_iterator;
|
||||
test::random_values<X> v(500, generator);
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
|
||||
compatible_hash h;
|
||||
compatible_predicate eq;
|
||||
|
||||
for(value_iterator it = v.begin(), end = v.end(); it != end; ++it) {
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
|
||||
for (value_iterator it = v.begin(), end = v.end(); it != end; ++it) {
|
||||
typename X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
}
|
||||
|
||||
test::random_values<X> v2(20, generator);
|
||||
|
||||
for(value_iterator it = v2.begin(), end = v2.end(); it != end; ++it) {
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
|
||||
for (value_iterator it = v2.begin(), end = v2.end(); it != end; ++it) {
|
||||
typename X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(find_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(find_compatible_keys_test,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(
|
||||
find_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(find_compatible_keys_test,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,62 +3,79 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
typedef boost::unordered_map<int, int> int_map;
|
||||
|
||||
void call_swap(int_map& x, int_map& y) {
|
||||
swap(x,y);
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y)
|
||||
{
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
bool call_equals(int_map& x, int_map& y) {
|
||||
return x == y;
|
||||
template <typename T>
|
||||
bool call_equals(boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_map& x, int_map& y) {
|
||||
return x != y;
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y)
|
||||
{
|
||||
return x != y;
|
||||
}
|
||||
|
||||
typedef boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
void call_swap(int_multimap& x, int_multimap& y) {
|
||||
swap(x,y);
|
||||
template <typename T>
|
||||
void call_swap(
|
||||
boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y)
|
||||
{
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
bool call_equals(int_multimap& x, int_multimap& y) {
|
||||
return x == y;
|
||||
template <typename T>
|
||||
bool call_equals(
|
||||
boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_multimap& x, int_multimap& y) {
|
||||
return x != y;
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y)
|
||||
{
|
||||
return x != y;
|
||||
}
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
UNORDERED_AUTO_TEST(use_map_fwd_declared_function) {
|
||||
int_map x, y;
|
||||
x[1] = 2;
|
||||
y[2] = 1;
|
||||
call_swap(x, y);
|
||||
typedef boost::unordered_map<int, int> int_map;
|
||||
typedef boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end() && y.find(1)->second == 2);
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
UNORDERED_AUTO_TEST (use_map_fwd_declared_function) {
|
||||
int_map x, y;
|
||||
x[1] = 2;
|
||||
y[2] = 1;
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == 1);
|
||||
BOOST_TEST(y.find(1) != y.end() && y.find(1)->second == 2);
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == 1);
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_multimap_fwd_declared_function) {
|
||||
int_multimap x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
UNORDERED_AUTO_TEST (use_multimap_fwd_declared_function) {
|
||||
int_multimap x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,85 +3,104 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
|
||||
#include <boost/unordered/unordered_set_fwd.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
struct true_type { char x[100]; };
|
||||
struct false_type { char x; };
|
||||
struct true_type
|
||||
{
|
||||
char x[100];
|
||||
};
|
||||
struct false_type
|
||||
{
|
||||
char x;
|
||||
};
|
||||
|
||||
false_type is_unordered_set_impl(void*);
|
||||
|
||||
template <class Value, class Hash, class Pred, class Alloc>
|
||||
true_type is_unordered_set_impl(
|
||||
boost::unordered_set<Value, Hash, Pred, Alloc>*);
|
||||
boost::unordered_set<Value, Hash, Pred, Alloc>*);
|
||||
|
||||
typedef boost::unordered_set<int> int_set;
|
||||
|
||||
void call_swap(int_set& x, int_set& y) {
|
||||
swap(x,y);
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_set<T>& x, boost::unordered_set<T>& y)
|
||||
{
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
bool call_equals(int_set& x, int_set& y) {
|
||||
return x == y;
|
||||
template <typename T>
|
||||
bool call_equals(boost::unordered_set<T>& x, boost::unordered_set<T>& y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_set& x, int_set& y) {
|
||||
return x != y;
|
||||
template <typename T>
|
||||
bool call_not_equals(boost::unordered_set<T>& x, boost::unordered_set<T>& y)
|
||||
{
|
||||
return x != y;
|
||||
}
|
||||
|
||||
typedef boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
void call_swap(int_multiset& x, int_multiset& y) {
|
||||
swap(x,y);
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y)
|
||||
{
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
bool call_equals(int_multiset& x, int_multiset& y) {
|
||||
return x == y;
|
||||
template <typename T>
|
||||
bool call_equals(
|
||||
boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
bool call_not_equals(int_multiset& x, int_multiset& y) {
|
||||
return x != y;
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y)
|
||||
{
|
||||
return x != y;
|
||||
}
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) {
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0))
|
||||
== sizeof(true_type));
|
||||
typedef boost::unordered_set<int> int_set;
|
||||
typedef boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
UNORDERED_AUTO_TEST (use_fwd_declared_trait_without_definition) {
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*)0)) == sizeof(true_type));
|
||||
}
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
UNORDERED_AUTO_TEST(use_fwd_declared_trait) {
|
||||
boost::unordered_set<int> x;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type));
|
||||
UNORDERED_AUTO_TEST (use_fwd_declared_trait) {
|
||||
boost::unordered_set<int> x;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type));
|
||||
|
||||
int dummy;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&dummy)) == sizeof(false_type));
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int*)0)) == sizeof(false_type));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_set_fwd_declared_function) {
|
||||
int_set x, y;
|
||||
x.insert(1);
|
||||
y.insert(2);
|
||||
call_swap(x, y);
|
||||
UNORDERED_AUTO_TEST (use_set_fwd_declared_function) {
|
||||
int_set x, y;
|
||||
x.insert(1);
|
||||
y.insert(2);
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end());
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
BOOST_TEST(y.find(1) != y.end());
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end());
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end());
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_multiset_fwd_declared_function) {
|
||||
int_multiset x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
UNORDERED_AUTO_TEST (use_multiset_fwd_declared_function) {
|
||||
int_multiset x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user