Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51d47fb3f4 | ||
|
|
cfd4829da5 | ||
|
|
64f60542ac | ||
|
|
a757f3737b | ||
|
|
26ab9ff584 | ||
|
|
1e92d9f545 | ||
|
|
2cf72093b1 | ||
|
|
88d4d64edf | ||
|
|
7f7e577e77 | ||
|
|
80d7203d78 | ||
|
|
5dfed4deec | ||
|
|
e08f9f11a1 | ||
|
|
c304284773 | ||
|
|
0e8affcc07 | ||
|
|
ba00dbd65a | ||
|
|
c214fb44a3 | ||
|
|
c704788718 | ||
|
|
a91efeb237 | ||
|
|
7812b26d3a | ||
|
|
8bd07e17c3 | ||
|
|
b3c0368ab5 | ||
|
|
37edc392a5 | ||
|
|
fb403bc233 | ||
|
|
910b8de697 | ||
|
|
3aff995ae0 | ||
|
|
68c018fda6 | ||
|
|
a9ad06139e | ||
|
|
9a0e5e9ea8 | ||
|
|
b1a52d0236 | ||
|
|
1723358298 | ||
|
|
6bf0e93a41 | ||
|
|
0e5ef25a69 | ||
|
|
ab84a922cf | ||
|
|
d8bc38f154 | ||
|
|
ecd4a82ed5 | ||
|
|
0898219edc | ||
|
|
d9b62d24dc | ||
|
|
b771278813 | ||
|
|
2226a7238d | ||
|
|
00c6a93a56 | ||
|
|
8ea1cbbd64 | ||
|
|
81a47ca88d | ||
|
|
c54151769f | ||
|
|
e73d5ecdd1 | ||
|
|
8a4e987030 | ||
|
|
8544d9f3c8 | ||
|
|
ed80cb14e2 | ||
|
|
91eb2ddbd1 | ||
|
|
3bd28dc3d7 | ||
|
|
e4d2da40f2 | ||
|
|
a004e71dd0 | ||
|
|
ddcab1c171 | ||
|
|
e3cbf03f47 | ||
|
|
f8fbbc3b76 | ||
|
|
52bf2bf7a2 | ||
|
|
cf39fc4c38 | ||
|
|
1309361a02 | ||
|
|
946491489e | ||
|
|
19202d2a8d | ||
|
|
3be466966d | ||
|
|
d22787c218 | ||
|
|
b86dee9a18 | ||
|
|
863984a7c8 | ||
|
|
e9b3ad4a5f | ||
|
|
e00d700457 | ||
|
|
53e20a2a1b | ||
|
|
af4cdf8fab | ||
|
|
7003e91d44 | ||
|
|
e86bb5cce2 | ||
|
|
6a4728add0 | ||
|
|
f02afbc815 | ||
|
|
6399dfd1e4 | ||
|
|
f468fb77e0 | ||
|
|
5e316ebc88 | ||
|
|
0c90585511 | ||
|
|
13b4fd7133 | ||
|
|
27b4c62bd2 | ||
|
|
846de7ca82 | ||
|
|
62cf58d1ca | ||
|
|
4482031329 | ||
|
|
7b1af37b9c | ||
|
|
1c48f665ea | ||
|
|
e4072747bb | ||
|
|
ce674c8007 | ||
|
|
45ebc1e555 | ||
|
|
02c3bd4072 | ||
|
|
5f4172c13f | ||
|
|
40c5c6907a | ||
|
|
8dbe380d6c | ||
|
|
37ff9de0db | ||
|
|
ae9f35073b | ||
|
|
a85df27d4c | ||
|
|
88c70b885d | ||
|
|
240f5f94b1 | ||
|
|
7415721f7d | ||
|
|
8b5539756b | ||
|
|
49ac1035bb | ||
|
|
d085c40541 | ||
|
|
99d5b9b1bb | ||
|
|
ad86f9211b | ||
|
|
d9515fdc2f | ||
|
|
eedbc6bcf7 | ||
|
|
297fb2e8c4 | ||
|
|
99eab2dfb1 | ||
|
|
1070c9b69e | ||
|
|
9e6b5a7e43 | ||
|
|
e1f11e840c | ||
|
|
f2d4f1968b | ||
|
|
4a7116b996 | ||
|
|
41584e73d9 | ||
|
|
52453cb5a4 | ||
|
|
44b918896d | ||
|
|
ff356ac083 | ||
|
|
3064801a89 | ||
|
|
e9d9f19e76 | ||
|
|
9b85c38e37 | ||
|
|
0b2829c793 | ||
|
|
a9c2d1daa5 | ||
|
|
d29815b3a8 | ||
|
|
7ed7878278 | ||
|
|
4c927cd2f2 | ||
|
|
2fae05ed31 | ||
|
|
41abb96d83 | ||
|
|
63f51e7c41 | ||
|
|
ba4f321934 | ||
|
|
68563fab72 | ||
|
|
d8e9503869 | ||
|
|
86e998cbc7 | ||
|
|
ce722e4d56 | ||
|
|
77eaab4803 | ||
|
|
96562f4c3b | ||
|
|
d66ceaf7fe | ||
|
|
2e44769247 | ||
|
|
e64fd45760 | ||
|
|
454fc7501e | ||
|
|
a89c62728a | ||
|
|
1d8c0f91f8 | ||
|
|
25ba8e4dfc | ||
|
|
fb4437219f | ||
|
|
0d1fdae84c | ||
|
|
c5debf11cf | ||
|
|
9e4f89aa43 | ||
|
|
12935eb695 | ||
|
|
2386188d69 | ||
|
|
e4b32f7f5e | ||
|
|
3df435d4d3 | ||
|
|
ed076facc4 | ||
|
|
b09c5bdcf0 | ||
|
|
6abb94bb68 | ||
|
|
d2b1f095c8 | ||
|
|
3d34571654 | ||
|
|
d683b3ac3e | ||
|
|
e16a8737f4 | ||
|
|
8f348aea26 | ||
|
|
9a8ba2bdff | ||
|
|
3aaefdcc78 | ||
|
|
ca59ed8c50 | ||
|
|
ff78ef25c0 | ||
|
|
ec487b5c6c | ||
|
|
0a03ed8170 | ||
|
|
5881dcc2b2 | ||
|
|
2070cbe2cc | ||
|
|
8198b9c57c | ||
|
|
c35e9fc631 | ||
|
|
f244ba55de | ||
|
|
5e225fe46c | ||
|
|
06535e518e | ||
|
|
81584c22cf | ||
|
|
83040211e8 | ||
|
|
4ed301df97 | ||
|
|
8010f506a6 | ||
|
|
840ea1ce5c | ||
|
|
447306bfb9 | ||
|
|
4569c1bec0 | ||
|
|
37ad547e18 | ||
|
|
e037ee8d82 | ||
|
|
9bbadfdb34 | ||
|
|
c1b63f68c8 | ||
|
|
0590e3bf8c | ||
|
|
8f17f5f548 | ||
|
|
3a8bea9e1d | ||
|
|
b33b354818 | ||
|
|
b08837b93e | ||
|
|
b3b840df30 | ||
|
|
2ef47f0813 | ||
|
|
27f5513911 | ||
|
|
a5100a9d35 | ||
|
|
ccbc639677 | ||
|
|
18725a682d | ||
|
|
dac1135199 | ||
|
|
ead55a8938 | ||
|
|
8f39001ff0 | ||
|
|
8b056b902e | ||
|
|
5724adbbe9 | ||
|
|
1c5640cfbe | ||
|
|
4d982e133e | ||
|
|
1bf193b8fc | ||
|
|
7faec20f26 | ||
|
|
ced8b45add | ||
|
|
15c9bc40f7 | ||
|
|
9aedb95296 | ||
|
|
e56cb4418c | ||
|
|
1ae21c6d1a | ||
|
|
82acad3794 | ||
|
|
c50461528c | ||
|
|
bd08e49255 | ||
|
|
dbba3cec7b | ||
|
|
6c5b5b3186 | ||
|
|
47dd02a4b3 | ||
|
|
8429d1a6aa | ||
|
|
86d3f9f632 | ||
|
|
48e92afd92 | ||
|
|
5a5c31de35 | ||
|
|
088941dc7b | ||
|
|
5f6f1691e5 | ||
|
|
45d6c07be6 | ||
|
|
5c63cd2bdb | ||
|
|
86318c1e88 | ||
|
|
0ff1fa0f6e | ||
|
|
d90bf0c438 | ||
|
|
dc63438e22 | ||
|
|
0a3ac26f00 | ||
|
|
c64ed1caa3 | ||
|
|
efc33b18be | ||
|
|
c189d8d5e8 | ||
|
|
886227db3b | ||
|
|
719eb90d03 | ||
|
|
fadb686bc5 | ||
|
|
aebefaef0d | ||
|
|
63a564e8ff | ||
|
|
16c1593368 | ||
|
|
53580a3070 | ||
|
|
d26aeed68f | ||
|
|
73eefd2b5d | ||
|
|
3df600d069 | ||
|
|
a1adacdfe2 | ||
|
|
f405fa9118 | ||
|
|
7b5d6e7c29 | ||
|
|
7d0ba7178e | ||
|
|
df5e2c3aca | ||
|
|
343e344582 | ||
|
|
34ed463bea | ||
|
|
5986f75d16 | ||
|
|
b08810c0c4 | ||
|
|
7c608ae7bc | ||
|
|
d51cee35d5 | ||
|
|
d0289b4c7b | ||
|
|
bc7ba9cb3b | ||
|
|
6b10c8a4d3 | ||
|
|
b9805c7309 | ||
|
|
844460fd22 | ||
|
|
a600278d27 | ||
|
|
4398ffe8c9 | ||
|
|
eed1eeedeb | ||
|
|
8c0c230f78 | ||
|
|
e96ec1e79a | ||
|
|
be7dd51fab | ||
|
|
4dec95840b | ||
|
|
d44fb36581 | ||
|
|
9d3bbe27db | ||
|
|
13ed4afc95 | ||
|
|
b3f54e74a7 | ||
|
|
d6374e2718 | ||
|
|
74156b6b06 | ||
|
|
965048d3e6 | ||
|
|
36dfe6b98b | ||
|
|
e4e89bdbde | ||
|
|
85a9d8d81d | ||
|
|
b21ad13bbb | ||
|
|
f0d10308e3 | ||
|
|
f240e587cb | ||
|
|
2a7dc9e40e | ||
|
|
99b8d0063b | ||
|
|
c6aff9278a | ||
|
|
129497133e | ||
|
|
eaa9ff0cec | ||
|
|
fa735864a3 | ||
|
|
0ce180e19b | ||
|
|
e578b7eee3 | ||
|
|
1844695b0c | ||
|
|
54b9adbdbc | ||
|
|
8b71656cd7 | ||
|
|
a858ef5688 | ||
|
|
18395c8d21 | ||
|
|
e68ec5c9a9 | ||
|
|
d3b264345d | ||
|
|
f1e1733c06 | ||
|
|
66ffbdb881 | ||
|
|
f7f5466ed2 | ||
|
|
83410fcabe | ||
|
|
1ee91d494d | ||
|
|
e8fe550d6c | ||
|
|
5b0fe7f655 | ||
|
|
ba439437bf | ||
|
|
aa6eef135e | ||
|
|
1dd085daaa | ||
|
|
2a8f50bcb7 | ||
|
|
866c58a879 | ||
|
|
c9a75a56c2 | ||
|
|
e1861aa3d9 | ||
|
|
242c7cb93a | ||
|
|
0597463902 | ||
|
|
14d80725eb | ||
|
|
a74962bc3c | ||
|
|
cafa1f2278 | ||
|
|
40d5097d99 | ||
|
|
958aea3a61 | ||
|
|
6846eb53fd | ||
|
|
3b3ba7d6f7 | ||
|
|
22135bd845 | ||
|
|
141550f585 | ||
|
|
d750b39e1e | ||
|
|
055587acf4 | ||
|
|
0f8dd003a3 | ||
|
|
9bc471310e | ||
|
|
e56aac2e98 | ||
|
|
09a3275357 | ||
|
|
a3c1e643dc | ||
|
|
955f94350b | ||
|
|
1955e4f36a | ||
|
|
644295db3a | ||
|
|
0391b6dafc | ||
|
|
c646f3e3ca | ||
|
|
0e9523a0a4 | ||
|
|
24d8449831 | ||
|
|
59d0accce0 | ||
|
|
61aedca940 | ||
|
|
3fb516367f | ||
|
|
7d77f1d478 | ||
|
|
7572de875c | ||
|
|
63d907cde7 | ||
|
|
f0037d336d | ||
|
|
8b14b7cddc | ||
|
|
6c60524fb7 | ||
|
|
8b1dcd3da3 | ||
|
|
0e980577b0 | ||
|
|
1f4244ec27 | ||
|
|
dfbff823a9 | ||
|
|
b85e17085f | ||
|
|
0a879c1063 | ||
|
|
01d508b6af | ||
|
|
7709950111 | ||
|
|
1ede59e662 | ||
|
|
bf2b521789 | ||
|
|
ee1515189b | ||
|
|
eb33ad3e3f | ||
|
|
0ad6ccb0b9 | ||
|
|
0ab4e12502 | ||
|
|
c8910e8007 | ||
|
|
2043f98593 | ||
|
|
260b573d8d | ||
|
|
4ac3dcc90c | ||
|
|
75ea43823e | ||
|
|
b1d43d3ca5 | ||
|
|
534170a942 | ||
|
|
7befee3bd6 | ||
|
|
01deb2fd61 | ||
|
|
91eddbabe8 | ||
|
|
47e205487d | ||
|
|
2c1c99407e | ||
|
|
6be2bf89b6 | ||
|
|
5eda445db0 | ||
|
|
63f07daa88 | ||
|
|
7040c57750 | ||
|
|
9716731864 | ||
|
|
0bcd46a485 | ||
|
|
46a2cd109f | ||
|
|
808f8e659a | ||
|
|
8ed05de91c | ||
|
|
1a02fca5c4 | ||
|
|
d036994237 | ||
|
|
8d4816eac7 | ||
|
|
46fc4f9f4d | ||
|
|
725993ab95 | ||
|
|
ffa5e6f805 | ||
|
|
84206ebf8f | ||
|
|
0398afae9b | ||
|
|
79dc3bb6d4 | ||
|
|
879de5fab8 | ||
|
|
89ccb49165 | ||
|
|
70a980a980 | ||
|
|
c895dd7192 | ||
|
|
ea71597053 | ||
|
|
324fa793fd | ||
|
|
39d53a0bfc | ||
|
|
20ea4a77a7 | ||
|
|
53a897008a | ||
|
|
ee8f2b991f | ||
|
|
5aff5b943f | ||
|
|
108d4535e0 | ||
|
|
2102031b93 | ||
|
|
5b92827b68 | ||
|
|
e2f4303319 | ||
|
|
c37081b4a2 | ||
|
|
fd48672fd1 | ||
|
|
530437c21b | ||
|
|
2949b37490 | ||
|
|
867e60113b | ||
|
|
551456c0c5 | ||
|
|
7857582ea2 | ||
|
|
1d99854979 | ||
|
|
e482947b20 | ||
|
|
5a4071d4f0 | ||
|
|
c30e93544d | ||
|
|
99bd9d9d31 | ||
|
|
4310809025 | ||
|
|
0d8c02ba0e | ||
|
|
d3985f87b3 | ||
|
|
3e4546465b | ||
|
|
79379a4049 | ||
|
|
71b860d6ae | ||
|
|
7c0a826815 | ||
|
|
a7156026b3 | ||
|
|
787b1a9887 | ||
|
|
6e6ad354dd | ||
|
|
4bbaa0f710 | ||
|
|
a3ef272a9e | ||
|
|
189e551dc7 | ||
|
|
fdd5fe3b40 | ||
|
|
a0652c2eda | ||
|
|
13e065466a | ||
|
|
300f5554e5 | ||
|
|
d3914d7101 | ||
|
|
3b592a3dd4 | ||
|
|
2068cf8d5b | ||
|
|
097f4fac0b | ||
|
|
5327fec080 | ||
|
|
8f02e43ba4 | ||
|
|
d0fc14b8c5 | ||
|
|
56b3700683 | ||
|
|
cf643fad2a | ||
|
|
5386033e67 | ||
|
|
d1e565dbf3 | ||
|
|
acf8ddc4b7 | ||
|
|
575e5eafb0 | ||
|
|
bce031f42b | ||
|
|
5e5addd82d | ||
|
|
0937f6443c | ||
|
|
90f2f0f67d | ||
|
|
772e1e7fa0 | ||
|
|
120fe90934 | ||
|
|
1dc949b2b5 | ||
|
|
4593d733a2 | ||
|
|
5e639a97a4 | ||
|
|
fb315252b3 | ||
|
|
d12ed06c3d | ||
|
|
49fc08b934 | ||
|
|
4f0edf9013 | ||
|
|
2afd1c5c9a | ||
|
|
492df9c9c6 | ||
|
|
e29bf7a4a0 | ||
|
|
7db310f6d2 | ||
|
|
1f781a407e | ||
|
|
ef54c6bd14 | ||
|
|
fb1b1dfe2d | ||
|
|
222f0a737d | ||
|
|
6c0d121e5b | ||
|
|
955dab4637 | ||
|
|
375d7157b6 | ||
|
|
01053738eb | ||
|
|
b75cd48899 | ||
|
|
d8f226d429 | ||
|
|
627ffe4ed7 | ||
|
|
2adab2be61 | ||
|
|
e0b680ac29 | ||
|
|
ad1e3a49a5 | ||
|
|
1d15067ef2 | ||
|
|
8a3e5dd918 | ||
|
|
2aa62c63c1 | ||
|
|
c9d1b6009e | ||
|
|
1d553447a0 | ||
|
|
703f8d1065 | ||
|
|
fe32f153a2 | ||
|
|
59f4da0a47 | ||
|
|
99ad45ed77 | ||
|
|
d93875a65e | ||
|
|
c1d5902911 | ||
|
|
0ac4aeca50 | ||
|
|
776935f24d | ||
|
|
2f048ea6ac | ||
|
|
f3353c9be3 | ||
|
|
3d07c33efe | ||
|
|
8a1562cc78 | ||
|
|
4de1be8911 | ||
|
|
46065065be | ||
|
|
8e42367a62 | ||
|
|
d13a9dcaaf | ||
|
|
64cb43ce32 | ||
|
|
c9340390b0 | ||
|
|
c76f44a8b3 | ||
|
|
2290375515 | ||
|
|
a200af610f | ||
|
|
2cb1d2bdf0 | ||
|
|
ac2bc8d615 | ||
|
|
0d6ebb4d2f | ||
|
|
27c386d47b | ||
|
|
cf6f4023bb | ||
|
|
aa41ab4195 | ||
|
|
6e4e5ead03 | ||
|
|
eb5351b2c6 | ||
|
|
599dee204f | ||
|
|
6b1d2f13da | ||
|
|
b0f6bb128f | ||
|
|
0389e0bc16 | ||
|
|
9246c30178 | ||
|
|
bb6b57d1a4 | ||
|
|
4fa61b98eb | ||
|
|
5535faf3cc | ||
|
|
ec389cdecd | ||
|
|
7c5bad60c6 | ||
|
|
cc75360f4c | ||
|
|
3a0b752363 | ||
|
|
63eaed843f | ||
|
|
0b575dc983 | ||
|
|
b8d4df2b5c | ||
|
|
3bf28d7b61 | ||
|
|
acc7f0ce5c | ||
|
|
1532e301d1 | ||
|
|
e663812f24 | ||
|
|
9da61e9050 | ||
|
|
1de8801c08 | ||
|
|
e16537d244 | ||
|
|
14c190223c | ||
|
|
e3c91ad812 | ||
|
|
454cb24cc8 | ||
|
|
5e24f6ef22 | ||
|
|
d02d4094e6 | ||
|
|
9a03d1e904 | ||
|
|
3683b43242 | ||
|
|
fc5c8c3669 | ||
|
|
df32d79e8a | ||
|
|
aefb5dd66a | ||
|
|
f85e04ef31 | ||
|
|
8c58ffe546 | ||
|
|
d538f6184c | ||
|
|
7339f4264a | ||
|
|
87674d000b | ||
|
|
6227ae49a7 | ||
|
|
c39ed8a5cf | ||
|
|
d4f7939aae | ||
|
|
fc7b5573c1 | ||
|
|
1c14bc1215 | ||
|
|
4399e8b360 | ||
|
|
3f9bd00f01 | ||
|
|
05b3025c0e | ||
|
|
becd166e66 | ||
|
|
006f62047b | ||
|
|
334dcb91ac | ||
|
|
df7792040c | ||
|
|
57ea45cb8f | ||
|
|
4a8d687778 | ||
|
|
ccd40d0c44 | ||
|
|
35118b5a71 | ||
|
|
858737fd88 | ||
|
|
648fb7b99d | ||
|
|
59c84cb744 | ||
|
|
becd6078b3 | ||
|
|
e163aa465c | ||
|
|
3b1f635926 | ||
|
|
7abd7bb36d | ||
|
|
545ad4f7ad | ||
|
|
c42d86ac0d | ||
|
|
316eeea983 | ||
|
|
f2afbe9f85 | ||
|
|
e9a94cb62a | ||
|
|
91f5925c41 | ||
|
|
0bdfa3c39e | ||
|
|
09f0b7c0a8 | ||
|
|
72bca09429 | ||
|
|
58b78f8ff0 | ||
|
|
1ff2dc4042 | ||
|
|
05f9668597 | ||
|
|
c7836659d1 | ||
|
|
c4cc805063 | ||
|
|
9e2bf3681f | ||
|
|
77f265a678 | ||
|
|
6bda467942 | ||
|
|
1fa2e84774 | ||
|
|
7caab66011 | ||
|
|
69aff6f776 | ||
|
|
505a08cf95 | ||
|
|
f776ffa008 | ||
|
|
a4c38c02c8 | ||
|
|
889a81f034 | ||
|
|
ad96ea632e | ||
|
|
2955a966cf | ||
|
|
3fbaf21b8c | ||
|
|
32a7ed74e8 | ||
|
|
3913fce638 | ||
|
|
16f86b0770 | ||
|
|
2907083b73 | ||
|
|
1fa823d815 | ||
|
|
6e8e2112ba | ||
|
|
9560d10771 | ||
|
|
e543818e3e | ||
|
|
e0bb258b39 | ||
|
|
d3ef0b9a4f | ||
|
|
86d623a0f4 | ||
|
|
b964fa777c | ||
|
|
cde017f791 | ||
|
|
d1982a664b | ||
|
|
7e479d62dc | ||
|
|
6be32f3ba4 | ||
|
|
049a1ec8f6 | ||
|
|
b3754b10c8 | ||
|
|
7441be730e | ||
|
|
38f9cb750a | ||
|
|
8a9aab57c0 | ||
|
|
b61ec3a65a | ||
|
|
74c2ae627a | ||
|
|
74ca1e50f3 | ||
|
|
5fc929b829 | ||
|
|
3aaf895514 | ||
|
|
2057ccaeb5 | ||
|
|
dc7b8f3ff2 | ||
|
|
2b7e9d826d | ||
|
|
c57470e0d3 | ||
|
|
6b1379a992 | ||
|
|
f1eb5d2106 | ||
|
|
ad248ab76a | ||
|
|
f4888c7940 | ||
|
|
d02b12c9a1 | ||
|
|
2cf9d5ac4c | ||
|
|
f3803fc071 | ||
|
|
a3c6235f3a | ||
|
|
7501eefd87 | ||
|
|
2134116cbc | ||
|
|
b86143de46 | ||
|
|
7c8045aab5 | ||
|
|
c15bd0092d | ||
|
|
d233d83811 | ||
|
|
df0c375541 | ||
|
|
886b1b4ded | ||
|
|
48816135df | ||
|
|
4d0f698937 | ||
|
|
fdbc79d2a8 | ||
|
|
1a89b0aa14 | ||
|
|
8e9b7cf259 | ||
|
|
bf6643844b | ||
|
|
e9c3ed1531 | ||
|
|
7dfcdc6da8 | ||
|
|
9ad7096851 | ||
|
|
4cdfb2537a | ||
|
|
9280e13697 | ||
|
|
21872edf83 | ||
|
|
b7e021ffc6 | ||
|
|
e69bb3aece | ||
|
|
06512a00e1 | ||
|
|
bdfe294e61 | ||
|
|
ddb9f370af | ||
|
|
b0c0384401 | ||
|
|
bf6e381ff2 | ||
|
|
d5fcc77579 | ||
|
|
b0097982af | ||
|
|
2e3a8a0fc0 | ||
|
|
357eed44a1 | ||
|
|
2ae70cd05c | ||
|
|
d370ae1095 | ||
|
|
5c48ad9a79 | ||
|
|
621b5b4ec1 | ||
|
|
4dbc83ccbf | ||
|
|
398a64b5e0 | ||
|
|
b926dbbbe9 | ||
|
|
b244b33402 | ||
|
|
f2e4b25615 | ||
|
|
29f2f1db2c | ||
|
|
cec09e1c61 | ||
|
|
36a42116e8 | ||
|
|
d9dcaf8ba1 | ||
|
|
984cf13afd | ||
|
|
ac41bf6e86 | ||
|
|
5f21e3964e | ||
|
|
364cd86191 | ||
|
|
b1449ca502 | ||
|
|
6110a0827c | ||
|
|
71b64139da | ||
|
|
3582ac91d7 | ||
|
|
30997bd9ef | ||
|
|
cb673135d2 | ||
|
|
6ac1cf1a5f | ||
|
|
8f29a32a33 | ||
|
|
ac3520791e | ||
|
|
faa6e91ed2 | ||
|
|
86956b0be1 | ||
|
|
fdc39982f3 | ||
|
|
c37cfacb44 | ||
|
|
3af53a6598 | ||
|
|
19c500de27 | ||
|
|
855d538ea3 | ||
|
|
6b1ef16e38 | ||
|
|
1577da25cc | ||
|
|
c44695eb37 | ||
|
|
63fdf67568 | ||
|
|
80cb7281ba | ||
|
|
cefe5965be | ||
|
|
2a9f47ea2c | ||
|
|
85324f9a43 | ||
|
|
2e776ad155 | ||
|
|
f6544f69ca | ||
|
|
c61222403e | ||
|
|
c487f24611 | ||
|
|
8dcd40c8f3 | ||
|
|
0ea2cb5a7a | ||
|
|
5a4a2f3ffd | ||
|
|
5293b328b7 | ||
|
|
2889aab226 | ||
|
|
7a1a25991f | ||
|
|
43f8e5e933 | ||
|
|
f4940d9344 | ||
|
|
701cdff982 | ||
|
|
450c915284 | ||
|
|
892e437428 | ||
|
|
8905157c1e | ||
|
|
2eb57995dd | ||
|
|
b64b88eb65 | ||
|
|
3da4b6411c | ||
|
|
e115634812 | ||
|
|
fc0f354df4 | ||
|
|
ba5cbd5ca6 | ||
|
|
505b060637 | ||
|
|
12b9bd0a6d | ||
|
|
e8715ffb96 | ||
|
|
5d34b137a3 | ||
|
|
ad352a6703 | ||
|
|
7d69d18473 | ||
|
|
668abe4b0a | ||
|
|
5dcccfda3b | ||
|
|
56b271850a | ||
|
|
d338e94267 | ||
|
|
42abfe3c7d | ||
|
|
6ef6540378 | ||
|
|
9a9b8e0a7b | ||
|
|
5ad86f559f | ||
|
|
a8b0e19a33 | ||
|
|
2b61fbb8df | ||
|
|
dea6ce164c | ||
|
|
9ebb705e75 | ||
|
|
010dfa52e3 | ||
|
|
db9d9d1f77 | ||
|
|
6f342bf119 | ||
|
|
48765e82e0 | ||
|
|
f141cd1dea | ||
|
|
6258856d2b | ||
|
|
c93ea188f7 | ||
|
|
329eb419f5 | ||
|
|
e83c42ca26 | ||
|
|
f9eae4153f | ||
|
|
7b41f4783f | ||
|
|
7227cfc68a | ||
|
|
6b87a43162 | ||
|
|
a4c6bf90aa | ||
|
|
a31e894411 | ||
|
|
91e78fd746 | ||
|
|
3abe5de533 | ||
|
|
dfa3c7311f | ||
|
|
2c5b8577aa | ||
|
|
4e804a9d4d | ||
|
|
0ca8c5f56f | ||
|
|
912798e5cb | ||
|
|
5bcdd7fdf0 | ||
|
|
78ffc4c192 | ||
|
|
966b76182f | ||
|
|
b7101494f2 | ||
|
|
be467b3dc4 | ||
|
|
ee70d96c75 | ||
|
|
8fbd380879 | ||
|
|
7746518c0a | ||
|
|
c8a98e27e0 | ||
|
|
3df902af23 | ||
|
|
45542e26cb | ||
|
|
49f73b118c | ||
|
|
6e3dcfddb0 | ||
|
|
09088045ac | ||
|
|
e466232757 | ||
|
|
2ccd6654c1 | ||
|
|
7d7a6b881e | ||
|
|
9661227d00 | ||
|
|
5855c67d4d | ||
|
|
3edfe2b76f | ||
|
|
f36bfe24f6 | ||
|
|
9da4b3a45a | ||
|
|
95524a6af4 | ||
|
|
d4b61541b5 | ||
|
|
143c378ba6 | ||
|
|
dfac93aebb | ||
|
|
b6daca37d5 | ||
|
|
4937619ea0 | ||
|
|
6d34532301 | ||
|
|
fb733483c6 | ||
|
|
2670bb149d | ||
|
|
d49eda63f8 | ||
|
|
08e0fee141 | ||
|
|
d204b9b408 | ||
|
|
c53e0228c5 | ||
|
|
31cffd8412 | ||
|
|
0f71fe28a2 | ||
|
|
f00a29d3df | ||
|
|
e111389d6c | ||
|
|
7079341416 | ||
|
|
7fdbfc0c1a | ||
|
|
e1dff1c931 | ||
|
|
90b2536a99 | ||
|
|
97f54318e3 | ||
|
|
f1481f0deb | ||
|
|
b1a9cde690 | ||
|
|
1ed2a0a0f1 | ||
|
|
759645cab6 | ||
|
|
3203251539 | ||
|
|
b84b94b4db | ||
|
|
3dd77edd16 | ||
|
|
a24165083f | ||
|
|
8878482ca1 | ||
|
|
19c7bbf97d | ||
|
|
23f15947d3 | ||
|
|
152129bf70 | ||
|
|
20ac32c34c | ||
|
|
707b40e8c2 | ||
|
|
0d1d9f4634 | ||
|
|
5a64ca48ad | ||
|
|
f4ddf18124 | ||
|
|
657cf68e55 | ||
|
|
f0013a4d65 | ||
|
|
83fe0249b3 | ||
|
|
3701199cfa | ||
|
|
4b56bfac05 | ||
|
|
613a997694 | ||
|
|
e690e8910c | ||
|
|
34b9a8d21f | ||
|
|
0106ed3d91 | ||
|
|
f8342e4b04 | ||
|
|
8a74b192b0 | ||
|
|
d0ac539d09 | ||
|
|
0be4856144 | ||
|
|
7503b85f6a | ||
|
|
4a9abf20b3 | ||
|
|
2836bb5c41 | ||
|
|
e2925ba01b | ||
|
|
f2724b745b | ||
|
|
712d20079a | ||
|
|
99a5409b39 | ||
|
|
72fe06aa00 | ||
|
|
8081a3f9ff | ||
|
|
f218f9b5a2 | ||
|
|
4e38751187 | ||
|
|
e36e3bcf96 | ||
|
|
18503e5eb8 | ||
|
|
110c5dcf10 | ||
|
|
37f5a462e4 | ||
|
|
a1fb756831 | ||
|
|
5a456eb295 | ||
|
|
ad639ffb61 | ||
|
|
2ae686c366 | ||
|
|
641c9fba9c | ||
|
|
8473d8120f | ||
|
|
954db4e246 | ||
|
|
4f43bc5ec7 | ||
|
|
0bcc79baab | ||
|
|
e7d34a5ab1 | ||
|
|
33f81fd490 | ||
|
|
a1c156cec1 | ||
|
|
3d62482fe9 | ||
|
|
470c9ffed0 | ||
|
|
49c70046e4 | ||
|
|
ff1b01bd10 | ||
|
|
5bcb07dc7f | ||
|
|
35475a260f | ||
|
|
3d377ec0f3 | ||
|
|
bca33372c2 | ||
|
|
96696b33c4 | ||
|
|
5772941057 | ||
|
|
d676ad814b | ||
|
|
5f9fdb0b15 | ||
|
|
0f44fd0064 | ||
|
|
ceba60831c | ||
|
|
fd90df5d54 | ||
|
|
3fe2c29204 | ||
|
|
55d4aaeef5 | ||
|
|
71d3b77668 | ||
|
|
0d3ece98c1 | ||
|
|
3dc83e4075 | ||
|
|
b57ac04728 | ||
|
|
3d952d3c0f | ||
|
|
0897423e69 | ||
|
|
b994ddf894 | ||
|
|
c322cc5621 | ||
|
|
d943283f80 | ||
|
|
995707a43e | ||
|
|
107b5e6ab9 | ||
|
|
2e0fdf7eb4 | ||
|
|
14ecf54d8a | ||
|
|
c6bdeae570 | ||
|
|
2d539a9b8f | ||
|
|
8e1f05082e | ||
|
|
170d86be9a | ||
|
|
d810b2d073 | ||
|
|
e948bab4d9 | ||
|
|
7bed1417b9 | ||
|
|
f7eea71b0b | ||
|
|
a0eee06c16 | ||
|
|
b7c013c1e8 | ||
|
|
1ee2eaf5e9 | ||
|
|
fe55012007 | ||
|
|
42eb31e7e1 | ||
|
|
83423adc05 | ||
|
|
b019f17590 | ||
|
|
e58ba2e044 | ||
|
|
79ca8e968c | ||
|
|
5a095c3771 | ||
|
|
65094532eb | ||
|
|
13caa6691c | ||
|
|
bcd1770a46 | ||
|
|
aa96d87502 | ||
|
|
d20be2aaf8 | ||
|
|
d2ded394f6 | ||
|
|
2b8f458a38 | ||
|
|
e3a7ec6aed | ||
|
|
93f9fd7206 | ||
|
|
28915fdce0 | ||
|
|
497455d281 | ||
|
|
c758cbda5e | ||
|
|
4655133843 | ||
|
|
672a97cb34 | ||
|
|
0f8cc79c00 | ||
|
|
e2b6865938 | ||
|
|
bf0bc6468a | ||
|
|
526bf15c3c | ||
|
|
bdfb0e3e25 | ||
|
|
2d6ebf16d8 | ||
|
|
13c62043eb | ||
|
|
39d60cd91d | ||
|
|
aaf79c5202 | ||
|
|
884c790009 | ||
|
|
5e5dbf5984 | ||
|
|
0794cfec9e | ||
|
|
a878374d28 | ||
|
|
120861bf55 | ||
|
|
b7514e1e04 | ||
|
|
da390e3959 | ||
|
|
3062759ca8 | ||
|
|
cb4b417f76 | ||
|
|
ef951094b3 | ||
|
|
b14aefa1d3 | ||
|
|
aa7c11a873 | ||
|
|
b871699103 | ||
|
|
8b946ec36d | ||
|
|
da73e1eda9 | ||
|
|
cd8716400b | ||
|
|
854ab0b151 | ||
|
|
c1c98e16d3 | ||
|
|
1ee99268f1 | ||
|
|
403ed3abaf | ||
|
|
de2ae678a9 | ||
|
|
45c92568a1 | ||
|
|
2f455409e2 | ||
|
|
55bdde560a | ||
|
|
4e249125eb | ||
|
|
1f0ba0198b | ||
|
|
145ccc77d6 | ||
|
|
1cb0908961 | ||
|
|
1db7fbad66 | ||
|
|
7d79b35f93 | ||
|
|
2f331b7a8b | ||
|
|
d96d5335b4 | ||
|
|
4c2150fb3d | ||
|
|
2751b3515b | ||
|
|
76b36a81ca | ||
|
|
3eb244898f | ||
|
|
7aacf9836c | ||
|
|
24eeb67275 | ||
|
|
bf86730a62 | ||
|
|
98494420c5 | ||
|
|
7717ff01a1 | ||
|
|
5c3576c7c6 | ||
|
|
d6576ed2f1 | ||
|
|
9a61c8f8dd | ||
|
|
d192ec8fae | ||
|
|
fe913577f6 | ||
|
|
312d00cc33 | ||
|
|
c3ac504c10 | ||
|
|
5d94f0eea6 | ||
|
|
97734fd895 | ||
|
|
596e1ce135 | ||
|
|
e1c58b4584 | ||
|
|
f5d470c531 | ||
|
|
a87277c6e8 | ||
|
|
6700ecaf43 | ||
|
|
ad8a11bb49 | ||
|
|
ce2051ed39 | ||
|
|
d16989ce55 | ||
|
|
a26e1c0f41 | ||
|
|
510267f6e9 | ||
|
|
8e6a5e19c2 | ||
|
|
21244ab832 | ||
|
|
7a64f1634f | ||
|
|
2d8268d3d0 | ||
|
|
f6b96e4984 | ||
|
|
7fd972d669 | ||
|
|
42190df874 | ||
|
|
19673e3b1c | ||
|
|
b6b334dd16 | ||
|
|
a8443abe80 | ||
|
|
49b630c2d4 | ||
|
|
cd56cae032 | ||
|
|
6c74aa0289 | ||
|
|
8ce147dcbd | ||
|
|
7f51c8dba4 | ||
|
|
7c2ba681e9 | ||
|
|
1c459e6ee6 | ||
|
|
f6a077e102 | ||
|
|
b797862a91 | ||
|
|
abc7327116 | ||
|
|
7c58a8247c | ||
|
|
263150e599 | ||
|
|
7a177d6ac0 | ||
|
|
d5e5c08b87 | ||
|
|
c485bc975a | ||
|
|
2dfdaca3eb | ||
|
|
56f11f94d8 | ||
|
|
ccbe691cc8 | ||
|
|
f8b53c1cf7 | ||
|
|
c920354423 | ||
|
|
1ab8cc4c0f | ||
|
|
3aa62a821a | ||
|
|
ecf76830a5 | ||
|
|
ce6ca0cf9d | ||
|
|
202a438044 | ||
|
|
d7ffd48c67 | ||
|
|
7440e7f789 | ||
|
|
f813bbdf86 | ||
|
|
2656bfbcac | ||
|
|
dc95efea1a | ||
|
|
81e7e4dd81 | ||
|
|
57a2b65488 | ||
|
|
b23e47c478 | ||
|
|
ff4ca3098b | ||
|
|
b6f8363023 | ||
|
|
9c07cf60a6 | ||
|
|
36324af017 | ||
|
|
31392ce1aa | ||
|
|
6cf039eecc | ||
|
|
79ab9800c0 | ||
|
|
05373cbb6b | ||
|
|
1b009da4d0 | ||
|
|
b39b6b7635 | ||
|
|
c2d3713f40 | ||
|
|
c4345c809e | ||
|
|
c761934868 | ||
|
|
77c4a09a9b | ||
|
|
58326b8fff | ||
|
|
ee5d4b9e73 | ||
|
|
e667e6dbd9 | ||
|
|
ec288246d0 | ||
|
|
71c332803a | ||
|
|
5e30830cb9 | ||
|
|
57054f7451 | ||
|
|
1c6c085127 | ||
|
|
ff4d25d454 | ||
|
|
85cb09ae6d | ||
|
|
854a5aa3c3 | ||
|
|
bde33a1d6a | ||
|
|
8d98d8752b | ||
|
|
cebeb4ea5f | ||
|
|
a3a27a9a6c | ||
|
|
973c72bdf0 | ||
|
|
7bdd180c30 | ||
|
|
19d2fe8738 | ||
|
|
3d5a2d26d1 | ||
|
|
4e37a14bf8 | ||
|
|
91500344d4 | ||
|
|
d8fe1a17cc | ||
|
|
9945ce7583 | ||
|
|
54d36f89ea | ||
|
|
193cf30780 | ||
|
|
ab8c09fcb9 | ||
|
|
1db53ba155 | ||
|
|
b41bb5c595 | ||
|
|
c7676755ab | ||
|
|
4f88b3865f | ||
|
|
089d2db104 | ||
|
|
fefb6ad4c4 | ||
|
|
05b795bc14 | ||
|
|
ff3f5067c8 | ||
|
|
0c54f60e17 | ||
|
|
82b33708ba | ||
|
|
5b8289c05a | ||
|
|
ea5cabb27f | ||
|
|
a6b9fb285c | ||
|
|
4041d06e95 | ||
|
|
13cd5aa4ce | ||
|
|
00b504ebc5 | ||
|
|
afb83a6cb9 | ||
|
|
f5b03fb2e8 | ||
|
|
b8d3aa2a68 | ||
|
|
52f154ec02 | ||
|
|
e4d0693eb9 | ||
|
|
4a42c93897 | ||
|
|
8b438dea76 | ||
|
|
12977a50bc | ||
|
|
33f84624ec | ||
|
|
f252480bee | ||
|
|
c9df887c4c | ||
|
|
03edf7f4a8 | ||
|
|
a98a719546 | ||
|
|
a97483b928 | ||
|
|
9955886ef5 | ||
|
|
3646a7143e | ||
|
|
13f40e4333 | ||
|
|
6249660e1f | ||
|
|
3eb2d3c4b3 | ||
|
|
8f1fc75fdf | ||
|
|
d3c37344f0 | ||
|
|
5e8b6a9e55 | ||
|
|
bbd0eedb5f | ||
|
|
ad51b34438 | ||
|
|
0d4b753409 | ||
|
|
6f5727cbdb | ||
|
|
10e88d07af | ||
|
|
3f1e4a703a | ||
|
|
bc9eca70d0 | ||
|
|
69b882a14b | ||
|
|
6984e6a4f2 | ||
|
|
fd0cab2ab8 | ||
|
|
93216374ef | ||
|
|
8ba710637a | ||
|
|
937c3484cf | ||
|
|
59db6cf788 | ||
|
|
f41b3e8295 | ||
|
|
fe439890e8 | ||
|
|
e29f762116 | ||
|
|
c8abaf32ee | ||
|
|
c0a9f638ce | ||
|
|
4a90ae5b0f | ||
|
|
7ccd62ba98 | ||
|
|
2e1ef850e3 | ||
|
|
dbba786a35 | ||
|
|
d0d4be9e35 | ||
|
|
2d69c7a5ca | ||
|
|
24a38922bd | ||
|
|
1e553df5b6 | ||
|
|
0f37f774f1 | ||
|
|
34c07ea148 | ||
|
|
70fca4483e | ||
|
|
b2b017accb | ||
|
|
a97160cf57 | ||
|
|
1d42f5b7b1 | ||
|
|
70ac0509df | ||
|
|
f1678399af | ||
|
|
bae1f8ca82 | ||
|
|
790c33d6a7 | ||
|
|
a9f5da7799 | ||
|
|
6a59e6db39 | ||
|
|
76a44cff09 | ||
|
|
e36dce52ba | ||
|
|
c31ace5fc8 | ||
|
|
c494b3db58 | ||
|
|
bf0c3c188e | ||
|
|
0f9f3eba72 | ||
|
|
0960f885d5 | ||
|
|
33b28a514e | ||
|
|
2497d663b7 | ||
|
|
887f1dc07c | ||
|
|
0d033679d4 | ||
|
|
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 |
@@ -0,0 +1,149 @@
|
||||
# Copyright 2016, 2017 Peter Dimov
|
||||
# Copyright 2017 - 2019 James E. King III
|
||||
# Copyright 2019 - 2021 Alexander Grund
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
version: 1.0.{build}-{branch}
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- /bugfix\/.*/
|
||||
- /feature\/.*/
|
||||
- /fix\/.*/
|
||||
- /pr\/.*/
|
||||
|
||||
matrix:
|
||||
fast_finish: false
|
||||
# Adding MAYFAIL to any matrix job allows it to fail but the build stays green:
|
||||
allow_failures:
|
||||
- MAYFAIL: true
|
||||
|
||||
environment:
|
||||
global:
|
||||
B2_CI_VERSION: 1
|
||||
GIT_FETCH_JOBS: 4
|
||||
B2_ADDRESS_MODEL: 32,64
|
||||
B2_VARIANT: debug,release
|
||||
|
||||
matrix:
|
||||
- FLAVOR: Visual Studio 2008, 2010, 2012
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
|
||||
B2_ADDRESS_MODEL: 32 # No 64bit support
|
||||
|
||||
- FLAVOR: Visual Studio 2013, 2015
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-12.0,msvc-14.0
|
||||
|
||||
- FLAVOR: Visual Studio 2017
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
B2_CXXSTD: 14,17
|
||||
B2_TOOLSET: msvc-14.1
|
||||
|
||||
- FLAVOR: Visual Studio 2017
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
B2_CXXSTD: latest
|
||||
B2_TOOLSET: msvc-14.1
|
||||
|
||||
- FLAVOR: cygwin (32-bit)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 03,11,14,1z
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 03,11,14,1z
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 03
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 11
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 14
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 1z
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
- FLAVOR: mingw-w64, 32 bit
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
||||
B2_CXXSTD: 03,11,14
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 32
|
||||
|
||||
- FLAVOR: mingw-w64, 32 bit
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
||||
B2_CXXSTD: 17,2a
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 32
|
||||
|
||||
- FLAVOR: mingw-w64, 64 bit
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
B2_CXXSTD: 03,11,14
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 64
|
||||
|
||||
- FLAVOR: mingw-w64, 64 bit
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
B2_CXXSTD: 17,2a
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 64
|
||||
|
||||
#- FLAVOR: CodeCov (VS 2019)
|
||||
# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
# B2_CXXFLAGS: -permissive-
|
||||
# B2_CXXSTD: 14
|
||||
# B2_TOOLSET: msvc-14.2
|
||||
# COVERAGE: true
|
||||
|
||||
install:
|
||||
- git clone --depth 1 https://github.com/boostorg/boost-ci.git C:\boost-ci-cloned
|
||||
# Copy ci folder if not testing Boost.CI
|
||||
- if NOT "%APPVEYOR_PROJECT_NAME%" == "boost-ci" xcopy /s /e /q /i /y C:\boost-ci-cloned\ci .\ci
|
||||
- rmdir /s /q C:\boost-ci-cloned
|
||||
- ci\appveyor\install.bat
|
||||
|
||||
build: off
|
||||
|
||||
test_script: ci\build.bat
|
||||
|
||||
for:
|
||||
# CodeCov coverage build
|
||||
- matrix:
|
||||
only: [COVERAGE: true]
|
||||
test_script: [ps: ci\codecov.ps1]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Copyright 2019 - 2021 Alexander Grund
|
||||
# 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)
|
||||
#
|
||||
# Sample codecov configuration file. Edit as required
|
||||
|
||||
codecov:
|
||||
max_report_age: off
|
||||
require_ci_to_pass: yes
|
||||
notify:
|
||||
# Increase this if you have multiple coverage collection jobs
|
||||
after_n_builds: 1
|
||||
wait_for_ci: yes
|
||||
|
||||
# Change how pull request comments look
|
||||
comment:
|
||||
layout: "reach,diff,flags,files,footer"
|
||||
|
||||
# Ignore specific files or folders. Glob patterns are supported.
|
||||
# See https://docs.codecov.com/docs/ignoring-paths
|
||||
ignore:
|
||||
- extra/**/*
|
||||
# - test/**/*
|
||||
@@ -0,0 +1,409 @@
|
||||
# Copyright 2022 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
local library = "unordered";
|
||||
|
||||
local triggers =
|
||||
{
|
||||
branch: [ "master", "develop", "feature/*", "bugfix/*", "fix/*", "pr/*" ]
|
||||
};
|
||||
|
||||
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
|
||||
local asan = { ASAN: '1' };
|
||||
local tsan = { TSAN: '1' };
|
||||
|
||||
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
|
||||
{
|
||||
name: name,
|
||||
kind: "pipeline",
|
||||
type: "docker",
|
||||
trigger: triggers,
|
||||
platform:
|
||||
{
|
||||
os: "linux",
|
||||
arch: arch
|
||||
},
|
||||
steps:
|
||||
[
|
||||
{
|
||||
name: "everything",
|
||||
image: image,
|
||||
environment: environment,
|
||||
commands:
|
||||
[
|
||||
'set -e',
|
||||
'uname -a',
|
||||
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
|
||||
] +
|
||||
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
|
||||
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
|
||||
[
|
||||
'export LIBRARY=' + library,
|
||||
'./.drone/drone.sh',
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") =
|
||||
{
|
||||
name: name,
|
||||
kind: "pipeline",
|
||||
type: "exec",
|
||||
trigger: triggers,
|
||||
platform: {
|
||||
"os": "darwin",
|
||||
"arch": arch
|
||||
},
|
||||
node: {
|
||||
"os": osx_version
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
name: "everything",
|
||||
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
|
||||
commands:
|
||||
[
|
||||
'uname -a',
|
||||
'export LIBRARY=' + library,
|
||||
'./.drone/drone.sh',
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
{
|
||||
name: name,
|
||||
kind: "pipeline",
|
||||
type: "docker",
|
||||
trigger: triggers,
|
||||
platform:
|
||||
{
|
||||
os: "windows",
|
||||
arch: arch
|
||||
},
|
||||
"steps":
|
||||
[
|
||||
{
|
||||
name: "everything",
|
||||
image: image,
|
||||
environment: environment,
|
||||
commands:
|
||||
[
|
||||
'echo $env:DRONE_STAGE_MACHINE',
|
||||
'cmd /C .drone\\\\drone.bat ' + library,
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
[
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.4 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.4', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
||||
"g++-4.4-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.6 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.6', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
||||
"g++-4.6-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.7 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
||||
"g++-4.7-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.8* 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.9 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '03,11', ADDRMD: '32,64' },
|
||||
"g++-4.9-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 GCC 5* 32/64",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 6 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
"g++-6-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 7* 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 8 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
|
||||
"g++-8-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* ARM64",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* S390x",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||
arch="s390x",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 10 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14,17,20', ADDRMD: '32,64' },
|
||||
"g++-10-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 11* 32/64",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 32 ASAN (03,11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14', ADDRMD: '32' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 32 ASAN (17,20,2b)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17,20,2b', ADDRMD: '32' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 64 ASAN (03,11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14', ADDRMD: '64' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 64 ASAN (17,20,2b)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17,20,2b', ADDRMD: '64' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 64 TSAN (11,14,17,20,2b)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14,17,20,2b', ADDRMD: '64', TARGET: 'libs/unordered/test//cfoa_tests' } + tsan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.5",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '03,11' },
|
||||
"clang-3.5",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.6",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '03,11,14' },
|
||||
"clang-3.6",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.7",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '03,11,14' },
|
||||
"clang-3.7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.8",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '03,11,14' },
|
||||
"clang-3.8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 3.9",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '03,11,14' },
|
||||
"clang-3.9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 4.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '03,11,14' },
|
||||
"clang-4.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 5.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '03,11,14,1z' },
|
||||
"clang-5.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 6.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '03,11,14,17' },
|
||||
"clang-6.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 7",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '03,11,14,17' },
|
||||
"clang-7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 8",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '03,11,14,17' },
|
||||
"clang-8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 9",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 10",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-10",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 11",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-11",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 12",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '03,11,14,17,2a' },
|
||||
"clang-12",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 13",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20' },
|
||||
"clang-13",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 UBSAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + ubsan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 ASAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + asan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 libc++ 64 TSAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', ADDRMD: '64', TARGET: 'libs/unordered/test//cfoa_tests', CXXSTD: '11,14,17,20', STDLIB: 'libc++' } + tsan,
|
||||
"clang-14 libc++-14-dev libc++abi-14-dev",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 15",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' },
|
||||
"clang-15",
|
||||
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 UBSAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 12.4 Xcode 13.4.1 ASAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 12.4 Xcode 13.4.1 TSAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z', TARGET: 'libs/unordered/test//cfoa_tests' } + tsan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2015 msvc-14.0",
|
||||
"cppalliance/dronevs2015",
|
||||
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2017 msvc-14.1",
|
||||
"cppalliance/dronevs2017",
|
||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2019 msvc-14.2",
|
||||
"cppalliance/dronevs2019",
|
||||
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2022 msvc-14.3",
|
||||
"cppalliance/dronevs2022:1",
|
||||
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
@REM Copyright 2022 Peter Dimov
|
||||
@REM Distributed under the Boost Software License, Version 1.0.
|
||||
@REM https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
@ECHO ON
|
||||
|
||||
set LIBRARY=%1
|
||||
set DRONE_BUILD_DIR=%CD%
|
||||
|
||||
set BOOST_BRANCH=develop
|
||||
if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init tools/boostdep
|
||||
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\
|
||||
python tools/boostdep/depinst/depinst.py %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2022 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
set -ex
|
||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||
|
||||
: ${TARGET:="libs/$LIBRARY/test"}
|
||||
|
||||
DRONE_BUILD_DIR=$(pwd)
|
||||
|
||||
BOOST_BRANCH=develop
|
||||
if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
|
||||
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init tools/boostdep
|
||||
cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY
|
||||
python tools/boostdep/depinst/depinst.py $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
|
||||
./b2 -j3 $TARGET toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${STDLIB:+stdlib=$STDLIB} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${TSAN:+thread-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
|
||||
@@ -0,0 +1,7 @@
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
|
||||
[*.?pp]
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,226 @@
|
||||
# Copyright 2020-2021 Peter Dimov
|
||||
# Copyright 2021 Andrey Semashev
|
||||
# Copyright 2021 Alexander Grund
|
||||
# Copyright 2022 James E. King III
|
||||
#
|
||||
# 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)
|
||||
---
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- bugfix/**
|
||||
- feature/**
|
||||
- fix/**
|
||||
- pr/**
|
||||
|
||||
#concurrency:
|
||||
# group: ${{format('{0}:{1}', github.repository, github.ref)}}
|
||||
# cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GIT_FETCH_JOBS: 8
|
||||
NET_RETRY_COUNT: 5
|
||||
B2_CI_VERSION: 1
|
||||
B2_VARIANT: debug,release
|
||||
LCOV_BRANCH_COVERAGE: 0
|
||||
CODECOV_NAME: Github Actions
|
||||
|
||||
jobs:
|
||||
posix:
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Linux, gcc
|
||||
# - { compiler: gcc-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-7' }
|
||||
# - { compiler: gcc-8, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-8' }
|
||||
# - { compiler: gcc-9, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-9' }
|
||||
# - { compiler: gcc-10, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-10' }
|
||||
# - { compiler: gcc-11, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-11' }
|
||||
# - { name: "gcc-12 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
# compiler: gcc-12, cxxstd: '03,11,14', os: ubuntu-22.04, ccache_key: "san1" }
|
||||
# - { name: "gcc-12 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
# compiler: gcc-12, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
|
||||
# - { name: Collect coverage, coverage: yes,
|
||||
# compiler: gcc-8, cxxstd: '03,11', os: ubuntu-20.04, install: 'g++-8-multilib', address-model: '32,64', ccache_key: "cov" }
|
||||
|
||||
- { name: "cfoa tsan (gcc)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: gcc-12,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes, ccache_key: "tsan-gcc" }
|
||||
|
||||
# Linux, clang, libc++
|
||||
# - { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, stdlib: libc++, install: 'clang-7 libc++-7-dev libc++abi-7-dev' }
|
||||
# - { compiler: clang-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, stdlib: libc++, install: 'clang-10 libc++-10-dev libc++abi-10-dev' }
|
||||
# - { compiler: clang-11, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, stdlib: libc++, install: 'clang-11 libc++-11-dev libc++abi-11-dev' }
|
||||
# clang-12 doesn't work on ubuntu-22.04, the linker can't find -lunwind for some reason
|
||||
# - { name: "clang-12 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
# compiler: clang-12, cxxstd: '03,11,14', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san1" }
|
||||
# - { name: "clang-12 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
# compiler: clang-12, cxxstd: '17,20,2b', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
||||
# - { compiler: clang-13, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
||||
# - { compiler: clang-14, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
||||
|
||||
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
|
||||
# - { name: "clang-14 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
# compiler: clang-14, cxxstd: '03,11,14', os: ubuntu-22.04, ccache_key: "san1" }
|
||||
# - { name: "clang-14 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
# compiler: clang-14, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
|
||||
|
||||
- { name: "cfoa tsan (clang)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: clang-14,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes,
|
||||
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev', ccache_key: "tsan-clang" }
|
||||
|
||||
# OSX, clang
|
||||
- { compiler: clang, cxxstd: '11,14', os: macos-11, ccache_key: "11-14" }
|
||||
- { compiler: clang, cxxstd: '17,2a', os: macos-11, ccache_key: "17-2a" }
|
||||
- { compiler: clang, cxxstd: '11,14', os: macos-12, sanitize: yes, ccache_key: "11-14" }
|
||||
- { compiler: clang, cxxstd: '17,2a', os: macos-12, sanitize: yes, ccache_key: "17-2a" }
|
||||
- { compiler: clang, cxxstd: '11,14', os: macos-12, variant: release, thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache_key: "tsan-macos-1" }
|
||||
- { compiler: clang, cxxstd: '17,2a', os: macos-12, variant: release, thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache_key: "tsan-macos-2" }
|
||||
|
||||
timeout-minutes: 240
|
||||
runs-on: ${{matrix.os}}
|
||||
container: ${{matrix.container}}
|
||||
env: {B2_USE_CCACHE: 1}
|
||||
|
||||
steps:
|
||||
- name: Setup environment
|
||||
run: |
|
||||
if [ -f "/etc/debian_version" ]; then
|
||||
echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
fi
|
||||
if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then
|
||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common
|
||||
# Need (newer) git, and the older Ubuntu container may require requesting the key manually using port 80
|
||||
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E1DD270288B4E6030699E45FA1715D88E1DF1F24
|
||||
for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done
|
||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y g++ python libpython-dev git
|
||||
fi
|
||||
# For jobs not compatible with ccache, use "ccache: no" in the matrix
|
||||
if [[ "${{ matrix.ccache }}" == "no" ]]; then
|
||||
echo "B2_USE_CCACHE=0" >> $GITHUB_ENV
|
||||
fi
|
||||
git config --global pack.threads 0
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
# For coverage builds fetch the whole history, else only 1 commit using a 'fake ternary'
|
||||
fetch-depth: ${{ matrix.coverage && '0' || '1' }}
|
||||
|
||||
- name: Cache ccache
|
||||
uses: actions/cache@v3
|
||||
if: env.B2_USE_CCACHE
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{matrix.ccache_key}}-${{github.sha}}
|
||||
restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{matrix.ccache_key}}-
|
||||
|
||||
- name: Fetch Boost.CI
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: boostorg/boost-ci
|
||||
ref: master
|
||||
path: boost-ci-cloned
|
||||
|
||||
- name: Get CI scripts folder
|
||||
run: |
|
||||
# Copy ci folder if not testing Boost.CI
|
||||
[[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci .
|
||||
rm -rf boost-ci-cloned
|
||||
|
||||
- name: Install packages
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
SOURCE_KEYS=(${{join(matrix.source_keys, ' ')}})
|
||||
SOURCES=(${{join(matrix.sources, ' ')}})
|
||||
# Add this by default
|
||||
SOURCES+=(ppa:ubuntu-toolchain-r/test)
|
||||
for key in "${SOURCE_KEYS[@]}"; do
|
||||
for i in {1..$NET_RETRY_COUNT}; do
|
||||
wget -O - "$key" | sudo apt-key add - && break || sleep 10
|
||||
done
|
||||
done
|
||||
for source in "${SOURCES[@]}"; do
|
||||
for i in {1..$NET_RETRY_COUNT}; do
|
||||
sudo add-apt-repository $source && break || sleep 10
|
||||
done
|
||||
done
|
||||
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
||||
if [[ -z "${{matrix.install}}" ]]; then
|
||||
pkgs="${{matrix.compiler}}"
|
||||
pkgs="${pkgs/gcc-/g++-}"
|
||||
else
|
||||
pkgs="${{matrix.install}}"
|
||||
fi
|
||||
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs
|
||||
|
||||
- name: Setup GCC Toolchain
|
||||
if: matrix.gcc_toolchain
|
||||
run: |
|
||||
GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain"
|
||||
echo "GCC_TOOLCHAIN_ROOT=$GCC_TOOLCHAIN_ROOT" >> $GITHUB_ENV
|
||||
MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)"
|
||||
mkdir -p "$GCC_TOOLCHAIN_ROOT"
|
||||
ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include"
|
||||
ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin"
|
||||
mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET"
|
||||
ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}"
|
||||
|
||||
- name: Setup multiarch
|
||||
if: matrix.multiarch
|
||||
run: |
|
||||
sudo apt-get install --no-install-recommends -y binfmt-support qemu-user-static
|
||||
sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
git clone https://github.com/jeking3/bdde.git
|
||||
echo "$(pwd)/bdde/bin/linux" >> ${GITHUB_PATH}
|
||||
echo "BDDE_DISTRO=${{ matrix.distro }}" >> ${GITHUB_ENV}
|
||||
echo "BDDE_EDITION=${{ matrix.edition }}" >> ${GITHUB_ENV}
|
||||
echo "BDDE_ARCH=${{ matrix.arch }}" >> ${GITHUB_ENV}
|
||||
echo "B2_WRAPPER=bdde" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Setup Boost
|
||||
env:
|
||||
B2_ADDRESS_MODEL: ${{matrix.address-model}}
|
||||
B2_COMPILER: ${{matrix.compiler}}
|
||||
B2_CXXSTD: ${{matrix.cxxstd}}
|
||||
B2_SANITIZE: ${{matrix.sanitize}}
|
||||
B2_TSAN: ${{matrix.thread-sanitize}}
|
||||
B2_TARGETS: ${{matrix.targets}}
|
||||
B2_STDLIB: ${{matrix.stdlib}}
|
||||
B2_VARIANT: ${{matrix.variant}}
|
||||
# More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys.
|
||||
# B2_DEFINES: ${{matrix.defines}}
|
||||
# Variables set here (to non-empty) will override the top-level environment variables, e.g.
|
||||
# B2_VARIANT: ${{matrix.variant}}
|
||||
run: source ci/github/install.sh
|
||||
|
||||
- name: Setup coverage collection
|
||||
if: matrix.coverage
|
||||
run: ci/github/codecov.sh "setup"
|
||||
|
||||
- name: Run tests
|
||||
if: '!matrix.coverity'
|
||||
run: B2_TARGETS=${{matrix.targets}} B2_FLAGS='-l 3600' ci/build.sh
|
||||
|
||||
- name: Upload coverage
|
||||
if: matrix.coverage
|
||||
run: ci/codecov.sh "upload"
|
||||
|
||||
- name: Run coverity
|
||||
if: matrix.coverity && github.event_name == 'push' && (github.ref_name == 'develop' || github.ref_name == 'master')
|
||||
run: ci/github/coverity.sh
|
||||
env:
|
||||
COVERITY_SCAN_NOTIFICATION_EMAIL: ${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }}
|
||||
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
@@ -1 +1,2 @@
|
||||
/doc/html/
|
||||
/doc/pdf/
|
||||
|
||||
@@ -11,7 +11,6 @@ language: c++
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libboost-tools-dev
|
||||
- libxml2-utils
|
||||
- g++-multilib
|
||||
|
||||
@@ -19,46 +18,70 @@ matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
env: |
|
||||
label="gcc C++03";
|
||||
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++03 ;"
|
||||
enable_coverage=1
|
||||
- compiler: gcc
|
||||
env: |
|
||||
label="gcc C++11";
|
||||
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror --std=c++11 ;"
|
||||
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 -Werror --std=c++11 ;"
|
||||
user_config="using gcc : : g++-4.8 -m32 -fsanitize=address ;"
|
||||
CXXSTD=11
|
||||
- compiler: clang
|
||||
env: |
|
||||
label="clang C++11";
|
||||
user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++11 ;"
|
||||
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 -Werror --std=c++03 ;"
|
||||
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
|
||||
- wget -O boost.tar.bz2 https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2
|
||||
- tar -xjf boost.tar.bz2
|
||||
- mv boost_1_64_0 boost
|
||||
- rm -r boost/boost/unordered
|
||||
- |
|
||||
# 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
|
||||
- bjam -q include=${HOME}/boost include=${TRAVIS_BUILD_DIR}/include
|
||||
- ${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
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Generated by `boostdep --cmake unordered`
|
||||
# Copyright 2020, 2021 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.20)
|
||||
|
||||
project(boost_unordered VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_unordered INTERFACE)
|
||||
add_library(Boost::unordered ALIAS boost_unordered)
|
||||
|
||||
target_include_directories(boost_unordered INTERFACE include)
|
||||
|
||||
target_link_libraries(boost_unordered
|
||||
INTERFACE
|
||||
Boost::assert
|
||||
Boost::config
|
||||
Boost::container_hash
|
||||
Boost::core
|
||||
Boost::move
|
||||
Boost::mp11
|
||||
Boost::predef
|
||||
Boost::preprocessor
|
||||
Boost::throw_exception
|
||||
Boost::tuple
|
||||
Boost::type_traits
|
||||
)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
||||
@@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Boost.Unordered
|
||||
|
||||
Part of collection of the [Boost C++ Libraries](http://github.com/boostorg).
|
||||
|
||||
For accessing data based on key lookup, the C++ standard library offers `std::set`, `std::map`, `std::multiset` and `std::multimap`.
|
||||
These are generally implemented using balanced binary trees so that lookup time has logarithmic complexity.
|
||||
That is generally okay, but in many cases a hash table can perform better, as accessing data has constant complexity, on average.
|
||||
The worst case complexity is linear, but that occurs rarely and with some care, can be avoided.
|
||||
|
||||
Also, the existing containers require a 'less than' comparison object 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, unordered associative containers were added to the C++ standard.
|
||||
This is an implementation of the containers described in C++11, with some deviations from the standard in order to work with non-C++11 compilers and libraries.
|
||||
|
||||
|
||||
### License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
### Properties
|
||||
|
||||
* C++03
|
||||
* Header-Only
|
||||
|
||||
### Build Status
|
||||
|
||||
Branch | GH Actions | Appveyor | codecov.io | Deps | Docs | Tests |
|
||||
:-------------: | ---------- | -------- | ---------- | ---- | ---- | ----- |
|
||||
[`master`](https://github.com/boostorg/unordered/tree/master) | [](https://github.com/boostorg/unordered/actions/workflows/ci.yml) | [](https://ci.appveyor.com/project/danieljames/unordered-qtwe6/branch/master) | [](https://codecov.io/gh/boostorg/unordered/branch/master) | [](https://pdimov.github.io/boostdep-report/master/unordered.html) | [](https://www.boost.org/doc/libs/master/libs/unordered/doc/html/unordered.html) | [](http://www.boost.org/development/tests/master/developer/unordered.html)
|
||||
[`develop`](https://github.com/boostorg/unordered/tree/develop) | [](https://github.com/boostorg/unordered/actions/workflows/ci.yml) | [](https://ci.appveyor.com/project/danieljames/unordered-qtwe6/branch/develop) | [](https://codecov.io/gh/boostorg/unordered/branch/develop) | [](https://pdimov.github.io/boostdep-report/develop/unordered.html) | [](https://www.boost.org/doc/libs/develop/libs/unordered/doc/html/unordered.html) | [](http://www.boost.org/development/tests/develop/developer/unordered.html)
|
||||
|
||||
### Directories
|
||||
|
||||
| Name | Purpose |
|
||||
| ----------- | ------------------------------ |
|
||||
| `doc` | documentation |
|
||||
| `example` | examples |
|
||||
| `include` | headers |
|
||||
| `test` | unit tests |
|
||||
|
||||
### More information
|
||||
|
||||
* [Ask questions](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-unordered)
|
||||
* [Report bugs](https://github.com/boostorg/unordered/issues): Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
|
||||
* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
|
||||
* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[unordered]` tag at the beginning of the subject line.
|
||||
|
||||
@@ -3,16 +3,17 @@
|
||||
# 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 3.8
|
||||
# http://llvm.org/releases/3.8.0/tools/clang/docs/ClangFormatStyleOptions.html
|
||||
# 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
|
||||
ContinuationIndentWidth: 4
|
||||
IndentWidth: 4
|
||||
NamespaceIndentation: All
|
||||
ContinuationIndentWidth: 2
|
||||
IndentWidth: 2
|
||||
UseTab: Never
|
||||
Language: Cpp
|
||||
Standard: Cpp03
|
||||
@@ -34,4 +35,4 @@ BraceWrapping:
|
||||
PointerAlignment: Left
|
||||
|
||||
# Boost specific stuff
|
||||
ForEachMacros: [ BOOST_FOREACH ]
|
||||
ForEachMacros: [ BOOST_FOREACH, UNORDERED_AUTO_TEST ]
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
enwik8
|
||||
enwik9
|
||||
*.exe
|
||||
@@ -0,0 +1,431 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
constexpr unsigned N = 2'000'000;
|
||||
constexpr int K = 10;
|
||||
|
||||
static std::vector<std::string> indices1, indices2;
|
||||
|
||||
static std::string make_index( unsigned x )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
std::snprintf( buffer, sizeof(buffer), "pfx_%u_sfx", x );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static std::string make_random_index( unsigned x )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
std::snprintf( buffer, sizeof(buffer), "pfx_%0*d_%u_sfx", x % 8 + 1, 0, x );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void init_indices()
|
||||
{
|
||||
indices1.reserve( N*2+1 );
|
||||
indices1.push_back( make_index( 0 ) );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices1.push_back( make_index( i ) );
|
||||
}
|
||||
|
||||
indices2.reserve( N*2+1 );
|
||||
indices2.push_back( make_index( 0 ) );
|
||||
|
||||
{
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices2.push_back( make_random_index( static_cast<std::uint32_t>( rng() ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices1[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices2[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Random insert", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::uint32_t s;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices1[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices2[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Random lookup", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
auto it = map.begin();
|
||||
|
||||
while( it != map.end() )
|
||||
{
|
||||
if( it->second & 1 )
|
||||
{
|
||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
||||
{
|
||||
map.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
it = map.erase( it );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices1[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices2[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Random erase", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::string, std::uint32_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_insert( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_lookup( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
test_lookup( map, t1 );
|
||||
test_erase( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map =
|
||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
|
||||
template<> struct fnv1a_hash_impl<32>
|
||||
{
|
||||
std::size_t operator()( std::string const& s ) const
|
||||
{
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x01000193ul;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct fnv1a_hash_impl<64>
|
||||
{
|
||||
std::size_t operator()( std::string const& s ) const
|
||||
{
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x00000100000001B3ull;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
template<class K, class V> using std_unordered_map_fnv1a =
|
||||
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map_fnv1a =
|
||||
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
||||
absl::node_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map_fnv1a =
|
||||
absl::flat_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,432 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
constexpr unsigned N = 2'000'000;
|
||||
constexpr int K = 10;
|
||||
|
||||
static std::vector<std::string> indices1, indices2;
|
||||
|
||||
static std::string make_index( unsigned x )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
std::snprintf( buffer, sizeof(buffer), "pfx_%u_sfx", x );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static std::string make_random_index( unsigned x )
|
||||
{
|
||||
char buffer[ 64 ];
|
||||
std::snprintf( buffer, sizeof(buffer), "pfx_%0*d_%u_sfx", x % 8 + 1, 0, x );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void init_indices()
|
||||
{
|
||||
indices1.reserve( N*2+1 );
|
||||
indices1.push_back( make_index( 0 ) );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices1.push_back( make_index( i ) );
|
||||
}
|
||||
|
||||
indices2.reserve( N*2+1 );
|
||||
indices2.push_back( make_index( 0 ) );
|
||||
|
||||
{
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices2.push_back( make_random_index( static_cast<std::uint32_t>( rng() ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices1[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices2[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Random insert", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::uint32_t s;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices1[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices2[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Random lookup", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
auto it = map.begin();
|
||||
|
||||
while( it != map.end() )
|
||||
{
|
||||
if( it->second & 1 )
|
||||
{
|
||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
||||
{
|
||||
map.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
it = map.erase( it );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices1[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices2[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Random erase", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::string_view, std::uint32_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_insert( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_lookup( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
test_lookup( map, t1 );
|
||||
test_erase( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map =
|
||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
|
||||
template<> struct fnv1a_hash_impl<32>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x01000193ul;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct fnv1a_hash_impl<64>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x00000100000001B3ull;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
template<class K, class V> using std_unordered_map_fnv1a =
|
||||
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map_fnv1a =
|
||||
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
||||
absl::node_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map_fnv1a =
|
||||
absl::flat_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,352 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
constexpr unsigned N = 2'000'000;
|
||||
constexpr int K = 10;
|
||||
|
||||
static std::vector< std::uint32_t > indices1, indices2, indices3;
|
||||
|
||||
static void init_indices()
|
||||
{
|
||||
indices1.push_back( 0 );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices1.push_back( i );
|
||||
}
|
||||
|
||||
indices2.push_back( 0 );
|
||||
|
||||
{
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices2.push_back( static_cast<std::uint32_t>( rng() ) );
|
||||
}
|
||||
}
|
||||
|
||||
indices3.push_back( 0 );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices3.push_back( boost::endian::endian_reverse( static_cast<std::uint32_t>( i ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices1[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices2[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Random insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices3[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed insert", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::uint32_t s;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices1[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices2[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Random lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices3[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed lookup", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
auto it = map.begin();
|
||||
|
||||
while( it != map.end() )
|
||||
{
|
||||
if( it->second & 1 )
|
||||
{
|
||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
||||
{
|
||||
map.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
it = map.erase( it );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices1[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices2[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Random erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices3[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed erase", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::uint32_t, std::uint32_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_insert( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_lookup( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
test_lookup( map, t1 );
|
||||
test_erase( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map =
|
||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,362 @@
|
||||
// Copyright 2021 Peter Dimov.
|
||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint64_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
constexpr unsigned N = 2'000'000;
|
||||
constexpr int K = 10;
|
||||
|
||||
static std::vector< std::uint64_t > indices1, indices2, indices3;
|
||||
|
||||
static void init_indices()
|
||||
{
|
||||
indices1.push_back( 0 );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices1.push_back( i );
|
||||
}
|
||||
|
||||
indices2.push_back( 0 );
|
||||
|
||||
{
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices2.push_back( rng() );
|
||||
}
|
||||
}
|
||||
|
||||
indices3.push_back( 0 );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices3.push_back( boost::endian::endian_reverse( static_cast<std::uint64_t>( i ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices1[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices2[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Random insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices3[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed insert", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::uint64_t s;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices1[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices2[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Random lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices3[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed lookup", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
auto it = map.begin();
|
||||
|
||||
while( it != map.end() )
|
||||
{
|
||||
if( it->second & 1 )
|
||||
{
|
||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
||||
{
|
||||
map.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
it = map.erase( it );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices1[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices2[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Random erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices3[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed erase", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::uint64_t, std::uint64_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_insert( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_lookup( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
test_lookup( map, t1 );
|
||||
test_erase( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map =
|
||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
#if defined(BOOST_LIBSTDCXX_VERSION) && __SIZE_WIDTH__ == 32
|
||||
|
||||
// Pathological behavior:
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104945
|
||||
|
||||
#else
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
|
||||
#endif
|
||||
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,403 @@
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint64_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
constexpr unsigned N = 2'000'000;
|
||||
constexpr int K = 10;
|
||||
|
||||
struct uuid
|
||||
{
|
||||
unsigned char data[ 16 ];
|
||||
|
||||
uuid(): data()
|
||||
{
|
||||
}
|
||||
|
||||
uuid( std::uint64_t low, std::uint64_t high ) noexcept
|
||||
{
|
||||
boost::endian::store_little_u64( data + 0, low );
|
||||
boost::endian::store_little_u64( data + 8, high );
|
||||
}
|
||||
|
||||
inline friend std::size_t hash_value( uuid const& u ) noexcept
|
||||
{
|
||||
std::uint64_t low = boost::endian::load_little_u64( u.data + 0 );
|
||||
std::uint64_t high = boost::endian::load_little_u64( u.data + 8 );
|
||||
|
||||
std::size_t r = 0;
|
||||
|
||||
boost::hash_combine( r, low );
|
||||
boost::hash_combine( r, high );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline friend bool operator==( uuid const& u1, uuid const& u2 ) noexcept
|
||||
{
|
||||
return std::memcmp( u1.data, u2.data, 16 ) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct hash< ::uuid >
|
||||
{
|
||||
std::size_t operator()( uuid const& u ) const noexcept
|
||||
{
|
||||
return hash_value( u );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
static std::vector< uuid > indices1, indices2, indices3;
|
||||
|
||||
static void init_indices()
|
||||
{
|
||||
indices1.push_back( {} );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices1.push_back( { i, 0 } );
|
||||
}
|
||||
|
||||
indices2.push_back( {} );
|
||||
|
||||
{
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices2.push_back( { rng(), rng() } );
|
||||
}
|
||||
}
|
||||
|
||||
indices3.push_back( {} );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
uuid k( i, 0 );
|
||||
std::reverse( k.data + 0, k.data + 16 );
|
||||
|
||||
indices3.push_back( k );
|
||||
}
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices1[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices2[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Random insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices3[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed insert", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::uint64_t s;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices1[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices2[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Random lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices3[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed lookup", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
auto it = map.begin();
|
||||
|
||||
while( it != map.end() )
|
||||
{
|
||||
if( it->second & 1 )
|
||||
{
|
||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
||||
{
|
||||
map.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
it = map.erase( it );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices1[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices2[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Random erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices3[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed erase", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<uuid, std::uint64_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_insert( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_lookup( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
test_lookup( map, t1 );
|
||||
test_erase( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map =
|
||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,386 @@
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::size_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
static std::vector<std::string> words;
|
||||
|
||||
static void init_words()
|
||||
{
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
|
||||
|
||||
#else
|
||||
|
||||
char const* fn = "enwik8"; // ditto
|
||||
|
||||
#endif
|
||||
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::ifstream is( fn );
|
||||
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
|
||||
|
||||
boost::regex re( "[a-zA-Z]+");
|
||||
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
|
||||
|
||||
words.assign( it, end );
|
||||
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_word_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
++map[ word ];
|
||||
++s;
|
||||
}
|
||||
|
||||
print_time( t1, "Word count", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_contains( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
std::string_view w2( word );
|
||||
w2.remove_prefix( 1 );
|
||||
|
||||
s += map.contains( w2 );
|
||||
}
|
||||
|
||||
print_time( t1, "Contains", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
std::string_view w2( word );
|
||||
w2.remove_prefix( 1 );
|
||||
|
||||
s += map.count( w2 );
|
||||
}
|
||||
|
||||
print_time( t1, "Count", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t max = 0;
|
||||
std::string_view word;
|
||||
|
||||
for( auto const& x: map )
|
||||
{
|
||||
if( x.second > max )
|
||||
{
|
||||
word = x.first;
|
||||
max = x.second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and find max element", max, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::string_view, std::size_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_word_count( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_contains( map, t1 );
|
||||
test_count( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map =
|
||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
|
||||
template<> struct fnv1a_hash_impl<32>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x01000193ul;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct fnv1a_hash_impl<64>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x00000100000001B3ull;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
template<class K, class V> using std_unordered_map_fnv1a =
|
||||
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map_fnv1a =
|
||||
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
||||
absl::node_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map_fnv1a =
|
||||
absl::flat_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
int main()
|
||||
{
|
||||
init_words();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,244 @@
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::size_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
static std::vector<std::string> words;
|
||||
|
||||
static void init_words()
|
||||
{
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
|
||||
|
||||
#else
|
||||
|
||||
char const* fn = "enwik8"; // ditto
|
||||
|
||||
#endif
|
||||
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::ifstream is( fn );
|
||||
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
|
||||
|
||||
boost::regex re( "[a-zA-Z]+");
|
||||
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
|
||||
|
||||
words.assign( it, end );
|
||||
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_word_size( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( auto const& word: words )
|
||||
{
|
||||
++map[ word.size() ];
|
||||
}
|
||||
|
||||
print_time( t1, "Word size count", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& x: map )
|
||||
{
|
||||
s += x.second;
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and sum counts", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::size_t, std::size_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_word_size( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_iteration( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_node_map =
|
||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
init_words();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -1,68 +1,21 @@
|
||||
|
||||
# Copyright 2005 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 boostbook ;
|
||||
using quickbook ;
|
||||
import asciidoctor ;
|
||||
|
||||
path-constant images_location : ../ ;
|
||||
path-constant admonishment_location : ../../../../doc/src/images ;
|
||||
html unordered.html : unordered.adoc ;
|
||||
|
||||
xml unordered : unordered.qbk ;
|
||||
boostbook standalone : unordered :
|
||||
<xsl:param>chunk.first.sections=1
|
||||
<xsl:param>chunk.section.depth=2
|
||||
<xsl:param>generate.section.toc.level=2
|
||||
<xsl:param>toc.section.depth=1
|
||||
<xsl:param>toc.max.depth=1
|
||||
install html_ : unordered.html : <location>html ;
|
||||
|
||||
<xsl:param>boost.compact.typedef=0
|
||||
<xsl:param>boost.compact.function=0
|
||||
<xsl:param>boost.compact.enum=0
|
||||
pdf unordered.pdf : unordered.adoc ;
|
||||
explicit unordered.pdf ;
|
||||
|
||||
# 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
|
||||
# TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9!
|
||||
<format>pdf:<xsl:param>fop.extensions=0
|
||||
# No indent on body text:
|
||||
<format>pdf:<xsl:param>body.start.indent=0pt
|
||||
# Margin size:
|
||||
<format>pdf:<xsl:param>page.margin.inner=0.5in
|
||||
# Margin size:
|
||||
<format>pdf:<xsl:param>page.margin.outer=0.5in
|
||||
# Paper type = A4
|
||||
<format>pdf:<xsl:param>paper.type=A4
|
||||
# Yes, we want graphics for admonishments:
|
||||
<xsl:param>admon.graphics=1
|
||||
# Set this one for PDF generation *only*:
|
||||
# default png graphics are awful in PDF form,
|
||||
# better use SVG's instead:
|
||||
<format>pdf:<xsl:param>admon.graphics.extension=".svg"
|
||||
<format>pdf:<xsl:param>use.role.for.mediaobject=1
|
||||
<format>pdf:<xsl:param>preferred.mediaobject.role=print
|
||||
<format>pdf:<xsl:param>img.src.path=$(images_location)/
|
||||
#<format>pdf:<xsl:param>admon.graphics.path=$(admonishment_location)
|
||||
<format>pdf:<xsl:param>draft.mode="no"
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/unordered/doc/html
|
||||
;
|
||||
install pdf_ : unordered.pdf : <location>pdf ;
|
||||
explicit pdf_ ;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: unordered
|
||||
:
|
||||
:
|
||||
: ;
|
||||
alias boostdoc ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
alias boostrelease : html_ ;
|
||||
explicit boostrelease ;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<!--
|
||||
Copyright Daniel James 2008-2009
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
<section id="unordered.bibliography">
|
||||
<title>Bibliography</title>
|
||||
<bibliography>
|
||||
<biblioentry>
|
||||
<biblioset relation="journal">
|
||||
<title>C/C++ Users Journal</title>
|
||||
<date>February, 2006</date>
|
||||
</biblioset>
|
||||
<biblioset relation="article">
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Pete</firstname>
|
||||
<surname>Becker</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<title><ulink url="http://www.ddj.com/cpp/184402066">STL and TR1: Part III - Unordered containers</ulink></title>
|
||||
</biblioset>
|
||||
<para>An introducation to the standard unordered containers.</para>
|
||||
</biblioentry>
|
||||
</bibliography>
|
||||
</section>
|
||||
@@ -1,171 +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) ]
|
||||
|
||||
[section:buckets The Data Structure]
|
||||
|
||||
The containers are made up of a number of 'buckets', each of which can contain
|
||||
any number of elements. For example, the following diagram shows an [classref
|
||||
boost::unordered_set unordered_set] with 7 buckets containing 5 elements, `A`,
|
||||
`B`, `C`, `D` and `E` (this is just for illustration, containers will typically
|
||||
have more buckets).
|
||||
|
||||
[diagram buckets]
|
||||
|
||||
In order to decide which bucket to place an element in, the container applies
|
||||
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
|
||||
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
|
||||
to the key to find the correct bucket. Then the key is compared with the
|
||||
elements in the bucket to find any elements that match (using the equality
|
||||
predicate `Pred`). If the hash function has worked well the elements will be
|
||||
evenly distributed amongst the buckets so only a small number of elements will
|
||||
need to be examined.
|
||||
|
||||
There is [link unordered.hash_equality more information on hash functions and
|
||||
equality predicates in the next section].
|
||||
|
||||
You can see in the diagram that `A` & `D` have been placed in the same bucket.
|
||||
When looking for elements in this bucket up to 2 comparisons are made, making
|
||||
the search slower. This is known as a collision. To keep things fast we try to
|
||||
keep collisions to a minimum.
|
||||
|
||||
'''
|
||||
<table frame="all"><title>Methods for Accessing Buckets</title>
|
||||
<tgroup cols="2">
|
||||
<thead><row>
|
||||
<entry><para>Method</para></entry>
|
||||
<entry><para>Description</para></entry>
|
||||
</row></thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>'''`size_type bucket_count() const`'''</entry>
|
||||
<entry>'''The number of buckets.'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`size_type max_bucket_count() const`'''</entry>
|
||||
<entry>'''An upper bound on the number of buckets.'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`size_type bucket_size(size_type n) const`'''</entry>
|
||||
<entry>'''The number of elements in bucket `n`.'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`size_type bucket(key_type const& k) const`'''</entry>
|
||||
<entry>'''Returns the index of the bucket which would contain k'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`local_iterator begin(size_type n);`'''</entry>
|
||||
<entry morerows='5'>'''Return begin and end iterators for bucket `n`.'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`local_iterator end(size_type n);`'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`const_local_iterator begin(size_type n) const;`'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`const_local_iterator end(size_type n) const;`'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`const_local_iterator cbegin(size_type n) const;`'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`const_local_iterator cend(size_type n) const;`'''</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
'''
|
||||
|
||||
[h2 Controlling the number of buckets]
|
||||
|
||||
As more elements are added to an unordered associative container, the number
|
||||
of elements in the buckets will increase causing performance to degrade.
|
||||
To combat this the containers increase the bucket count as elements are inserted.
|
||||
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
|
||||
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.
|
||||
|
||||
You can't control the bucket count directly but there are two ways to
|
||||
influence it:
|
||||
|
||||
* Specify the minimum number of buckets when constructing a container or
|
||||
when calling `rehash`.
|
||||
* Suggest a maximum load factor by calling `max_load_factor`.
|
||||
|
||||
`max_load_factor` doesn't let you set the maximum load factor yourself, it just
|
||||
lets you give a /hint/. And even then, the draft standard doesn't actually
|
||||
require the container to pay much attention to this value. The only time the
|
||||
load factor is /required/ to be less than the maximum is following a call to
|
||||
`rehash`. But most implementations will try to keep the number of elements
|
||||
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:bucket_size Methods for Controlling Bucket Size
|
||||
[[Method] [Description]]
|
||||
|
||||
[
|
||||
[`X(size_type n)`]
|
||||
[Construct an empty container with at least `n` buckets (`X` is the container type).]
|
||||
]
|
||||
[
|
||||
[`X(InputIterator i, InputIterator j, size_type n)`]
|
||||
[Construct an empty container with at least `n` buckets and insert elements
|
||||
from the range \[`i`, `j`) (`X` is the container type).]
|
||||
]
|
||||
[
|
||||
[`float load_factor() const`]
|
||||
[The average number of elements per bucket.]
|
||||
]
|
||||
[
|
||||
[`float max_load_factor() const`]
|
||||
[Returns the current maximum load factor.]
|
||||
]
|
||||
[
|
||||
[`float max_load_factor(float z)`]
|
||||
[Changes the container's maximum load factor, using `z` as a hint.]
|
||||
]
|
||||
[
|
||||
[`void rehash(size_type n)`]
|
||||
[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.]
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
[h2 Iterator Invalidation]
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
In a similar manner to using `reserve` for `vector`s, it can be a good idea
|
||||
to call `rehash` before inserting a large number of elements. This will get
|
||||
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);
|
||||
|
||||
[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.]
|
||||
|
||||
[endsect]
|
||||
@@ -1,161 +0,0 @@
|
||||
[/ 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 Interface differences.
|
||||
[[Associative Containers] [Unordered Associative Containers]]
|
||||
|
||||
[
|
||||
[Parameterized by an ordering relation `Compare`]
|
||||
[Parameterized by a function object `Hash` and an equivalence relation
|
||||
`Pred`]
|
||||
]
|
||||
[
|
||||
[Keys can be compared using `key_compare` which is accessed by member function `key_comp()`,
|
||||
values can be compared using `value_compare` which is accessed by member function `value_comp()`.]
|
||||
[Keys can be hashed using `hasher` which is accessed by member function `hash_function()`,
|
||||
and checked for equality using `key_equal` which is accessed by member function `key_eq()`.
|
||||
There is no function object for compared or hashing values.]
|
||||
]
|
||||
[
|
||||
[Constructors have optional extra parameters for the comparison object.]
|
||||
[Constructors have optional extra parameters for the initial minimum
|
||||
number of buckets, a hash function and an equality object.]
|
||||
]
|
||||
|
||||
[
|
||||
[Keys `k1`, `k2` are considered equivalent if
|
||||
`!Compare(k1, k2) && !Compare(k2, k1)`]
|
||||
[Keys `k1`, `k2` are considered equivalent if `Pred(k1, k2)`]
|
||||
]
|
||||
[
|
||||
[Member function `lower_bound(k)` and `upper_bound(k)`]
|
||||
[No equivalent. Since the elements aren't ordered `lower_bound` and
|
||||
`upper_bound` would be meaningless.]
|
||||
]
|
||||
[
|
||||
[`equal_range(k)` returns an empty range at the position that k
|
||||
would be inserted if k isn't present in the container.]
|
||||
[`equal_range(k)` returns a range at the end of the container if
|
||||
k isn't present in the container. It can't return a positioned
|
||||
range as k could be inserted into multiple place. To find out the
|
||||
bucket that k would be inserted into use `bucket(k)`. But remember
|
||||
that an insert can cause the container to rehash - meaning that the
|
||||
element can be inserted into a different bucket.]
|
||||
]
|
||||
[
|
||||
[`iterator`, `const_iterator` are of the bidirectional category.]
|
||||
[`iterator`, `const_iterator` are of at least the forward category.]
|
||||
]
|
||||
[
|
||||
[Iterators, pointers and references to the container's elements are
|
||||
never invalidated.]
|
||||
[[link unordered.buckets.iterator_invalidation Iterators can
|
||||
be invalidated by calls to insert or rehash]. Pointers and
|
||||
references to the container's elements are never invalidated.]
|
||||
]
|
||||
[
|
||||
[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
|
||||
are always adjacent.]
|
||||
]
|
||||
[
|
||||
[No equivalent]
|
||||
[Local iterators can be used to iterate through individual buckets.
|
||||
(The order of local iterators and iterators aren't
|
||||
required to have any correspondence.)]
|
||||
]
|
||||
[
|
||||
[Can be compared using the `==`, `!=`, `<`, `<=`, `>`, `>=` operators.]
|
||||
[Can be compared using the `==` and `!=` operators.]
|
||||
]
|
||||
[
|
||||
[]
|
||||
[When inserting with a hint, implementations are permitted to ignore
|
||||
the hint.]
|
||||
]
|
||||
[
|
||||
[`erase` never throws an exception]
|
||||
[The containers' hash or predicate function can throw exceptions
|
||||
from `erase`]
|
||||
]
|
||||
]
|
||||
|
||||
[table:complexity_guarantees Complexity Guarantees
|
||||
[[Operation] [Associative Containers] [Unordered Associative Containers]]
|
||||
[
|
||||
[Construction of empty container]
|
||||
[constant]
|
||||
[O(/n/) where /n/ is the minimum number of buckets.]
|
||||
]
|
||||
[
|
||||
[Construction of container from a range of /N/ elements]
|
||||
[O(/N/ log /N/), O(/N/) if the range is sorted with `value_comp()`]
|
||||
[Average case O(/N/), worst case
|
||||
O(/N/'''<superscript>2</superscript>''')]
|
||||
]
|
||||
[
|
||||
[Insert a single element]
|
||||
[logarithmic]
|
||||
[Average case constant, worst case linear]
|
||||
]
|
||||
[
|
||||
[Insert a single element with a hint]
|
||||
[Amortized constant if t elements inserted right after hint,
|
||||
logarithmic otherwise]
|
||||
[Average case constant, worst case linear (ie. the same as
|
||||
a normal insert).]
|
||||
]
|
||||
[
|
||||
[Inserting a range of /N/ elements]
|
||||
[ /N/ log(`size()`+/N/) ]
|
||||
[Average case O(/N/), worst case O(/N/ * `size()`)]
|
||||
]
|
||||
[
|
||||
[Erase by key, `k`]
|
||||
[O(log(`size()`) + `count(k)`)]
|
||||
[Average case: O(`count(k)`), Worst case: O(`size()`)]
|
||||
]
|
||||
[
|
||||
[Erase a single element by iterator]
|
||||
[Amortized constant]
|
||||
[Average case: O(1), Worst case: O(`size()`)]
|
||||
]
|
||||
[
|
||||
[Erase a range of /N/ elements]
|
||||
[O(log(`size()`) + /N/)]
|
||||
[Average case: O(/N/), Worst case: O(`size()`)]
|
||||
]
|
||||
[
|
||||
[Clearing the container]
|
||||
[O(`size()`)]
|
||||
[O(`size()`)]
|
||||
]
|
||||
[
|
||||
[Find]
|
||||
[logarithmic]
|
||||
[Average case: O(1), Worst case: O(`size()`)]
|
||||
]
|
||||
[/ TODO: Average case is probably wrong. ]
|
||||
[
|
||||
[Count]
|
||||
[O(log(`size()`) + `count(k)`)]
|
||||
[Average case: O(1), Worst case: O(`size()`)]
|
||||
]
|
||||
[
|
||||
[`equal_range(k)`]
|
||||
[logarithmic]
|
||||
[Average case: O(`count(k)`), Worst case: O(`size()`)]
|
||||
]
|
||||
[
|
||||
[`lower_bound`,`upper_bound`]
|
||||
[logarithmic]
|
||||
[n/a]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 15 KiB |