Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62c8ac3e5d | ||
|
|
1d7e93251c | ||
|
|
92fa4691d1 | ||
|
|
a20fdf4713 | ||
|
|
570dedf1c3 | ||
|
|
59e5c873ad | ||
|
|
8dbcdf9991 | ||
|
|
cd43b50068 | ||
|
|
c0413a26f9 | ||
|
|
b2d3d86e0c | ||
|
|
bc7552f4a8 | ||
|
|
28ae13092f | ||
|
|
1f561da43f | ||
|
|
ef8dcda196 | ||
|
|
cf9eb892cf | ||
|
|
ffa1e2e59c | ||
|
|
9549e82b04 | ||
|
|
50261e390e | ||
|
|
618fc99cda | ||
|
|
a9fc7e15f8 | ||
|
|
6b064870f5 | ||
|
|
d78c50be3b | ||
|
|
c96cea5a13 | ||
|
|
51d4e930f5 | ||
|
|
e650addfe4 | ||
|
|
30afcb45d8 | ||
|
|
e10c3586a3 | ||
|
|
836d892832 | ||
|
|
826d251ffe | ||
|
|
510cd062ba | ||
|
|
2695cd6f3e | ||
|
|
f6e3cbbb65 | ||
|
|
f172bbaad2 | ||
|
|
9176953a8e | ||
|
|
ae6b87d646 | ||
|
|
f719b2387a | ||
|
|
5bfa8321d0 | ||
|
|
e99fd23e69 | ||
|
|
5057366fb2 | ||
|
|
44801b8b91 | ||
|
|
9eabc86bdd | ||
|
|
fbc8f407eb | ||
|
|
09a8b93634 | ||
|
|
2caa7b77e7 | ||
|
|
c057247126 | ||
|
|
0899be21c3 | ||
|
|
c29c9f9ccd | ||
|
|
c12f698f32 | ||
|
|
d6a8a6d159 | ||
|
|
7bf325f91a | ||
|
|
fdfff0c5c5 | ||
|
|
4409f613e0 | ||
|
|
9de644b0f3 | ||
|
|
3e36363d28 | ||
|
|
4f1d1a949c | ||
|
|
e52f3b8b30 | ||
|
|
36916e7b3d | ||
|
|
ba778e9bd2 | ||
|
|
df7112489a | ||
|
|
d9c203736f | ||
|
|
2b61ffa784 | ||
|
|
ba85640172 | ||
|
|
4d21ad5050 | ||
|
|
aae14de62b | ||
|
|
70fa621745 | ||
|
|
e97f4f7f41 | ||
|
|
7a08ddce9e | ||
|
|
e19c9d31a8 | ||
|
|
51ae5f9f0c | ||
|
|
22e8133f95 | ||
|
|
c2e19fed01 | ||
|
|
274afc9978 | ||
|
|
0c337836ca | ||
|
|
1a3e694e20 | ||
|
|
a0572b63b1 | ||
|
|
1765d8ef06 | ||
|
|
1e00a102e8 | ||
|
|
61f8dcdbae | ||
|
|
39eeb3aec7 | ||
|
|
2178dcfcab | ||
|
|
f8b4f44105 | ||
|
|
9c2468c2b7 | ||
|
|
3d5cc55d0a | ||
|
|
5b9cccd2dd | ||
|
|
103b2ab79b | ||
|
|
05f1cd784c | ||
|
|
6e6754f84e | ||
|
|
33ef448a86 | ||
|
|
8ce59c2e9d | ||
|
|
85a363d325 | ||
|
|
7dc1a9dc0e | ||
|
|
983d90b731 | ||
|
|
f307762801 | ||
|
|
7924798e7a | ||
|
|
e46bbaffb9 | ||
|
|
0171c49413 | ||
|
|
a79cd9da97 | ||
|
|
408959c927 | ||
|
|
ac4d93fe29 | ||
|
|
82d224fa66 | ||
|
|
a5b6d8e391 | ||
|
|
7f79abec3f | ||
|
|
ca8d4aa97a | ||
|
|
690cef561c | ||
|
|
16ac4c556b | ||
|
|
3c175b9199 | ||
|
|
a3827cc384 | ||
|
|
353daecbd1 | ||
|
|
368392fb8f | ||
|
|
57441b2fc1 | ||
|
|
b225600238 | ||
|
|
6b361e0d0c | ||
|
|
08668aa02b | ||
|
|
3d3eb6f1d2 | ||
|
|
9bd820c652 | ||
|
|
0e960ec23f | ||
|
|
ca65d81b60 | ||
|
|
23624a1d73 | ||
|
|
3ac08b0395 | ||
|
|
dedb79dbc5 | ||
|
|
154b503bc6 | ||
|
|
5c612ce521 | ||
|
|
80582ac5ce | ||
|
|
8e6af3bfeb | ||
|
|
61671d1b18 | ||
|
|
aa3ad973d0 | ||
|
|
a19a010d1e | ||
|
|
36003b6bb3 | ||
|
|
3c83e4088c | ||
|
|
357feb9532 | ||
|
|
7e234cba65 | ||
|
|
0535ceeaeb | ||
|
|
e688f0b1df | ||
|
|
a950e15625 | ||
|
|
cf8b198dac | ||
|
|
c75d5da02d | ||
|
|
cdffb15066 | ||
|
|
cd0ad0dba9 | ||
|
|
d3be5dba96 | ||
|
|
cb94a26a9f | ||
|
|
3c8b238e75 | ||
|
|
74202d52b3 | ||
|
|
603c92cd0e | ||
|
|
e514d74f43 | ||
|
|
970161464a | ||
|
|
3e7de27c00 | ||
|
|
e28d403216 | ||
|
|
fdeb9f1322 | ||
|
|
76fad21103 | ||
|
|
5d4fa31083 | ||
|
|
c3858f4e63 | ||
|
|
2e0fc21878 | ||
|
|
4b71bbec7e | ||
|
|
052989a5a2 | ||
|
|
60cfc63c4e | ||
|
|
60ef4c7f06 | ||
|
|
58fc40d0f1 | ||
|
|
3d7e9e7c03 | ||
|
|
52e745f905 | ||
|
|
8433fc178c | ||
|
|
59807baa18 | ||
|
|
9b5b15e8cb | ||
|
|
2c54b63c51 | ||
|
|
e4d1167274 | ||
|
|
2f10aba390 | ||
|
|
a044fadec8 | ||
|
|
0edb6165b5 | ||
|
|
7d262f2450 | ||
|
|
fa30328572 | ||
|
|
b0cff7c6ac | ||
|
|
50da9e803c | ||
|
|
26252fedf5 | ||
|
|
2dcda90c7b | ||
|
|
b7d79c0a83 | ||
|
|
ae285c0a01 | ||
|
|
07db846f3b | ||
|
|
3b6907b743 | ||
|
|
82e49c6214 | ||
|
|
8e9aa9cac4 | ||
|
|
5cd6c1dd36 | ||
|
|
a98ce5ea91 | ||
|
|
a4bb0fab8f | ||
|
|
7b2e242c94 | ||
|
|
5fd6352a4e | ||
|
|
a82f2ba065 | ||
|
|
3377acd9e6 | ||
|
|
709168652a | ||
|
|
e25e9ba29b | ||
|
|
ed5eac6e9d | ||
|
|
651768f012 | ||
|
|
88c0a881da | ||
|
|
5b9dd504e5 | ||
|
|
165ec09061 | ||
|
|
6cc972bab2 | ||
|
|
333047fc4c | ||
|
|
3e4a5932c2 | ||
|
|
e2f6b81a03 | ||
|
|
0231aad947 | ||
|
|
6636800c5b | ||
|
|
d1f41de0cb | ||
|
|
c4d339cb62 | ||
|
|
56b2adc57d | ||
|
|
a73bee2650 | ||
|
|
517da1b999 | ||
|
|
25497bd96f | ||
|
|
d12b1edc39 | ||
|
|
0515cfd068 | ||
|
|
e84bc9fc0d | ||
|
|
d85df43329 | ||
|
|
16e2e07d41 | ||
|
|
57fcb4012b | ||
|
|
5be981def3 | ||
|
|
493e38abfc | ||
|
|
6e006d216b | ||
|
|
da613ad188 | ||
|
|
3dad326bea | ||
|
|
480a791f4c | ||
|
|
753c46ef14 | ||
|
|
f2d5de252b | ||
|
|
0cb1a8054f | ||
|
|
07eb5697ab | ||
|
|
e4dc06a0e2 | ||
|
|
cd2012f33d | ||
|
|
9eba30648d | ||
|
|
7e70371197 | ||
|
|
527f6d8d9a | ||
|
|
9ebc12a98f | ||
|
|
bb21d9a6ad | ||
|
|
ad39cdd393 | ||
|
|
0de771036b | ||
|
|
6d6afa4cfd | ||
|
|
7546cbedd2 | ||
|
|
8d5962eefd | ||
|
|
8597b0b8c0 | ||
|
|
c625c39883 | ||
|
|
bce86460fe | ||
|
|
f002eebc83 | ||
|
|
139da2e49f | ||
|
|
91d40a0f43 | ||
|
|
25fe26deaa | ||
|
|
cd357c5eb7 | ||
|
|
561f67b3b9 | ||
|
|
15a02e3306 | ||
|
|
944d29e8bc | ||
|
|
aefba70c1e | ||
|
|
c9ed4ba820 | ||
|
|
df97ea848c | ||
|
|
93d810421d | ||
|
|
f560839516 | ||
|
|
8a9d5f6a00 | ||
|
|
5f05c1e169 | ||
|
|
3df2408ffb | ||
|
|
ffc2ec8c4b | ||
|
|
b0ebbb306e | ||
|
|
c3574aa290 | ||
|
|
eabc867c2a | ||
|
|
a03b2e80c6 | ||
|
|
c4f23640d5 | ||
|
|
a42b854f14 | ||
|
|
9aa08bfc59 | ||
|
|
06b79a6caa | ||
|
|
6d533bd52a | ||
|
|
1b4c608087 | ||
|
|
6ccc81fd92 | ||
|
|
6f7d3fcd79 | ||
|
|
7484dee707 | ||
|
|
a580aaac83 | ||
|
|
52bef353e0 | ||
|
|
826ecf76c0 | ||
|
|
2cf5bff32d | ||
|
|
1377d7a1c2 | ||
|
|
ab9284ca20 | ||
|
|
5dab01c1c7 | ||
|
|
f9c434401b | ||
|
|
76b9f9a715 | ||
|
|
2ee82c478b | ||
|
|
211121435d | ||
|
|
fffd1702a5 | ||
|
|
9aa99bf230 | ||
|
|
1671ca8d67 | ||
|
|
ad16b310e1 | ||
|
|
4dbcfd25b3 | ||
|
|
01167b09c4 | ||
|
|
15d0b86c62 | ||
|
|
edbcecb272 | ||
|
|
1689db7b9c | ||
|
|
f5bc8796f7 | ||
|
|
e893560a48 | ||
|
|
a4ff7c71f2 | ||
|
|
9f780805f0 | ||
|
|
749273d1bb | ||
|
|
d8fd2e3e69 | ||
|
|
d443a84254 | ||
|
|
ef614b19ee | ||
|
|
1c5c4aa50f | ||
|
|
5533ffffaa | ||
|
|
34c990e259 | ||
|
|
5f0b6b9f26 | ||
|
|
26eb882a30 | ||
|
|
4d0e799c7a | ||
|
|
6801f688a4 | ||
|
|
bdf29af9e9 | ||
|
|
79dabfc52f | ||
|
|
de2268c406 | ||
|
|
85ea1f40dc | ||
|
|
f89ba94689 | ||
|
|
0279dcc3cc | ||
|
|
62c8e005bb | ||
|
|
2a28f8d407 | ||
|
|
9802fc5098 | ||
|
|
f372a72fd8 | ||
|
|
9d661852b2 | ||
|
|
b343d356c3 | ||
|
|
2e4404ca7e | ||
|
|
29eebaf38d | ||
|
|
d0d69aebfa | ||
|
|
477c5853f1 | ||
|
|
55e7b3083a | ||
|
|
0b9e27fb7f | ||
|
|
36ac6d5104 | ||
|
|
d898d6d4cc | ||
|
|
e7388929c4 | ||
|
|
45f8b31efc | ||
|
|
ebf440731d | ||
|
|
501a4a65ec | ||
|
|
800d03f728 | ||
|
|
19ff6bfeac | ||
|
|
24f5739a3b | ||
|
|
b658598e02 | ||
|
|
47343a2893 | ||
|
|
c1f99359be | ||
|
|
bd89e162fc | ||
|
|
983a63fbbc | ||
|
|
978e0ea5d7 | ||
|
|
85c4b50b6f | ||
|
|
e77aec4619 | ||
|
|
d67e084010 | ||
|
|
b0a74f162e | ||
|
|
d92126b97e | ||
|
|
c055358fa2 | ||
|
|
9f89148b69 | ||
|
|
ef1145603a | ||
|
|
d169a06f79 | ||
|
|
8e15a8cfe9 | ||
|
|
6466cefbf4 | ||
|
|
bec9a897c9 | ||
|
|
37d47cb0f1 | ||
|
|
0854136005 | ||
|
|
9427931e45 | ||
|
|
6aa28b4cfe | ||
|
|
a29682ca29 | ||
|
|
f5afd6e275 | ||
|
|
7b5fd14bcf | ||
|
|
22ce001f03 | ||
|
|
6f761091cc | ||
|
|
bb9e0e4f6e | ||
|
|
5e658a81fe | ||
|
|
ddc722bf78 | ||
|
|
0818d0ac7c | ||
|
|
2f315793cd | ||
|
|
067a034bc9 | ||
|
|
201cc45fd8 | ||
|
|
7a270ffacb | ||
|
|
27bb62533a | ||
|
|
032388b790 | ||
|
|
f1e2f81e79 | ||
|
|
54d4b80368 | ||
|
|
8a0a556604 | ||
|
|
895f362628 | ||
|
|
d24b52586d | ||
|
|
d76585cb0e | ||
|
|
fb44be6efe | ||
|
|
0b6a5aaa97 | ||
|
|
c00fdc65a2 | ||
|
|
ab7490eb8a | ||
|
|
1a46c0cd3f | ||
|
|
22f595c015 | ||
|
|
68c76ad146 | ||
|
|
0b18792b96 | ||
|
|
464e8e5f8f | ||
|
|
45410f3f0c | ||
|
|
556e706343 | ||
|
|
1e534bd307 | ||
|
|
7a517ee3ae | ||
|
|
9bb1957afa | ||
|
|
86f942ee5f | ||
|
|
a23df528e4 | ||
|
|
0e9af6dfac | ||
|
|
99a8db1111 | ||
|
|
24cdf1ca5c | ||
|
|
f1b794b239 | ||
|
|
b4fdcbc547 | ||
|
|
ce9986f6d8 | ||
|
|
ad4dcae1db | ||
|
|
b3fa63c971 | ||
|
|
364101592b | ||
|
|
5b89196cd7 | ||
|
|
feb8b30048 | ||
|
|
8340cf70fb | ||
|
|
affb3778a0 | ||
|
|
c039f07f2d | ||
|
|
c180981768 | ||
|
|
2cfac5c332 | ||
|
|
8ba489eef3 | ||
|
|
a4cb6e3681 | ||
|
|
379e0be211 | ||
|
|
acb886c391 | ||
|
|
7f26ef0f1c | ||
|
|
1d8e541205 | ||
|
|
a4fa70a478 | ||
|
|
3d3a473716 | ||
|
|
e04b120d41 | ||
|
|
63eee6bba3 | ||
|
|
b396b42808 | ||
|
|
eb8b106f48 | ||
|
|
5d144991cb | ||
|
|
35718ae551 | ||
|
|
1dd9aff402 | ||
|
|
6d47074457 | ||
|
|
1943650ca3 | ||
|
|
5722f19939 | ||
|
|
7cf14b5d8a | ||
|
|
b3a1a75f6f | ||
|
|
eb7556f88f | ||
|
|
805c747c60 | ||
|
|
5f9feb833c | ||
|
|
efef35c1e1 | ||
|
|
b1b32f565d | ||
|
|
f4cd8eaff9 | ||
|
|
2cd5258f89 | ||
|
|
1b206931df | ||
|
|
f68840ef8c | ||
|
|
779c15ec08 | ||
|
|
29bcc00202 | ||
|
|
1ff0d9fac0 | ||
|
|
4488853642 | ||
|
|
d5dc5d083d | ||
|
|
784c42d850 | ||
|
|
8c1eb1fcb5 | ||
|
|
49180bfbe5 | ||
|
|
a3116dd813 | ||
|
|
23df465401 | ||
|
|
966170452f | ||
|
|
eaf7ae7dee | ||
|
|
8a6652646a | ||
|
|
2063bf879d | ||
|
|
2529d4ae49 | ||
|
|
439bc06423 | ||
|
|
ab6c90f42f | ||
|
|
ac9e9a83b9 | ||
|
|
e495b92ae5 | ||
|
|
50b1bedc54 | ||
|
|
4a80ccd5f4 | ||
|
|
6ca65dd60c | ||
|
|
b2be4d5397 | ||
|
|
de34cefa83 | ||
|
|
40c8dbae1e | ||
|
|
18af53cf38 | ||
|
|
8510318ba5 | ||
|
|
6ad02ffe56 | ||
|
|
535e45d564 | ||
|
|
e2c60aa45c | ||
|
|
56d2a74818 | ||
|
|
8a36b5ff15 | ||
|
|
7607645636 | ||
|
|
cbb84accfe | ||
|
|
3e70cf7b5f | ||
|
|
1a7deef735 | ||
|
|
748771ab72 | ||
|
|
6ef279dd2f | ||
|
|
abcf37dc72 | ||
|
|
690b7bf9c1 | ||
|
|
71cec5155a | ||
|
|
d2b0873a95 | ||
|
|
4cecdbb93e | ||
|
|
2abca7d244 | ||
|
|
c26b467e86 | ||
|
|
19514b09b0 | ||
|
|
ab98577deb | ||
|
|
aae5f00dbd | ||
|
|
04706d48b9 | ||
|
|
c7df60c78d | ||
|
|
f03a4503eb | ||
|
|
a6951fe5e3 | ||
|
|
6def48a0d1 | ||
|
|
8b5d1e07ce | ||
|
|
3182c39280 | ||
|
|
e0b5dc2f02 | ||
|
|
6e5181e405 | ||
|
|
75f4f23144 | ||
|
|
bc1402f66a | ||
|
|
fc5ffcb404 | ||
|
|
bd20a021ce | ||
|
|
dfd12107de | ||
|
|
6743cb9456 | ||
|
|
4aa93325e9 | ||
|
|
f2a06ede62 | ||
|
|
a36752b8ce | ||
|
|
3b347f2ba5 | ||
|
|
47296e5c11 | ||
|
|
a24c530ec6 | ||
|
|
7ebe0608ae | ||
|
|
2a3021c021 | ||
|
|
4d313aa72b | ||
|
|
7906a39647 | ||
|
|
86254958f0 | ||
|
|
0089c1af61 | ||
|
|
6b5a3ddef7 | ||
|
|
42c2fd69a2 | ||
|
|
bcb9b831db | ||
|
|
f6483cbb30 | ||
|
|
f742707699 | ||
|
|
aee02d86ab | ||
|
|
dfbf34daf6 | ||
|
|
494cbbecf0 | ||
|
|
a1513777f1 | ||
|
|
9784a16d47 | ||
|
|
a8648e0cc1 | ||
|
|
3f8e93ad7a | ||
|
|
b040bc411f | ||
|
|
ae8c3e5300 | ||
|
|
01d390c3e9 | ||
|
|
56e4cda76c | ||
|
|
c59d585c22 | ||
|
|
81c97682a7 | ||
|
|
a432628df6 | ||
|
|
d16effb4c5 | ||
|
|
6279f98bb5 | ||
|
|
3cbc474e76 | ||
|
|
c80fb7bebe | ||
|
|
68788a6fb8 | ||
|
|
fd3cb50249 | ||
|
|
7e0bd8414d | ||
|
|
70de571dc8 | ||
|
|
cc6da8941c | ||
|
|
d27c448a94 | ||
|
|
06a1590645 | ||
|
|
652653af0b | ||
|
|
c520b7d0be | ||
|
|
4f4605befb | ||
|
|
3f84f54d65 | ||
|
|
bf49b8e933 | ||
|
|
1edb204ec6 | ||
|
|
dd5c9ac8ad | ||
|
|
32b6f82249 | ||
|
|
44b3895698 | ||
|
|
5ce6ccde3d | ||
|
|
ee64e068f9 | ||
|
|
8d89e7c958 | ||
|
|
ef74f8eb55 | ||
|
|
a7749e944f | ||
|
|
18bf06ff5f | ||
|
|
b27f490acb | ||
|
|
e84fa859c6 | ||
|
|
4c57ca69bc | ||
|
|
b0d2557ea1 | ||
|
|
82906e03e9 | ||
|
|
1859868838 | ||
|
|
4ab3a3605b | ||
|
|
279b46b4e2 | ||
|
|
17950c5fe5 | ||
|
|
45b94c8abc | ||
|
|
a98ebd3b20 | ||
|
|
cb7cd1ac67 | ||
|
|
9a41faf40a | ||
|
|
8c44362f74 | ||
|
|
548c0c0c61 | ||
|
|
607221f480 | ||
|
|
160c76361b | ||
|
|
2fadad0c8d | ||
|
|
4d4973abcc | ||
|
|
f8ae9eb677 | ||
|
|
de825203cf | ||
|
|
4f865176d3 | ||
|
|
cb4b43e2e8 | ||
|
|
89b6e1aac0 | ||
|
|
daeaa242b8 | ||
|
|
100af17328 | ||
|
|
7527bfec85 | ||
|
|
f73d25c92d | ||
|
|
9080f5d52f | ||
|
|
6beb142bbe | ||
|
|
9b8b93288a | ||
|
|
6a2a549ec5 | ||
|
|
468b7e7a0c | ||
|
|
fd640e9232 | ||
|
|
d13d7feae3 | ||
|
|
17f69326e2 | ||
|
|
273fcd51b6 | ||
|
|
f4b9185ceb | ||
|
|
b722227b39 | ||
|
|
3d7e2f5c6b | ||
|
|
9369530068 | ||
|
|
4e968c3777 | ||
|
|
9a5302ac19 | ||
|
|
8216ef0f7b | ||
|
|
b897027021 | ||
|
|
6095cf8610 | ||
|
|
e917ac5663 | ||
|
|
2b44892aad | ||
|
|
294e45c7e1 | ||
|
|
467acfdd10 | ||
|
|
d3823951b5 | ||
|
|
cc33079d43 | ||
|
|
78d0bfb286 | ||
|
|
b2f5ae6917 | ||
|
|
9c723da768 | ||
|
|
70c3932f6e | ||
|
|
92bddcaab4 | ||
|
|
79a8401d75 | ||
|
|
570473e465 | ||
|
|
990b7b02d7 | ||
|
|
0b301d1cea | ||
|
|
f35db79792 | ||
|
|
dc1f163716 | ||
|
|
4d6bb407ee | ||
|
|
37cef298c6 | ||
|
|
0396d1f648 | ||
|
|
e694d83cc4 | ||
|
|
19fc150763 | ||
|
|
3784f653d9 | ||
|
|
eb40cff6a1 | ||
|
|
b7f84236d3 | ||
|
|
65e3f1049b | ||
|
|
cc45b9c1fe | ||
|
|
9340c2e55c | ||
|
|
9710e014f2 | ||
|
|
7761fb6bf1 | ||
|
|
2f4df5f67c | ||
|
|
b841f81416 | ||
|
|
72fd53ab44 | ||
|
|
8335bc525b | ||
|
|
9e5d14ce36 | ||
|
|
3bafede8b7 | ||
|
|
3f2904ab0d | ||
|
|
933b495ed1 | ||
|
|
77813adc00 | ||
|
|
ce2adea6c0 | ||
|
|
3ecdfff8f0 | ||
|
|
a103ceb850 | ||
|
|
9f24b89487 | ||
|
|
8be06cadb3 | ||
|
|
c488d979cf | ||
|
|
f4c24f07af | ||
|
|
3d2ce63d63 | ||
|
|
0ac2c62ffe | ||
|
|
6001781e68 | ||
|
|
d90cb7caf3 | ||
|
|
88a4835025 | ||
|
|
75ae7a06e5 | ||
|
|
3885cb29a2 | ||
|
|
bf3ffd1766 | ||
|
|
d884d257bb | ||
|
|
a87cac84dd | ||
|
|
d1ae26f0fd | ||
|
|
9c58e73c37 | ||
|
|
024b62a7a7 | ||
|
|
c59731775e | ||
|
|
4668476c6a | ||
|
|
743959ebde | ||
|
|
dd27fa7e72 | ||
|
|
f2025f83d3 | ||
|
|
8c06b43b2b | ||
|
|
3cde7a1731 | ||
|
|
e9db1d28b8 | ||
|
|
adffaf0e87 | ||
|
|
49a2e600c4 | ||
|
|
0bedcba32b | ||
|
|
c531f805b0 | ||
|
|
da0ab5ea98 | ||
|
|
6774afd751 | ||
|
|
6d489136e7 | ||
|
|
4ea6dbc7fa | ||
|
|
defc58f6a3 | ||
|
|
006d0d16a5 | ||
|
|
b8af8bb344 | ||
|
|
e249be1142 | ||
|
|
05fde6c3cf | ||
|
|
aaa1d7dc4b | ||
|
|
8c479b2e5a | ||
|
|
45d2a529b5 | ||
|
|
7d17223332 | ||
|
|
12bc65b6a8 | ||
|
|
a849d5c031 | ||
|
|
f195b09657 | ||
|
|
439177ec71 | ||
|
|
aadd4f11b1 | ||
|
|
113fdbf388 | ||
|
|
648406a99a | ||
|
|
055e74d350 | ||
|
|
ac3d7568f2 | ||
|
|
6c222b9ad7 | ||
|
|
4426a60904 | ||
|
|
34f70a031f | ||
|
|
79f2f396b9 | ||
|
|
88143f7d52 | ||
|
|
c1261dd0f2 | ||
|
|
8f7a60ea73 | ||
|
|
4758bbd6cc | ||
|
|
3f66325c19 | ||
|
|
6f10d7deb9 | ||
|
|
919900c90a | ||
|
|
e6daaf429c | ||
|
|
1200f30695 | ||
|
|
fca1120990 | ||
|
|
3735704c95 | ||
|
|
8c0c1b3102 | ||
|
|
db192993f1 | ||
|
|
4f44b3f60b | ||
|
|
b196fcc3c0 | ||
|
|
395f1af19e | ||
|
|
d8f761e889 | ||
|
|
563ffb4275 | ||
|
|
9ba2de4b70 | ||
|
|
0ac6a53fe9 | ||
|
|
4431e9f9ae | ||
|
|
48526ff5c7 | ||
|
|
4ee453025c | ||
|
|
1e7b543c0f | ||
|
|
8c2b4f8cf9 | ||
|
|
13cadfa470 | ||
|
|
deb595372b | ||
|
|
01fd5d929e | ||
|
|
2d60bd2c1b | ||
|
|
9655b13203 | ||
|
|
6b97a7436d | ||
|
|
1c792dd0a4 | ||
|
|
dcbd9f496f | ||
|
|
9804120cde | ||
|
|
a9b06718f0 | ||
|
|
963d819e22 | ||
|
|
28847af43f | ||
|
|
130fa36970 | ||
|
|
ab99035291 | ||
|
|
6de43d8a45 | ||
|
|
7b46891622 | ||
|
|
a0a32d8c6c | ||
|
|
1ffd07dc6e | ||
|
|
cb49cd7100 | ||
|
|
923b340a80 | ||
|
|
5b8750ee2a | ||
|
|
d438d089fb | ||
|
|
843ddac3dd | ||
|
|
c5238e0a4c | ||
|
|
f99ee8aa40 | ||
|
|
18c7d0e11a | ||
|
|
4e67823593 | ||
|
|
e7fcefb391 | ||
|
|
be06426783 | ||
|
|
e558e83be3 | ||
|
|
d77a235b2a | ||
|
|
3add6bb5bf | ||
|
|
4367daaa00 | ||
|
|
4d46b3d126 | ||
|
|
548cd84a7f | ||
|
|
d87ffaa572 | ||
|
|
370cdb4e45 | ||
|
|
068d023917 | ||
|
|
86b6ad54d5 | ||
|
|
bdf999a9fc | ||
|
|
39f8b6828b | ||
|
|
11f84ab34b | ||
|
|
c3a5306266 | ||
|
|
1fe9e4c14c | ||
|
|
e69203dc50 | ||
|
|
342954f272 | ||
|
|
741d6b8828 | ||
|
|
f1f41ef320 | ||
|
|
785792d1f4 | ||
|
|
9affe3106c | ||
|
|
eb9fd14e2c | ||
|
|
c281a2c339 | ||
|
|
cb109eb479 | ||
|
|
3c6d194974 | ||
|
|
653a0d9734 | ||
|
|
a5fbd8405c | ||
|
|
70994d4f60 | ||
|
|
f15203afb2 | ||
|
|
0a0d707afd | ||
|
|
e206c3fe48 | ||
|
|
7f5704d321 | ||
|
|
4f7b0b9455 | ||
|
|
f5f16015df | ||
|
|
935325e0cb | ||
|
|
7b9530ac58 | ||
|
|
a9fc259420 | ||
|
|
6f603b52df | ||
|
|
aeb2a47952 | ||
|
|
ca7cea3fe3 | ||
|
|
f14aca8808 | ||
|
|
f1e5e9d9db | ||
|
|
cecba9777a | ||
|
|
4352267034 | ||
|
|
0c3730d9a3 | ||
|
|
5111b0c726 | ||
|
|
8ecd3f1592 | ||
|
|
0a6f8851c9 | ||
|
|
f0d3e93d9d | ||
|
|
e77ff2451b | ||
|
|
142c224f84 | ||
|
|
29e8d9199d | ||
|
|
7128f5add2 | ||
|
|
1b7bcda4e1 | ||
|
|
03b6146ef0 | ||
|
|
e99735d2b6 | ||
|
|
7263629c55 | ||
|
|
605ce9b938 | ||
|
|
049d8b6ca6 | ||
|
|
90d3dda830 | ||
|
|
2022a66db3 | ||
|
|
78c786070e | ||
|
|
c5c72007af | ||
|
|
c60d59cb7a | ||
|
|
00111e3e3c | ||
|
|
5cc2ac17d9 | ||
|
|
d37ea84ab5 | ||
|
|
5e335bc8bd | ||
|
|
65765763ae | ||
|
|
90f248fbe8 | ||
|
|
a39cf23697 | ||
|
|
261776762c | ||
|
|
f207f9441c | ||
|
|
ffed880e0a | ||
|
|
a79b67cea2 | ||
|
|
bc3c8b5bcd | ||
|
|
3489bb42bc | ||
|
|
7fe36f7bd7 | ||
|
|
82fd4c94db | ||
|
|
4fc48b490e | ||
|
|
750e5e6d95 | ||
|
|
cb564128e6 | ||
|
|
047fc986f2 | ||
|
|
aca800ef8a | ||
|
|
dde090d4b0 | ||
|
|
87183573ce | ||
|
|
baddcc3855 | ||
|
|
ba531774a0 | ||
|
|
708d17a4d2 | ||
|
|
7d802c03e5 | ||
|
|
787e1e9965 | ||
|
|
625691d279 | ||
|
|
4f0148dc77 | ||
|
|
c78f2b992f | ||
|
|
9857db0d15 | ||
|
|
8b71064643 | ||
|
|
bc39034f6d | ||
|
|
e6a9b8fc8e | ||
|
|
3db43dc2db | ||
|
|
d384d5ad6c | ||
|
|
7b2004caad | ||
|
|
6754f88861 | ||
|
|
9393809dfd | ||
|
|
79ecacb6c0 | ||
|
|
853acbad4b | ||
|
|
e158eac10a | ||
|
|
48ca2a2384 | ||
|
|
d9d3d3cbe3 | ||
|
|
6b4f10bf45 | ||
|
|
3b647b982f | ||
|
|
00b875ea53 | ||
|
|
545fc4d93c | ||
|
|
c41342739a | ||
|
|
ed99c5aaa3 | ||
|
|
08842811e8 | ||
|
|
3ea063d1e0 | ||
|
|
a905f12915 | ||
|
|
5d8548b92b | ||
|
|
99b63e9c77 | ||
|
|
4002ef5aff | ||
|
|
d31ccfe8a4 | ||
|
|
c4ab76a330 | ||
|
|
84d4277be3 | ||
|
|
0a99814ce2 | ||
|
|
11d695cb57 | ||
|
|
13e2d6b473 | ||
|
|
e8137e4218 | ||
|
|
fe5df08d6e | ||
|
|
f77017f35f | ||
|
|
ce93c00a7b | ||
|
|
b8f44cc219 | ||
|
|
2c921fdefe | ||
|
|
20eb95ba45 | ||
|
|
7a6239912e | ||
|
|
9067311788 | ||
|
|
23b2e07132 | ||
|
|
c8f2c0e06e | ||
|
|
72c4eb80a2 | ||
|
|
1f18e788e6 | ||
|
|
f855e24b56 | ||
|
|
84d1b7ad50 | ||
|
|
9f82649aa8 | ||
|
|
791f586c7e | ||
|
|
8d3b0cc94b | ||
|
|
70d1dfeb8b | ||
|
|
9a4c6ba0d5 | ||
|
|
ef2dbf89ee | ||
|
|
d30b776fb0 | ||
|
|
6408b28513 | ||
|
|
32b3e21564 | ||
|
|
1ef28bedcb | ||
|
|
1356bb746e | ||
|
|
23240a44d5 | ||
|
|
589c023622 | ||
|
|
047b6c5a58 | ||
|
|
951425e963 | ||
|
|
e69cbfcab3 | ||
|
|
37f3cd6a72 | ||
|
|
ec7b5dd120 | ||
|
|
d50a78171f | ||
|
|
b422aec2cd | ||
|
|
7ba0e03b4f | ||
|
|
c535766c22 | ||
|
|
289a3fdc71 | ||
|
|
7f0b6208a4 | ||
|
|
60a10eb799 | ||
|
|
5321085856 | ||
|
|
03be814a4d | ||
|
|
6c3f7683a5 | ||
|
|
06d6a90a21 | ||
|
|
747da27489 | ||
|
|
2869345920 | ||
|
|
6b8938cf76 | ||
|
|
8e7eae5751 | ||
|
|
1882148a7c | ||
|
|
e46746ce01 | ||
|
|
32917e2cfa | ||
|
|
65a243fc13 | ||
|
|
1e011cb851 | ||
|
|
48f585a4ee | ||
|
|
bc10b616ae | ||
|
|
851f08131d | ||
|
|
e294f4557e | ||
|
|
9e5775fc16 | ||
|
|
8eb95d0cdc | ||
|
|
42f807d64b | ||
|
|
d1bb97ac52 | ||
|
|
f502b16b1d | ||
|
|
51e5764258 | ||
|
|
ec2281c29a | ||
|
|
acfe1cb7e8 | ||
|
|
594aebd903 | ||
|
|
8bca63ac08 | ||
|
|
c02ec4f94c | ||
|
|
797ac1f0da | ||
|
|
058d3202ff | ||
|
|
62fcdac9cb | ||
|
|
b9131353b6 | ||
|
|
a34deb2f3b | ||
|
|
9ef4b5c93f | ||
|
|
417b0295be | ||
|
|
d11409bcc6 | ||
|
|
928b81f454 | ||
|
|
05a68157bc | ||
|
|
b6d5b5462b | ||
|
|
1c77082a29 | ||
|
|
363c55668d | ||
|
|
7ed85fb97a | ||
|
|
585ea1293d | ||
|
|
448072555f | ||
|
|
4701d5919b | ||
|
|
0997f59665 | ||
|
|
dcf7a94728 | ||
|
|
12ba563416 | ||
|
|
f2fffb9219 | ||
|
|
3f03615ed2 | ||
|
|
bc6bda057c | ||
|
|
aeebe42bfb | ||
|
|
5c4c93b62f | ||
|
|
c3ddd48d38 | ||
|
|
98f3c40ac5 | ||
|
|
ada1b9861f | ||
|
|
50cc8689bb | ||
|
|
83da861a9c | ||
|
|
1cb1d16e77 | ||
|
|
b525723084 | ||
|
|
4accdc994d | ||
|
|
ad9bee0eec | ||
|
|
6c7ff1c723 | ||
|
|
3b2aad1b2e | ||
|
|
5222fabf02 | ||
|
|
44abead174 | ||
|
|
492d5f0f9a | ||
|
|
9bc5ac3df8 | ||
|
|
5c726d63f4 | ||
|
|
2cd0a8db74 | ||
|
|
0fa0445fa9 | ||
|
|
1e171f9cc0 | ||
|
|
8d16ea4bf4 | ||
|
|
a0c2ead91d | ||
|
|
b2875f6ba0 | ||
|
|
edb4ccf63e | ||
|
|
481009d18b | ||
|
|
6153383dab | ||
|
|
74fed41818 | ||
|
|
2d5de1b9ea | ||
|
|
e23691c743 | ||
|
|
aaac236db6 | ||
|
|
ccccedc2d5 | ||
|
|
446afb04c7 | ||
|
|
87cd964329 | ||
|
|
80a344e46d | ||
|
|
f2eb5014ac | ||
|
|
d6c72061ce | ||
|
|
7c26fd25c9 | ||
|
|
10e12d2b5c | ||
|
|
b9070f89d9 | ||
|
|
46d41a8882 | ||
|
|
b5dc3481d4 | ||
|
|
c18cd81dde | ||
|
|
eaf5a26157 | ||
|
|
547c67b676 | ||
|
|
c89d6ef0ce | ||
|
|
a54041c340 | ||
|
|
352e0972cd | ||
|
|
91ebd7cc9f | ||
|
|
d8854c276b | ||
|
|
cc61840ae8 | ||
|
|
67a7a4762a | ||
|
|
c28597014f | ||
|
|
d00f29bf26 | ||
|
|
1432fbabca | ||
|
|
f3b6ee0190 | ||
|
|
229d21ef72 | ||
|
|
00f1b1fc4f | ||
|
|
277d8b37af | ||
|
|
7b83761ef4 | ||
|
|
a96e9c7e11 | ||
|
|
866721d067 | ||
|
|
b356c29c89 | ||
|
|
a2f7cb7670 | ||
|
|
08887c1df0 | ||
|
|
8b0a9f2da9 | ||
|
|
e6c958c0df | ||
|
|
01ad221972 | ||
|
|
c269a36e8b | ||
|
|
95fcd054a3 | ||
|
|
7760f16260 | ||
|
|
6d016d732b | ||
|
|
b9aebf875e | ||
|
|
1eb0e8730d | ||
|
|
7eb26a29f1 | ||
|
|
0ef051e6d2 | ||
|
|
0d641f0d17 | ||
|
|
ce6a7f6cb3 | ||
|
|
07b4c1a9f4 | ||
|
|
4d3a82583d | ||
|
|
2835d53ef1 | ||
|
|
620ecadec1 | ||
|
|
dc803f23bb | ||
|
|
a6d11fe897 | ||
|
|
78b05690e7 | ||
|
|
958a79ad73 | ||
|
|
ead25c905a | ||
|
|
97f80450ca | ||
|
|
8e62537604 | ||
|
|
7813182e2b | ||
|
|
b199fef674 | ||
|
|
e27c06c227 | ||
|
|
41b04f34e2 | ||
|
|
b091f84f90 | ||
|
|
05ae9f382b | ||
|
|
a36efcd888 | ||
|
|
af2fe9ccf9 | ||
|
|
c4a5727c2a | ||
|
|
31ca762c62 | ||
|
|
30bda70319 | ||
|
|
7fa9d375b8 | ||
|
|
91ae3fd4f2 | ||
|
|
b00d6a9655 | ||
|
|
013aa58524 | ||
|
|
8ce7e0483f | ||
|
|
582c413cd2 | ||
|
|
22e16e983b | ||
|
|
7c0c16260a | ||
|
|
e496fbd152 | ||
|
|
e025de91ab | ||
|
|
69e2fc432f | ||
|
|
78ba83ce42 | ||
|
|
6d9b61c119 | ||
|
|
61cfa5cedd | ||
|
|
0507d94306 | ||
|
|
7e8919080b | ||
|
|
8406efcaab | ||
|
|
2d87eb1e6a | ||
|
|
4685aac454 | ||
|
|
9863a8325c | ||
|
|
b9514cbe72 | ||
|
|
7b085d18fc | ||
|
|
91e73520f3 | ||
|
|
aebf5c83ba | ||
|
|
42ff47f511 | ||
|
|
746bdf144b | ||
|
|
4e8f5f7b51 | ||
|
|
50d89f71cb | ||
|
|
d70ef53283 | ||
|
|
1b6182c1cd | ||
|
|
73b50c852a | ||
|
|
063011d8e9 | ||
|
|
0f3bf6ab82 | ||
|
|
475836e851 | ||
|
|
325ca30c61 | ||
|
|
72e872c768 | ||
|
|
c2a837b30b | ||
|
|
08822ac7d5 | ||
|
|
7f9007ca1a | ||
|
|
f067cb334c | ||
|
|
60ee253fa7 | ||
|
|
4642e0b506 | ||
|
|
bd29680b62 | ||
|
|
c337462af6 | ||
|
|
c990277855 | ||
|
|
8870a1c2f9 | ||
|
|
60f1454550 | ||
|
|
38eb1c26c6 | ||
|
|
af050d0100 | ||
|
|
14f3ae5cea | ||
|
|
f4ed750d39 | ||
|
|
4b3adc8d35 | ||
|
|
8b3a4a802c | ||
|
|
8b9f605ffa | ||
|
|
3c56f24db2 | ||
|
|
82dbf60a4c | ||
|
|
b596e81e88 | ||
|
|
b7bbe15547 | ||
|
|
cb5f8c20c8 | ||
|
|
61a1e15103 | ||
|
|
2416c2e466 | ||
|
|
b898ce3c56 | ||
|
|
061e83b9e1 | ||
|
|
0a8f727908 | ||
|
|
ba584ab096 | ||
|
|
1fb1fa2e0a | ||
|
|
8cf780a60f | ||
|
|
ae171115bc | ||
|
|
a8620c3aff | ||
|
|
c154cdf46c | ||
|
|
77c59e2b85 | ||
|
|
f07656757f | ||
|
|
a1c22fb679 | ||
|
|
3640041c47 | ||
|
|
d3934dccb9 | ||
|
|
10cf2f2270 | ||
|
|
c180b2b96d | ||
|
|
5d5c2380ed | ||
|
|
a8b5c3ff4e | ||
|
|
16587aeb93 | ||
|
|
629a3a3dc1 | ||
|
|
ea46379d24 | ||
|
|
ee0c77edc8 | ||
|
|
c0610b2d60 | ||
|
|
13ab545246 | ||
|
|
d85d6bcb13 | ||
|
|
138662d6a0 | ||
|
|
e45437e19f | ||
|
|
725846e155 | ||
|
|
74aa514903 | ||
|
|
7f7230be90 | ||
|
|
d4a6e8c47a | ||
|
|
9c19ed4471 | ||
|
|
357c37c69d | ||
|
|
7c2d9c8643 | ||
|
|
69d699b80e | ||
|
|
40832dd727 | ||
|
|
31c3baa42b | ||
|
|
0ed03224c2 | ||
|
|
f8d82ae74a | ||
|
|
16234bde82 | ||
|
|
31a5d7ee3b | ||
|
|
f908c7e04d | ||
|
|
eb20f66bd9 | ||
|
|
3b3e853cf8 | ||
|
|
998ae05a5b | ||
|
|
155d01b8c3 | ||
|
|
1a4cce7efd | ||
|
|
3a0dd2ffe7 | ||
|
|
68b705b16a | ||
|
|
fe245e76cf | ||
|
|
618e37b07c | ||
|
|
3dde8d45c1 | ||
|
|
4691f95b73 | ||
|
|
02d4bf0e09 | ||
|
|
5ecf4f37c0 | ||
|
|
15f6484dd2 | ||
|
|
2ead3905e5 | ||
|
|
99d883253c | ||
|
|
ed4d4f9f23 | ||
|
|
d76f9565b2 | ||
|
|
1c637f1182 | ||
|
|
4dbe5de79c | ||
|
|
afcb88d04c | ||
|
|
1ea1deef94 | ||
|
|
08d2af22db | ||
|
|
70179bb1d7 | ||
|
|
83226c5ce8 | ||
|
|
3d6b737c46 | ||
|
|
fff511101c | ||
|
|
6672becdd5 | ||
|
|
bd315c7e43 | ||
|
|
fbfe28c087 | ||
|
|
adbafc0b02 | ||
|
|
4e6dad939a | ||
|
|
12bf9c0f59 | ||
|
|
f7f7d7bc38 | ||
|
|
c169c05bba | ||
|
|
19d48740cd | ||
|
|
7a067a4b90 | ||
|
|
13f3dab23a | ||
|
|
fd9d308b28 | ||
|
|
1047d842d0 | ||
|
|
77385e53f7 | ||
|
|
f7b3de2750 | ||
|
|
a65e6de66b | ||
|
|
41cf523dfc | ||
|
|
3774f8fd11 | ||
|
|
b9e26b1c2c | ||
|
|
609175713b | ||
|
|
d56b794177 | ||
|
|
608a929fcb | ||
|
|
4bf045e3d6 | ||
|
|
6b5434d64f | ||
|
|
abb5480890 | ||
|
|
95069b0d4c | ||
|
|
8f15b50b5f | ||
|
|
c7a1505f9b | ||
|
|
ff098c91f4 | ||
|
|
fb40a4f904 | ||
|
|
c87696f5c1 | ||
|
|
4f3dad4bea | ||
|
|
46c2e33096 | ||
|
|
66ee266b90 | ||
|
|
14883b1e26 | ||
|
|
33f74988b1 | ||
|
|
78b157ff7f | ||
|
|
546b756932 | ||
|
|
5b74d54c64 | ||
|
|
fc608b21ee | ||
|
|
2b6a266b93 | ||
|
|
7cb5092010 | ||
|
|
a1c3681002 | ||
|
|
91f35aa3bb | ||
|
|
49a6715dfe | ||
|
|
b799725bef | ||
|
|
1ada22462f | ||
|
|
b0ec9680a1 | ||
|
|
7a8a6b1bb1 | ||
|
|
1380a91bf1 | ||
|
|
83208f74ec | ||
|
|
5f571418d0 | ||
|
|
a7d8ff208f | ||
|
|
1046f3e220 | ||
|
|
6406f97f56 | ||
|
|
e0c456490a | ||
|
|
6a1b2a3964 | ||
|
|
3452b72add | ||
|
|
2e3b312fab | ||
|
|
8f67ca339b | ||
|
|
1679b7b5cf | ||
|
|
757049543d | ||
|
|
38b098b547 | ||
|
|
60478e3f61 | ||
|
|
6325f01122 | ||
|
|
74c12e6ea2 | ||
|
|
fd3453bb2a | ||
|
|
2ff7631c9c | ||
|
|
7a6b0ab641 | ||
|
|
8fd0003548 | ||
|
|
bb8de993b6 | ||
|
|
7c83d733cd | ||
|
|
6f49a1905c | ||
|
|
d0378aadeb | ||
|
|
4834318742 | ||
|
|
1838a490ba | ||
|
|
de3cbe45b4 | ||
|
|
a34cb6c89d | ||
|
|
9c0724ddb9 | ||
|
|
ce948bd9ce | ||
|
|
5eb5d2420e | ||
|
|
7510e36f6b | ||
|
|
8bfdf2bd5f | ||
|
|
2174c28aa2 | ||
|
|
7a55667a5d | ||
|
|
79d0452427 | ||
|
|
ad5c141a7c | ||
|
|
d4cd327ea3 | ||
|
|
27b29d5ffe | ||
|
|
b52222cad9 | ||
|
|
822c27399c | ||
|
|
0e717389c1 | ||
|
|
2197c4ce81 | ||
|
|
b894d64063 | ||
|
|
d95a11365a | ||
|
|
dbcade3087 | ||
|
|
7ac54c0eb8 | ||
|
|
91c74b863d | ||
|
|
8c0b6f1e9d | ||
|
|
539f388e66 | ||
|
|
b03c312b4e | ||
|
|
71db5f9a79 | ||
|
|
e33e77595f | ||
|
|
d4016b310d | ||
|
|
a41177a110 | ||
|
|
f8600296f0 | ||
|
|
e1147fb33d | ||
|
|
ec0d020669 | ||
|
|
e8eab86546 | ||
|
|
c9ebedb01f | ||
|
|
af5742ce2d | ||
|
|
8f85c71654 | ||
|
|
70753c1082 | ||
|
|
2ab2b9efd6 | ||
|
|
dbb34b75fd | ||
|
|
7447492c76 | ||
|
|
492e4c33db | ||
|
|
cbb08bdcfc | ||
|
|
0de829741a | ||
|
|
0fa7aed1c4 | ||
|
|
3b0e940284 | ||
|
|
48a970ceb9 | ||
|
|
c7b533f21e | ||
|
|
839d4da191 | ||
|
|
b76ddfe93c | ||
|
|
4ba0156ad8 | ||
|
|
6ef9936e24 | ||
|
|
e835dbc7c6 | ||
|
|
5c8429a7bb | ||
|
|
824011657a | ||
|
|
8e2031bf5a | ||
|
|
8bb5f5475e | ||
|
|
eb4f249a54 | ||
|
|
3aa3b87709 | ||
|
|
0046157862 | ||
|
|
acbf1efad6 | ||
|
|
5d1eb45d5c | ||
|
|
c52c41c885 | ||
|
|
822f9aacf6 | ||
|
|
7d5608ca0e | ||
|
|
937bbef818 | ||
|
|
c506443ed0 | ||
|
|
5f42f26587 | ||
|
|
f84e96d790 | ||
|
|
ede57a20be | ||
|
|
df8306c721 | ||
|
|
1bb144e256 | ||
|
|
7d83603646 | ||
|
|
7e4d51bab0 | ||
|
|
4ef1b079cb | ||
|
|
e95d13adb1 | ||
|
|
92d7009804 | ||
|
|
354327e40b | ||
|
|
34d56c54c8 | ||
|
|
143a5fdf4f | ||
|
|
030510613c | ||
|
|
984b8e7da0 | ||
|
|
aba1ac1646 | ||
|
|
6b93d7644a | ||
|
|
68c737dcef | ||
|
|
b8f8ffe0a2 | ||
|
|
02e8681f76 | ||
|
|
603fb9db62 | ||
|
|
b01459d1ef | ||
|
|
667f1f5951 | ||
|
|
660c5a2db4 | ||
|
|
8a4d013354 | ||
|
|
faedca81d1 | ||
|
|
166d408f5e | ||
|
|
017f25d9d5 | ||
|
|
6a70eba83f | ||
|
|
ef13ab6938 | ||
|
|
75cb61fd36 | ||
|
|
9c31f8aa92 | ||
|
|
27a08da430 | ||
|
|
fdada9661f | ||
|
|
f1a52439bb | ||
|
|
d13849c173 | ||
|
|
d8a0e73899 | ||
|
|
b6a3387f8a | ||
|
|
04dd708941 | ||
|
|
39ffe1c95a | ||
|
|
7b5ae3c15b | ||
|
|
7678625071 | ||
|
|
dbe8817d95 | ||
|
|
09e117cd57 | ||
|
|
4b8779d8d3 | ||
|
|
79158dabbc | ||
|
|
f962bc8da5 | ||
|
|
28e8dde06d | ||
|
|
6c3d41a124 | ||
|
|
9c2967f8df | ||
|
|
99311364e7 | ||
|
|
16e86b8291 | ||
|
|
5741af8fd3 | ||
|
|
6bdd47a557 | ||
|
|
750ba93c14 | ||
|
|
18be930507 | ||
|
|
be26176828 | ||
|
|
540e01f1fe | ||
|
|
7cfb6b16e4 | ||
|
|
d5a8b9648f | ||
|
|
1657d7af7d | ||
|
|
318f1a2818 | ||
|
|
8b0b115709 | ||
|
|
7d2494b7f9 | ||
|
|
3b642ffeb3 | ||
|
|
815bf5f0e0 | ||
|
|
4af48724ce | ||
|
|
001272820c | ||
|
|
4aca0664ef | ||
|
|
6721a86768 | ||
|
|
5025b3690d | ||
|
|
42b37a718f | ||
|
|
fcdfd836ec | ||
|
|
b2f005239b | ||
|
|
bc3fa890bd | ||
|
|
95dbbf6e75 | ||
|
|
22f2ae7341 | ||
|
|
96202aa78f | ||
|
|
cef8a13cc2 | ||
|
|
54271231a0 | ||
|
|
d1bb651596 | ||
|
|
10b7f65437 | ||
|
|
3a70324d43 | ||
|
|
21b72cd174 | ||
|
|
ce8656f1b2 | ||
|
|
9277dc967b | ||
|
|
67b1e65d97 | ||
|
|
79fe9da2da | ||
|
|
3164e2698d | ||
|
|
ffae33e6f7 | ||
|
|
8dafe3b7a6 | ||
|
|
e23616169b | ||
|
|
9d7fc942f7 | ||
|
|
982d8cf19d | ||
|
|
aae460623d | ||
|
|
df14e5bcb6 | ||
|
|
15d5a83c16 | ||
|
|
4b0f7543ee | ||
|
|
362c64aa9c | ||
|
|
56c497cf2c | ||
|
|
e0dc2da80a | ||
|
|
41362f12ea | ||
|
|
3765c0b0fb | ||
|
|
d1f2b62f66 | ||
|
|
26b8c1d0a2 | ||
|
|
aa195f9f6f | ||
|
|
cd1d59264e | ||
|
|
923e009fd3 | ||
|
|
70a4fd99f4 | ||
|
|
feb4011f57 | ||
|
|
bf2a04ff66 | ||
|
|
e16d352e71 | ||
|
|
817724ce39 | ||
|
|
0fda117ffe | ||
|
|
e5be1e1f05 | ||
|
|
7d7af8cf59 | ||
|
|
cbc09f83d4 | ||
|
|
31913ae80e | ||
|
|
522632bea6 | ||
|
|
397f75a4db | ||
|
|
0bf84a321b | ||
|
|
5915208dee | ||
|
|
2167931e3f | ||
|
|
2d18171914 | ||
|
|
28f6a7d399 | ||
|
|
8e042435e5 | ||
|
|
cddf8712e4 | ||
|
|
88fd96e022 | ||
|
|
17e715f408 | ||
|
|
c821d9ea65 | ||
|
|
5cb8a9ddd0 | ||
|
|
f0131b2c39 | ||
|
|
bc3c68a3cb | ||
|
|
b81d387778 | ||
|
|
0afbe72672 | ||
|
|
5fc63485f3 | ||
|
|
1bc84c98f8 | ||
|
|
737af45c85 | ||
|
|
e08fbc7d86 | ||
|
|
91090d20de | ||
|
|
05a22e20b8 | ||
|
|
7c43f343a3 | ||
|
|
029e6aa251 | ||
|
|
2f26d4ffd3 | ||
|
|
d306bae035 | ||
|
|
34dc8b32cb | ||
|
|
fe38244d7c | ||
|
|
25e8c9f637 | ||
|
|
337b568b5e | ||
|
|
e696192ef7 | ||
|
|
928fc077b8 | ||
|
|
2a448b932c | ||
|
|
d40d23a50e | ||
|
|
c4548c4355 | ||
|
|
50fdea813b | ||
|
|
0ff163e541 | ||
|
|
38cd8847a2 | ||
|
|
e62ae9fb94 | ||
|
|
187b6cf072 | ||
|
|
a3fad5966a | ||
|
|
74350f3638 | ||
|
|
ee2c7caac2 | ||
|
|
c915a6912e | ||
|
|
d5cd232441 | ||
|
|
c4c14b0fc6 | ||
|
|
e5f5563249 | ||
|
|
2a6893efb4 | ||
|
|
9fd920945a | ||
|
|
a116daa7a1 | ||
|
|
0b8759380b | ||
|
|
00c5e3544f | ||
|
|
53a79e3170 | ||
|
|
5810bf9acd | ||
|
|
7815feddba | ||
|
|
f529a5eea8 | ||
|
|
40e9550b29 | ||
|
|
64d0202f95 | ||
|
|
da9483aa3a | ||
|
|
0221e555fe | ||
|
|
494ee2c099 | ||
|
|
dc92ad9c02 | ||
|
|
8a4a019973 | ||
|
|
a1a49ebf4b | ||
|
|
45263a6261 | ||
|
|
7ccede36b1 | ||
|
|
482e1631fa | ||
|
|
d0fe7f3e25 | ||
|
|
86083e3a92 | ||
|
|
281f567d97 | ||
|
|
7f887720cc | ||
|
|
717268add9 | ||
|
|
2f7e3b1596 | ||
|
|
1a3cd2f626 | ||
|
|
2fbea43a5c | ||
|
|
70788e932e | ||
|
|
949d12052e | ||
|
|
2af35673bb | ||
|
|
4a64ca58ac | ||
|
|
815c594fa6 | ||
|
|
fc4dba4569 | ||
|
|
1d8df98339 | ||
|
|
745aabcfd5 | ||
|
|
be100790f1 | ||
|
|
afc5e82906 | ||
|
|
2951d4b7fa | ||
|
|
dcd300211f | ||
|
|
f796d27bb4 | ||
|
|
47a2553356 | ||
|
|
67bf199254 | ||
|
|
4b1ed25ef3 | ||
|
|
a5ac43e5f3 | ||
|
|
0557527bfe | ||
|
|
dc1445e0d6 | ||
|
|
431401bc96 | ||
|
|
fded6c404a | ||
|
|
680a850618 | ||
|
|
7d08a7ba1a | ||
|
|
e9f603fa30 | ||
|
|
1a064e033b | ||
|
|
ebcfcf9bfa | ||
|
|
cf063b75ff | ||
|
|
951a9d7989 | ||
|
|
37191a53c3 | ||
|
|
42d420db6a | ||
|
|
122cf63a3f | ||
|
|
fafce60f9e | ||
|
|
e855f27c8c | ||
|
|
f01a593ff7 | ||
|
|
6af34b1c16 | ||
|
|
188b329eae | ||
|
|
7b0f71cc99 | ||
|
|
73f8baf464 | ||
|
|
3a09efde91 | ||
|
|
4efa8c1ef9 | ||
|
|
9f178208f2 | ||
|
|
0f2113ee12 | ||
|
|
139e003b0b | ||
|
|
1bf80cf315 | ||
|
|
bcf182f515 | ||
|
|
c34fb94e77 | ||
|
|
64080fadd3 | ||
|
|
1009cd6ed4 | ||
|
|
839c1af124 | ||
|
|
6b24842704 | ||
|
|
2ad8ae3451 | ||
|
|
b1597f6f61 | ||
|
|
47a49263ae | ||
|
|
9fed336c9e | ||
|
|
ac5b689950 | ||
|
|
3d43bb260a | ||
|
|
2eaeb26d4c | ||
|
|
34d0f8ec81 | ||
|
|
ddc1c7e98f | ||
|
|
e41475f672 | ||
|
|
e954622925 | ||
|
|
fae899e52e | ||
|
|
7b11f5afbc | ||
|
|
40c0bf79b1 | ||
|
|
df2df593b6 | ||
|
|
1dc59d610d | ||
|
|
8fc8decd09 | ||
|
|
08f44845ce | ||
|
|
4fbffc4788 | ||
|
|
8cf4050d3d | ||
|
|
31c18fc56d | ||
|
|
005207cfd6 | ||
|
|
c8d668ad96 | ||
|
|
a39c4ba9a4 | ||
|
|
f4deea05bf | ||
|
|
1c18133603 | ||
|
|
15566b4b65 | ||
|
|
737185752c | ||
|
|
a12e3534c6 | ||
|
|
51575b341b | ||
|
|
06b330ec51 | ||
|
|
e0a6bce5b0 | ||
|
|
da07a5b613 | ||
|
|
fbbca37b55 | ||
|
|
7fa1c2264e | ||
|
|
dcfbe53713 | ||
|
|
8b2993c979 | ||
|
|
131da660c8 | ||
|
|
f3de34a62b | ||
|
|
928d6bafcb | ||
|
|
704fb0cbd9 | ||
|
|
3be27aefa3 | ||
|
|
8be81ac09e | ||
|
|
e2fc9c3699 | ||
|
|
472eaff6f0 | ||
|
|
805b016aee | ||
|
|
624a13ba1a | ||
|
|
9692bf3991 | ||
|
|
3f5406f1d4 | ||
|
|
b684a62f8b | ||
|
|
6bb94db22f | ||
|
|
d70a971d2e | ||
|
|
b05b515f3d | ||
|
|
12b15e0037 | ||
|
|
2c9169308b | ||
|
|
74a3d50c88 | ||
|
|
6b8bb33221 | ||
|
|
175fb46508 | ||
|
|
2f65400641 | ||
|
|
b5f4f2fc4b | ||
|
|
8c34f44dae | ||
|
|
d97f46133b | ||
|
|
a94a5feb84 | ||
|
|
ead5d7511a | ||
|
|
1cd7446013 | ||
|
|
40747a463b | ||
|
|
8e20118ab6 | ||
|
|
19f330e670 | ||
|
|
20d549b5e1 | ||
|
|
e09fa89781 | ||
|
|
70b1421114 | ||
|
|
b80a30785a | ||
|
|
c3245ac301 | ||
|
|
085d5b411c | ||
|
|
8c26d6d0b5 | ||
|
|
76f5085e84 | ||
|
|
80d78e3270 | ||
|
|
654521b74c | ||
|
|
353d2d4cc9 | ||
|
|
b38d84419a | ||
|
|
0d085771e4 | ||
|
|
f3b2b6b41e | ||
|
|
fb35ad7ab3 | ||
|
|
cf6e721994 | ||
|
|
9faea5ff15 | ||
|
|
fe18009bc0 | ||
|
|
10f900ea3e | ||
|
|
63874694f8 | ||
|
|
9b9e246e66 | ||
|
|
e6a6eb9be5 | ||
|
|
050bb5dbfa | ||
|
|
b005ec1845 | ||
|
|
f158a94e0a | ||
|
|
a166620a6d | ||
|
|
47fb467878 | ||
|
|
67af80c772 | ||
|
|
1f44155127 | ||
|
|
87a3ac4a76 | ||
|
|
73354a04d5 | ||
|
|
cb3038e73c | ||
|
|
b6ec31fe11 | ||
|
|
c7059a60ee | ||
|
|
af49aaf8b1 | ||
|
|
4149b8388b | ||
|
|
df0d723714 | ||
|
|
44209ed93e | ||
|
|
930a3c8637 | ||
|
|
d2f5698397 | ||
|
|
42d9fc3284 | ||
|
|
91db494898 | ||
|
|
75217d4914 | ||
|
|
ceaf004719 | ||
|
|
27b7380433 | ||
|
|
7ca254ade9 | ||
|
|
c91864c2a7 | ||
|
|
4925297a35 | ||
|
|
d7ece50ed0 | ||
|
|
3ef4a9f413 | ||
|
|
9768b5b37a | ||
|
|
e4cd999bd0 | ||
|
|
8e335535cc | ||
|
|
2f53d98806 | ||
|
|
5d99331358 | ||
|
|
316022cde4 | ||
|
|
8d1abca8de | ||
|
|
1b2e73eaa2 | ||
|
|
6127371920 | ||
|
|
7936dbbf8c | ||
|
|
8aa45309a2 | ||
|
|
d75237ba66 | ||
|
|
9909877771 | ||
|
|
64ef1f3aba | ||
|
|
d670e1a6bb | ||
|
|
7082a4dc24 | ||
|
|
e6c9314c91 | ||
|
|
3dccd4484e | ||
|
|
170ed98701 | ||
|
|
54fa2c8635 | ||
|
|
bc83fe43e5 | ||
|
|
18710567f2 | ||
|
|
9a98ed5cb6 | ||
|
|
35a98fd3b5 | ||
|
|
cd74fdf234 | ||
|
|
6cccbfc73a | ||
|
|
e59308a9a3 | ||
|
|
85a3be4ae3 | ||
|
|
d873693fe7 | ||
|
|
2df967d5c2 | ||
|
|
20989a7ab5 | ||
|
|
8e114d6fe4 | ||
|
|
479ad2d4ba | ||
|
|
d05bb49f5d | ||
|
|
fc9755379d | ||
|
|
a85db0c383 | ||
|
|
d19ec5bf49 | ||
|
|
ba72e4ebbf | ||
|
|
5936e25ce4 | ||
|
|
d82dc196e0 | ||
|
|
c174b368e8 | ||
|
|
81e3515f40 | ||
|
|
bffec6206b | ||
|
|
d269c23948 | ||
|
|
f2b2335080 | ||
|
|
5dded0d9aa | ||
|
|
33142c3a0d | ||
|
|
06e256f77a | ||
|
|
3f13cca666 | ||
|
|
73117708e5 | ||
|
|
f88b53dce5 | ||
|
|
3e609bab04 | ||
|
|
a6bf530c5f | ||
|
|
5d003b7678 | ||
|
|
a5cbc3f34a | ||
|
|
52e92e1ebf | ||
|
|
5307b6c097 | ||
|
|
dd4f4761de | ||
|
|
96f3533e46 | ||
|
|
774e1720b7 | ||
|
|
83f8eadce9 | ||
|
|
f8e75761ef | ||
|
|
cbb881df86 | ||
|
|
103e5304e8 | ||
|
|
e152ff0377 | ||
|
|
65f39ab22e | ||
|
|
df51c6dc64 | ||
|
|
b7c86ee01e | ||
|
|
992bb6a73a | ||
|
|
557dd3e0d5 | ||
|
|
c8d5b5440f | ||
|
|
0900e72070 | ||
|
|
dcdc64f974 | ||
|
|
58898adbcd | ||
|
|
ff2050466b | ||
|
|
dd209c05b9 | ||
|
|
12a4806b85 | ||
|
|
82575962ed | ||
|
|
1db2813aa3 | ||
|
|
c71613dcfe | ||
|
|
762d8a8e74 | ||
|
|
b7966f6b61 | ||
|
|
b1443533e0 | ||
|
|
6f12ac1d19 | ||
|
|
0295eea145 | ||
|
|
171402f99f | ||
|
|
3d57d35536 | ||
|
|
bacf2b9eec | ||
|
|
fd885bdb19 | ||
|
|
a497c07b0b | ||
|
|
ffd5f23406 | ||
|
|
97e3cc35c2 | ||
|
|
44d8363292 | ||
|
|
e540a95ad0 | ||
|
|
db63b0d515 | ||
|
|
7637c2fb58 | ||
|
|
5b40b43435 | ||
|
|
6ec277ec99 | ||
|
|
1befa63c9b | ||
|
|
3d3e052f23 | ||
|
|
aea816dcaf | ||
|
|
d258fb3eff | ||
|
|
1463d83b9f | ||
|
|
10c947d9d4 | ||
|
|
2da51ea6e9 | ||
|
|
d930c0a4ad | ||
|
|
d0e7cc41bf | ||
|
|
8c610adee5 | ||
|
|
a1e791d1e9 | ||
|
|
264249fb8b | ||
|
|
e2b00d7c73 | ||
|
|
ff3964e2eb | ||
|
|
2ed95bfe16 | ||
|
|
958936319f | ||
|
|
39fca33958 | ||
|
|
eb4cbe863e | ||
|
|
d146ea6a63 | ||
|
|
f4b2ba8322 | ||
|
|
acb1aa8104 | ||
|
|
03f7a75e54 | ||
|
|
2dc71cc5fd | ||
|
|
4a92419bbe | ||
|
|
92699501f6 | ||
|
|
b49ed97be0 | ||
|
|
aec661edea | ||
|
|
675fa2cf85 | ||
|
|
b442d72ef7 | ||
|
|
2ff197c670 | ||
|
|
5c9a610823 | ||
|
|
8d871256ed | ||
|
|
3d59fb0d9a | ||
|
|
057d783158 | ||
|
|
ffb8a2a00a | ||
|
|
b32b93340c | ||
|
|
35a3f7c02a | ||
|
|
6de4c4092f | ||
|
|
c5de5e07d8 | ||
|
|
0176071011 | ||
|
|
3f2a641cdf | ||
|
|
20be2d8850 | ||
|
|
b37cd7dba7 | ||
|
|
e274a49ffd | ||
|
|
cba37abfae | ||
|
|
be198a7040 | ||
|
|
29d181c113 | ||
|
|
3d5914f389 | ||
|
|
c78c75d89a | ||
|
|
a4753be5ae | ||
|
|
3bda360196 | ||
|
|
2b4de98aee | ||
|
|
bbd887fd2c | ||
|
|
84a5add410 | ||
|
|
c999563ecd | ||
|
|
80c7cdbdd2 | ||
|
|
9c7b453732 | ||
|
|
45982c4b01 | ||
|
|
438704be37 | ||
|
|
1753ddc4d6 | ||
|
|
96178194b3 | ||
|
|
57fb2192be | ||
|
|
546a78be33 | ||
|
|
29acb67566 | ||
|
|
0afad9a825 | ||
|
|
c99b3de902 | ||
|
|
e8cf1d6b9a | ||
|
|
a9aa1e13ee | ||
|
|
f5857c8aab | ||
|
|
67856a98af | ||
|
|
c71de15cb0 | ||
|
|
73f15c1980 | ||
|
|
646df4f34e | ||
|
|
8489d0df97 | ||
|
|
86dfad860e | ||
|
|
c97a68029b | ||
|
|
08a4dfbe4c | ||
|
|
adcacf3cf9 | ||
|
|
7950b69136 | ||
|
|
5d75416948 | ||
|
|
2e96a00fde | ||
|
|
1f08bcf0f8 | ||
|
|
a3e2e75021 | ||
|
|
603bdd2941 | ||
|
|
6fb7a4f24b | ||
|
|
0c2d290835 | ||
|
|
210e05f7fc | ||
|
|
f4b443c33e | ||
|
|
52ffa09f73 | ||
|
|
52bb23bb6f | ||
|
|
2089af8fd3 | ||
|
|
778bc4072b | ||
|
|
2b2ebecae7 | ||
|
|
69cbd61915 | ||
|
|
4d41774345 | ||
|
|
ff6772aaa7 | ||
|
|
bbe9d43532 | ||
|
|
6549bea3e0 | ||
|
|
9d727589aa | ||
|
|
aede0547d3 | ||
|
|
55332d61fd | ||
|
|
83eeb5d6d0 | ||
|
|
5eaf796aab | ||
|
|
d46c40d3fa | ||
|
|
2461afa573 | ||
|
|
6acacf5efe | ||
|
|
075a74ea0c | ||
|
|
f9ddc43349 | ||
|
|
1c9a232a9d | ||
|
|
9c727a8d8c | ||
|
|
7c241c65de | ||
|
|
4f3823bfeb | ||
|
|
3f7b16c736 | ||
|
|
362fbb39d4 | ||
|
|
38fe24085f | ||
|
|
af3d5cb273 | ||
|
|
9200b742c5 | ||
|
|
f39c8ebaba | ||
|
|
bbb1831c5f | ||
|
|
ecae3d0e1e |
No files matched your search
@@ -0,0 +1,106 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check C99
|
||||
run: make clean && make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="cc -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C++
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="c++ -std=c++11"
|
||||
|
||||
build_linux32:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: update package list
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
run: sudo apt-get install gcc-multilib g++-multilib
|
||||
- name: make check C99 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C++ (32 bits)
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="g++ -m32 -std=c++11 -Wno-unknown-warning-option "
|
||||
- name: make check against C++ STL
|
||||
working-directory: ./tests
|
||||
run: make clean && make check-stl -j 2
|
||||
|
||||
build_linux_tcc:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Clone TCC
|
||||
shell: bash
|
||||
run: git clone https://repo.or.cz/tinycc.git
|
||||
- name: Configure, build & install TCC
|
||||
shell: bash
|
||||
run: cd tinycc && ./configure --prefix=/tmp/tcc && make && make install
|
||||
- name: make depend
|
||||
shell: bash
|
||||
run: make depend
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_windows_mingw:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: mingw32-make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_msys2:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: true
|
||||
install: git mingw-w64-x86_64-toolchain make
|
||||
- name: make check
|
||||
run: make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_visual:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat cl
|
||||
|
||||
build_windows_clang_cl:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat clang-cl
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['cpp']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
- name: Autobuild
|
||||
working-directory: ./tests
|
||||
run: make exe
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
+12
@@ -7,6 +7,8 @@
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
depend
|
||||
*.depend
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
@@ -31,3 +33,13 @@
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
|
||||
# Others
|
||||
other/
|
||||
a*.dat
|
||||
config
|
||||
*.log
|
||||
.vscode
|
||||
.vs
|
||||
tmp-serial.*
|
||||
*~
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017, Patrick Pelissier
|
||||
Copyright (c) 2017-2021, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,6 +1,49 @@
|
||||
PREFIX=/usr/local
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# + Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# + Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Environnement variable. To customize if needed.
|
||||
RM=rm -f
|
||||
MKDIR=mkdir -p
|
||||
RMDIR=rmdir
|
||||
INSTALL=install
|
||||
INSTALL_PROGRAM=${INSTALL}
|
||||
INSTALL_DATA=${INSTALL} -m 644
|
||||
|
||||
# Installation directory
|
||||
PREFIX=/usr/local
|
||||
DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.6.0
|
||||
|
||||
# Define the contain of the distribution tarball
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
|
||||
DOC1=LICENSE README.md
|
||||
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
|
||||
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
all:
|
||||
@echo "Nothing to be done."
|
||||
@@ -11,21 +54,65 @@ check:
|
||||
cd tests && $(MAKE) check
|
||||
cd example && $(MAKE) all
|
||||
|
||||
doc: README.md
|
||||
checkall:
|
||||
cd tests && $(MAKE) checkall
|
||||
cd example && $(MAKE) all
|
||||
|
||||
html: README.md
|
||||
markdown < README.md > README.html
|
||||
|
||||
doc: html doc/depend.png
|
||||
|
||||
clean:
|
||||
cd tests && $(MAKE) clean
|
||||
cd example && $(MAKE) clean
|
||||
cd bench && $(MAKE) clean
|
||||
$(RM) -f README.html
|
||||
$(RM) README.html depend.dot
|
||||
$(RM) -r 'm*lib-$(VERSION)'
|
||||
$(RM) 'm*lib-$(VERSION).tar.bz2'
|
||||
|
||||
distclean:
|
||||
distclean: clean
|
||||
cd tests && $(MAKE) distclean
|
||||
|
||||
depend:
|
||||
cd tests && $(MAKE) depend
|
||||
|
||||
doc/depend.png: $(HEADER)
|
||||
(echo "digraph g { " ; for i in *.h ; do list=$$(grep "include \"" $$i |cut -f2 -d\") ; for j in $$list ; do echo "\"$$i\" -> \"$$j\" ;" ; done ; done ; echo "}" )> depend.dot
|
||||
dot -Tpng depend.dot -o doc/depend.png
|
||||
optipng -o7 doc/depend.png
|
||||
|
||||
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean versioncheck
|
||||
$(MKDIR) '$(PACKAGE)'
|
||||
$(MKDIR) '$(PACKAGE)/doc'
|
||||
$(MKDIR) '$(PACKAGE)/tests'
|
||||
$(MKDIR) '$(PACKAGE)/example'
|
||||
cp $(HEADER) $(DOC1) Makefile '$(PACKAGE)'
|
||||
cp $(EXAMPLE) '$(PACKAGE)/example'
|
||||
cp $(TEST) '$(PACKAGE)/tests'
|
||||
cp $(DOC2) '$(PACKAGE)/doc'
|
||||
cd '$(PACKAGE)/tests' && $(MAKE) depend
|
||||
tar jcf '$(PACKAGE).tar.bz2' '$(PACKAGE)'
|
||||
|
||||
distcheck: dist
|
||||
cd '$(PACKAGE)' && make check
|
||||
|
||||
versioncheck:
|
||||
@if test "$(VERSION)." != `grep M_CORE_VERSION m-core.h |awk '{printf "%d.",$$3 } END {printf "\n"}'` ; then echo "ERROR: Version mismatch between Makefile & HEADERS" ; exit 2 ; fi
|
||||
@for i in *.h ; do echo $(HEADER) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing header $$i in Makefile" ; exit 3 ; fi ; done
|
||||
@for i in doc/* ; do echo $(DOC2) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing document $$i in Makefile" ; exit 4 ; fi ; done
|
||||
@for i in tests/*.c tests/*.txt tests/*.h ; do echo $(TEST) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing test $$i in Makefile" ; exit 5 ; fi ; done
|
||||
@for i in example/*.c example/*.json ; do echo $(EXAMPLE) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing example $$i in Makefile" ; exit 6 ; fi ; done
|
||||
@for i in tests/*.cpp tests/*.hpp ; do echo $(TEST) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing test $$i in Makefile" ; exit 7 ; fi ; done
|
||||
|
||||
install:
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include
|
||||
cp m-*.h $(DESTDIR)$(PREFIX)/include
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
|
||||
uninstall:
|
||||
for i in $(HEADER) ; do $(RM) $(DESTDIR)$(PREFIX)/include/m-lib/$$i ; done
|
||||
$(RMDIR) $(DESTDIR)$(PREFIX)/include/m-lib/
|
||||
|
||||
format:
|
||||
cd example && $(MAKE) ex-string01.exe
|
||||
for i in $(HEADER) ; do ./example/ex-string01.exe $$i > tmp.h && mv tmp.h $$i ; done
|
||||
+201
-50
@@ -1,18 +1,48 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# + Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# + Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
CC=cc -std=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
XCFLAGS=
|
||||
CPPFLAGS=-I..
|
||||
N=4
|
||||
BENCH_DEF=
|
||||
RM=rm -rf
|
||||
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
|
||||
|
||||
all: container queue mempool string plain
|
||||
|
||||
pgo:
|
||||
$(MAKE) all XCFLAGS="-fprofile-generate=pgo"
|
||||
$(MAKE) all XCFLAGS="-fprofile-use=pgo"
|
||||
|
||||
#########################################################################
|
||||
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap bench-ctl
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
mempool: bench-mempool
|
||||
@@ -30,46 +60,65 @@ plain: bench-plain
|
||||
|
||||
|
||||
bench-mlib:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -pthread bench-mlib.c -o bench-mlib.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -pthread bench-mlib.c common.c -o bench-mlib.exe
|
||||
@./bench-mlib.exe 10
|
||||
@./bench-mlib.exe 11
|
||||
@./bench-mlib.exe 20
|
||||
@./bench-mlib.exe 30
|
||||
@./bench-mlib.exe 31
|
||||
@./bench-mlib.exe 40
|
||||
@./bench-mlib.exe 41
|
||||
@./bench-mlib.exe 42
|
||||
@./bench-mlib.exe 46
|
||||
@./bench-mlib.exe 47
|
||||
@./bench-mlib.exe 43
|
||||
@./bench-mlib.exe 50
|
||||
@./bench-mlib.exe 51
|
||||
|
||||
bench-mlib-mempool:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c common.c -DUSE_MEMPOOL -pthread -o bench-mlib-mempool.exe
|
||||
@./bench-mlib-mempool.exe 10
|
||||
@./bench-mlib-mempool.exe 11
|
||||
@./bench-mlib-mempool.exe 20
|
||||
@./bench-mlib-mempool.exe 30
|
||||
@./bench-mlib-mempool.exe 31
|
||||
@./bench-mlib-mempool.exe 40
|
||||
@./bench-mlib-mempool.exe 41
|
||||
@./bench-mlib-mempool.exe 42
|
||||
@./bench-mlib-mempool.exe 46
|
||||
@./bench-mlib-mempool.exe 47
|
||||
@./bench-mlib-mempool.exe 43
|
||||
@./bench-mlib-mempool.exe 50
|
||||
@./bench-mlib-mempool.exe 51
|
||||
|
||||
bench-mlib-thread:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-mlib.c common.c -DMULTI_THREAD_MEASURE -pthread -o bench-mlib-thread.exe
|
||||
@./bench-mlib-thread.exe 60
|
||||
@./bench-mlib-thread.exe 61
|
||||
@./bench-mlib-thread.exe 62
|
||||
@./bench-mlib-thread.exe 63
|
||||
@./bench-mlib-thread.exe 64
|
||||
@./bench-mlib-thread.exe 65
|
||||
@./bench-mlib-thread.exe 66
|
||||
|
||||
bench-stl:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) bench-stl.cpp -o bench-stl.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-stl.cpp common.c -o bench-stl.exe
|
||||
@./bench-stl.exe 10
|
||||
@./bench-stl.exe 20
|
||||
@./bench-stl.exe 30
|
||||
@./bench-stl.exe 40
|
||||
@./bench-stl.exe 41
|
||||
@./bench-stl.exe 42
|
||||
@./bench-stl.exe 46
|
||||
@./bench-stl.exe 43
|
||||
@./bench-stl.exe 50
|
||||
@./bench-stl.exe 51
|
||||
|
||||
# QT is supposed to be installed
|
||||
# QT shall point to the the directory containing the file .pc are stored
|
||||
bench-qt:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -fPIC `pkg-config --libs --cflags Qt5Core` bench-qt.cpp -o bench-qt.exe
|
||||
@if test -n "$${QT}" ; then $(MAKE) bench-qt0 ; else echo "Nothing to be done for QT." ; fi
|
||||
bench-qt0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp common.c -o bench-qt.exe
|
||||
@./bench-qt.exe 10
|
||||
@./bench-qt.exe 20
|
||||
@./bench-qt.exe 30
|
||||
@@ -78,9 +127,11 @@ bench-qt:
|
||||
@./bench-qt.exe 42
|
||||
@./bench-qt.exe 50
|
||||
|
||||
#GLIB is supposed to be installed
|
||||
# GLIB shall point to the the directory containing the file .pc are stored
|
||||
bench-glib:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-glib.c -o bench-glib.exe `pkg-config --libs --cflags glib-2.0`
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-glib0 ; else echo "Nothing to be done for GLIB." ; fi
|
||||
bench-glib0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-glib.c common.c -o bench-glib.exe `PKG_CONFIG_PATH="$${GLIB}" pkg-config --libs --cflags glib-2.0`
|
||||
@./bench-glib.exe 10
|
||||
@./bench-glib.exe 20
|
||||
@./bench-glib.exe 30
|
||||
@@ -93,7 +144,7 @@ bench-klib:
|
||||
@if test -n "$${KLIB}" ; then $(MAKE) bench-klib0 ; else echo "Nothing to be done for KLIB." ; fi
|
||||
|
||||
bench-klib0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I $${KLIB} bench-klib.c -o bench-klib.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${KLIB} bench-klib.c common.c -o bench-klib.exe
|
||||
@./bench-klib.exe 10
|
||||
@./bench-klib.exe 20
|
||||
@./bench-klib.exe 30
|
||||
@@ -101,25 +152,32 @@ bench-klib0:
|
||||
@./bench-klib.exe 41
|
||||
@./bench-klib.exe 50
|
||||
|
||||
# CMC shall point to the directory where the CMC main header is
|
||||
bench-cmc:
|
||||
@if test -n "$${CMC}" ; then $(MAKE) bench-cmc0 ; else echo "Nothing to be done for CMC." ; fi
|
||||
|
||||
bench-cmc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CMC} bench-cmc.c common.c -o bench-cmc.exe
|
||||
@./bench-cmc.exe 20
|
||||
@./bench-cmc.exe 30
|
||||
@./bench-cmc.exe 40
|
||||
|
||||
# LIBDYNAMIC shall point to the the directory containing the file libdynamic.pc
|
||||
bench-libdynamic:
|
||||
@if test -n "$${LIBDYNAMIC}" ; then $(MAKE) bench-libdynamic0 ; else echo "Nothing to be done for LIBDYNAMIC." ; fi
|
||||
|
||||
bench-libdynamic0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-libdynamic.c -o bench-libdynamic.exe `PKG_CONFIG_PATH="$${LIBDYNAMIC}" pkg-config --libs --cflags libdynamic`
|
||||
@./bench-libdynamic.exe 10
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe `PKG_CONFIG_PATH="$${LIBDYNAMIC}" pkg-config --libs --cflags libdynamic`
|
||||
@./bench-libdynamic.exe 20
|
||||
@./bench-libdynamic.exe 30
|
||||
@./bench-libdynamic.exe 40
|
||||
@./bench-libdynamic.exe 41
|
||||
@./bench-libdynamic.exe 50
|
||||
|
||||
# SPARSEPP shall point to the directory where the headers are
|
||||
bench-sparsepp:
|
||||
@if test -n "$${SPARSEPP}" ; then $(MAKE) bench-sparsepp0 ; else echo "Nothing to be done for SPARSEPP." ; fi
|
||||
|
||||
bench-sparsepp0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${SPARSEPP}" -I "$${SPARSEPP}/.." bench-sparsepp.cpp -o bench-sparsepp.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${SPARSEPP}" -I "$${SPARSEPP}/.." bench-sparsepp.cpp common.c -o bench-sparsepp.exe
|
||||
@./bench-sparsepp.exe 41
|
||||
@./bench-sparsepp.exe 42
|
||||
@./bench-sparsepp.exe 43
|
||||
@@ -129,17 +187,17 @@ bench-densehashmap:
|
||||
@if test -n "$${DENSEHASHMAP}" ; then $(MAKE) bench-densehashmap0 ; else echo "Nothing to be done Google DENSEHASHMAP." ; fi
|
||||
|
||||
bench-densehashmap0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${DENSEHASHMAP}" -I "$${DENSEHASHMAP}/.." bench-densehashmap.cpp -o bench-densehashmap.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${DENSEHASHMAP}" -I "$${DENSEHASHMAP}/.." bench-densehashmap.cpp common.c -o bench-densehashmap.exe
|
||||
@./bench-densehashmap.exe 41
|
||||
@./bench-densehashmap.exe 42
|
||||
@./bench-densehashmap.exe 43
|
||||
|
||||
# COLLECTIONC shall point to the directory where the 'src' directory is.
|
||||
# COLLECTIONC shall point to the directory where it is installed
|
||||
bench-collectionc:
|
||||
@if test -n "$${COLLECTIONC}" ; then $(MAKE) bench-collectionc0 ; else echo "Nothing to be done for COLLECTIONC." ; fi
|
||||
|
||||
bench-collectionc0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include" -L "$${COLLECTIONC}" -static bench-collectionc.c -lcollectc -o bench-collectionc.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include/collectc" bench-collectionc.c common.c "$${COLLECTIONC}/lib/libcollectc.a" -o bench-collectionc.exe
|
||||
@./bench-collectionc.exe 10
|
||||
@./bench-collectionc.exe 20
|
||||
@./bench-collectionc.exe 30
|
||||
@@ -152,7 +210,7 @@ bench-tommyds:
|
||||
@if test -n "$${TOMMYDS}" ; then $(MAKE) bench-tommyds0 ; else echo "Nothing to be done for TOMMYDS." ; fi
|
||||
|
||||
bench-tommyds0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${TOMMYDS}" bench-tommyds.c $${TOMMYDS}/tommyds/tommyarray.c $${TOMMYDS}/tommyds/tommylist.c $${TOMMYDS}/tommyds/tommytree.c $${TOMMYDS}/tommyds/tommyhashlin.c -o bench-tommyds.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${TOMMYDS}" bench-tommyds.c $${TOMMYDS}/tommyds/tommyarray.c $${TOMMYDS}/tommyds/tommylist.c $${TOMMYDS}/tommyds/tommytree.c $${TOMMYDS}/tommyds/tommyhashlin.c common.c -o bench-tommyds.exe
|
||||
@./bench-tommyds.exe 10
|
||||
@./bench-tommyds.exe 20
|
||||
@./bench-tommyds.exe 30
|
||||
@@ -164,17 +222,29 @@ bench-flathashmap:
|
||||
@if test -n "$${FLATHASHMAP}" ; then $(MAKE) bench-flathashmap0 ; else echo "Nothing to be done for FLATHASHMAP." ; fi
|
||||
|
||||
bench-flathashmap0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp -o bench-flathashmap.exe
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp common.c -o bench-flathashmap.exe
|
||||
@./bench-flathashmap.exe 41
|
||||
@./bench-flathashmap.exe 42
|
||||
@./bench-flathashmap.exe 46
|
||||
@./bench-flathashmap.exe 43
|
||||
|
||||
# EMILIB shall point to the directory where the headers are
|
||||
bench-emilib:
|
||||
@if test -n "$${EMILIB}" ; then $(MAKE) bench-emilib0 ; else echo "Nothing to be done for EMILIB." ; fi
|
||||
|
||||
bench-emilib0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMILIB}" bench-emilib.cpp common.c -o bench-emilib.exe
|
||||
@./bench-emilib.exe 41
|
||||
@./bench-emilib.exe 42
|
||||
@./bench-emilib.exe 46
|
||||
@./bench-emilib.exe 43
|
||||
|
||||
# HOPSCOTCHMAP shall point to the directory where the source are
|
||||
bench-hopscotchmap:
|
||||
@if test -n "$${HOPSCOTCHMAP}" ; then $(MAKE) bench-hopscotchmap0 ; else echo "Nothing to be done for HOPSCOTCHMAP." ; fi
|
||||
|
||||
bench-hopscotchmap0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${HOPSCOTCHMAP}" bench-hopscotchmap.cpp -o bench-hopscotchmap.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${HOPSCOTCHMAP}/include/tsl" bench-hopscotchmap.cpp common.c -o bench-hopscotchmap.exe
|
||||
@./bench-hopscotchmap.exe 41
|
||||
@./bench-hopscotchmap.exe 42
|
||||
@./bench-hopscotchmap.exe 43
|
||||
@@ -184,12 +254,11 @@ bench-uthash:
|
||||
@if test -n "$${UTHASH}" ; then $(MAKE) bench-uthash0 ; else echo "Nothing to be done for UTHASH." ; fi
|
||||
|
||||
bench-uthash0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c -o bench-uthash.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c common.c -o bench-uthash.exe
|
||||
@./bench-uthash.exe 10
|
||||
@./bench-uthash.exe 20
|
||||
@./bench-uthash.exe 40
|
||||
@./bench-uthash.exe 41
|
||||
@./bench-uthash.exe 42
|
||||
@./bench-uthash.exe 43
|
||||
@./bench-uthash.exe 50
|
||||
|
||||
# QLIBC shall point to the directory where the library is installed.
|
||||
@@ -197,24 +266,18 @@ bench-qlibc:
|
||||
@if test -n "$${QLIBC}" ; then $(MAKE) bench-qlibc0 ; else echo "Nothing to be done for QLIBC." ; fi
|
||||
|
||||
bench-qlibc0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${QLIBC}/include" -L "$${QLIBC}/lib" -lqlibc -pthread bench-qlibc.c -o bench-qlibc.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${QLIBC}/include" -L "$${QLIBC}/lib" -lqlibc -pthread bench-qlibc.c common.c -o bench-qlibc.exe
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 10
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 20
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 30
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 42
|
||||
@LD_LIBRARY_PATH="$${QLIBC}/lib:$${LD_LIBRARY_PATH}" ./bench-qlibc.exe 41
|
||||
|
||||
# LIBSRT shall point to the directory where the source are
|
||||
# LIBSRT shall point to the directory where it is installed
|
||||
bench-libsrt:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
|
||||
|
||||
bench-libsrt0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c -o bench-libsrt.exe $${LIBSRT}/libsrt.a
|
||||
@./bench-libsrt.exe 10
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/include/libsrt" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/lib/libsrt.a
|
||||
@./bench-libsrt.exe 20
|
||||
@./bench-libsrt.exe 41
|
||||
@./bench-libsrt.exe 42
|
||||
@./bench-libsrt.exe 43
|
||||
@./bench-libsrt.exe 50
|
||||
|
||||
|
||||
@@ -222,9 +285,8 @@ bench-libsrt0:
|
||||
# The library shall be built.
|
||||
bench-liblfds:
|
||||
@if test -n "$${LIBLFDS}" ; then $(MAKE) bench-liblfds0 ; else echo "Nothing to be done for LIBLFDS." ; fi
|
||||
|
||||
bench-liblfds0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.so -lpthread
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBLFDS}/inc" -Wno-unknown-pragmas bench-liblfds.c common.c -DMULTI_THREAD_MEASURE -o bench-liblfds.exe $${LIBLFDS}/bin/liblfds711.a -lpthread
|
||||
@LD_LIBRARY_PATH="$${LIBLFDS}/bin:$${LD_LIBRARY_PATH}" ./bench-liblfds.exe 60
|
||||
|
||||
|
||||
@@ -232,54 +294,143 @@ bench-liblfds0:
|
||||
# The library shall be built.
|
||||
bench-concurrentqueue:
|
||||
@if test -n "$${CONCURRENTQUEUE}" ; then $(MAKE) bench-concurrentqueue0 ; else echo "Nothing to be done for CONCURRENTQUEUE." ; fi
|
||||
|
||||
bench-concurrentqueue0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${CONCURRENTQUEUE}/" bench-concurrentqueue.cpp -o bench-concurrentqueue.exe -lpthread
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${CONCURRENTQUEUE}/" bench-concurrentqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-concurrentqueue.exe -lpthread
|
||||
@./bench-concurrentqueue.exe 60
|
||||
|
||||
|
||||
# BOOST is assumed to be installed in the system
|
||||
# XXHASH shall point to the source directory of xxhash
|
||||
# The library shall be built.
|
||||
bench-xxhash:
|
||||
@if test -n "$${XXHASH}" ; then $(MAKE) bench-xxhash0 ; else echo "Nothing to be done for XXHASH." ; fi
|
||||
bench-xxhash0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${XXHASH}/" bench-xxhash.c common.c "$${XXHASH}/libxxhash.a" -o bench-xxhash.exe
|
||||
@./bench-xxhash.exe 70
|
||||
|
||||
# BOOST shall point to the header location.
|
||||
bench-boost:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) bench-boost.cpp -o bench-boost.exe -lpthread
|
||||
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
|
||||
bench-boost0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -DMULTI_THREAD_MEASURE -o bench-boost.exe -lpthread
|
||||
@./bench-boost.exe 60
|
||||
|
||||
# NEDTRIES shall point to the header location.
|
||||
bench-nedtries:
|
||||
@if test -n "$${NEDTRIES}" ; then $(MAKE) bench-nedtries0 ; else echo "Nothing to be done for NEDTRIES." ; fi
|
||||
bench-nedtries0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${NEDTRIES}" bench-nedtries.c common.c -o bench-nedtries.exe
|
||||
@./bench-nedtries.exe 40
|
||||
@./bench-nedtries.exe 45
|
||||
|
||||
# RIGTORP_HASHMAP shall point to the directory where the headers are
|
||||
bench-rigtorp-hashmap:
|
||||
@if test -n "$${RIGTORP_HASHMAP}" ; then $(MAKE) bench-rigtorp-hashmap0 ; else echo "Nothing to be done for RIGTORP_HASHMAP." ; fi
|
||||
|
||||
bench-rigtorp-hashmap0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_HASHMAP}/include" bench-rigtorp-hashmap.cpp common.c -o bench-rigtorp-hashmap.exe
|
||||
@./bench-rigtorp-hashmap.exe 42
|
||||
@./bench-rigtorp-hashmap.exe 41
|
||||
@./bench-rigtorp-hashmap.exe 43
|
||||
|
||||
# RIGTORP_MPMC_QUEUE shall point to the directory where the headers are
|
||||
bench-rigtorp-mpmc-queue:
|
||||
@if test -n "$${RIGTORP_MPMC_QUEUE}" ; then $(MAKE) bench-rigtorp-mpmc-queue0 ; else echo "Nothing to be done for RIGTORP_MPMC_QUEUE." ; fi
|
||||
bench-rigtorp-mpmc-queue0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_MPMC_QUEUE}" bench-rigtorp-mpmcqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-mpmcqueue.exe -lpthread
|
||||
@./bench-mpmcqueue.exe 60
|
||||
|
||||
# CTL shall point to the source directory (not where the headers are)
|
||||
bench-ctl:
|
||||
@if test -n "$${CTL}" ; then $(MAKE) bench-ctl0 ; else echo "Nothing to be done for CTL." ; fi
|
||||
|
||||
bench-ctl0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CTL} bench-ctl.c common.c -o bench-ctl.exe
|
||||
@./bench-ctl.exe 10
|
||||
@./bench-ctl.exe 20
|
||||
@./bench-ctl.exe 30
|
||||
@./bench-ctl.exe 40
|
||||
@./bench-ctl.exe 50
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
@./bench-mlib.exe 110
|
||||
@./bench-mlib.exe 111
|
||||
@./bench-mlib.exe 112
|
||||
|
||||
bench-rapidjson:
|
||||
@if test -n "$${RAPIDJSON}" ; then $(MAKE) bench-rapidjson0 ; else echo "Nothing to be done for RAPIDJSON." ; fi
|
||||
bench-rapidjson0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RAPIDJSON}/" bench-rapidjson.cpp common.c -o bench-rapidjson.exe
|
||||
@./bench-rapidjson.exe 110
|
||||
@./bench-rapidjson.exe 111
|
||||
@./bench-rapidjson.exe 112
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-plain:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-plain-c.c -o bench-plain-c.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-plain-c.c -o bench-plain-c.exe
|
||||
@./bench-plain-c.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mempool:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) pool.cc `pkg-config --libs --cflags glib-2.0` -lboost_system -o bench-mempool.exe
|
||||
@if test -n "$${BOOST}" ; then if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_BOOST -DUSE_GLIB `pkg-config --libs --cflags glib-2.0` -lboost_system" ; else make bench-mempool0 BENCH_DEF="-DUSE_BOOST -lboost_system" ; fi ; else if test -n "$${GLIB}" ; then make bench-mempool0 BENCH_DEF="-DUSE_GLIB `pkg-config --libs --cflags glib-2.0`" ; else make bench-mempool0 ; fi ; fi
|
||||
bench-mempool0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) pool.cc $(BENCH_DEF) -o bench-mempool.exe
|
||||
@./bench-mempool.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-maxdict:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) max-dict.c -o bench-max-dict.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) max-dict.c -o bench-max-dict.exe
|
||||
@./bench-max-dict.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
# BSTRLIB shall point to the BSTRLIB sources
|
||||
# LIBSRT shall point to the LIBSRT sources
|
||||
# LIBSRT shall point to the LIBSRT install directory
|
||||
bench-string:
|
||||
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-with BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-with ; fi
|
||||
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-step1 BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-step1 ; fi
|
||||
|
||||
bench-string-with:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-exe BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/libsrt.a" ; else $(MAKE) bench-string-exe BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
bench-string-step1:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/include/libsrt $${LIBSRT}/lib/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-exe:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${BSTRLIB}" -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string.cpp -o bench-string.exe $(BENCH_DEF)
|
||||
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
|
||||
bench-string-step2:
|
||||
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step4:
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_GLIB $$(pkg-config --cflags --libs glib-2.0)" ; else $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step5:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string.cpp common.c $(BENCH_DEF) -o bench-string.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string-2.cpp common.c $(BENCH_DEF) -o bench-string-2.exe
|
||||
@./bench-string.exe
|
||||
@./bench-string-2.exe 2000000 0
|
||||
@./bench-string-2.exe 2000000 1
|
||||
@./bench-string-2.exe 2000000 2
|
||||
@./bench-string-2.exe 2000000 4
|
||||
|
||||
bench-string-pgo:
|
||||
$(MAKE) bench-string XCFLAGS="-fprofile-generate=pgo"
|
||||
$(MAKE) bench-string XCFLAGS="-fprofile-use=pgo"
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-find-sort:
|
||||
g++ bench-find-sort.cpp -O2 -march=native -std=c++11 -I.. -g common.c -o bench-find-sort.exe
|
||||
./bench-find-sort.exe 10000000
|
||||
|
||||
############################################################################
|
||||
|
||||
clean:
|
||||
rm -f *.o bench-*.exe bench-*.s *~ massif.out.*
|
||||
$(RM) *.o bench-*.exe
|
||||
$(RM) bench-*.s *~ massif.out.*
|
||||
$(RM) plot-*.dat
|
||||
$(RM) pgo
|
||||
$(RM) tmp-serial.*
|
||||
cd nucleotide && $(MAKE) clean
|
||||
|
||||
############################################################################
|
||||
|
||||
|
||||
@@ -6,11 +6,8 @@
|
||||
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#include "m-mutex.h"
|
||||
#define MULTI_THREAD_MEASURE
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
boost::lockfree::queue<unsigned int, boost::lockfree::capacity<4*64>> g_buff;
|
||||
boost::lockfree::queue<unsigned long long, boost::lockfree::capacity<4*64>> g_final;
|
||||
@@ -51,7 +48,7 @@ static void prod(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(size_t n)
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
@@ -88,11 +85,12 @@ static void test_buffer(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 60)
|
||||
test_function("Buffer time", 1000000, test_buffer);
|
||||
test("BOOST-LOCKFREE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// CMC list are dynamic array
|
||||
#define MY_LIST_PARAMS (list_uint, list_uint_s, , , unsigned int)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, LIST, MY_LIST_PARAMS, (STR))
|
||||
|
||||
struct list_uint_s_fval list_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
struct list_uint_s *a1 = list_uint_new(1, &list_fval);
|
||||
struct list_uint_s *a2 = list_uint_new(1, &list_fval);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
list_uint_push_back(a1, rand_get() );
|
||||
list_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += list_uint_get(a1, i ) * list_uint_get(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
list_uint_free(a1);
|
||||
list_uint_free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define my_cmp(a,b) ( (a) < (b) ? -1 : (a) > (b) )
|
||||
|
||||
#define MY_TMAP_PARAMS (tree_ulong, tree_ulong_s, , unsigned long, bool)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, TREEMAP, MY_TMAP_PARAMS, (STR))
|
||||
|
||||
int cmp_ulong(unsigned long a, unsigned long b) { return my_cmp(a,b); }
|
||||
|
||||
struct tree_ulong_s_fkey tree_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
struct tree_ulong_s_fval tree_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
struct tree_ulong_s *tree;
|
||||
tree = tree_ulong_new(&tree_fkey, &tree_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
tree_ulong_insert(tree, j, true);
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (tree_ulong_get_ref(tree, j) != 0)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
tree_ulong_free(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
#define hash_func(a) kh_int64_hash_func(a)
|
||||
size_t hash_ulong(unsigned long a)
|
||||
{
|
||||
return ( (a) >> 33 ) ^ (a) ^ ((a) << 11);
|
||||
}
|
||||
|
||||
#define MY_DICT_PARAMS (hmap, hmap_s, , unsigned long, unsigned long)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct hmap_s_fkey hmap_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = hash_ulong,
|
||||
.pri = NULL };
|
||||
|
||||
struct hmap_s_fval hmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
struct hmap_s *dict = hmap_new(16, 0.7, &hmap_fkey, &hmap_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
hmap_insert(dict, rand_get(), rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *val = hmap_get_ref(dict, rand_get());
|
||||
if (val != 0)
|
||||
s += *val;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
hmap_free(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#if 0 // Not working issue in using not integer types
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
static inline int char_cmp (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.a); }
|
||||
static inline size_t char_hash(const char_array_t a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define MY_DICTB_PARAMS (bhmap, bhmap_s, , char_array_t, char_array_t)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct bhmap_s_fkey bhmap_fkey = { .cmp = char_cmp,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = char_hash,
|
||||
.pri = NULL };
|
||||
|
||||
struct bhmap_s_fval bhmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
struct bhmap_s *dict = bhmap_new(16, 0.7, &bhmap_fkey, &bhmap_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
bhmap_insert(dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1.a, "%u", rand_get() );
|
||||
char_array_t *val = bhmap_get_ref(dict, s1);
|
||||
if (val != 0)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
bhmap_free(dict);
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
//{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CMC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+24
-19
@@ -93,7 +93,7 @@ static void test_rbtree(size_t n)
|
||||
stat = treetable_new(compare, &tree);
|
||||
if (stat != CC_OK) abort();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *key = (void*)(uintptr_t) i;
|
||||
void *key = (void*)(uintptr_t) rand_get();
|
||||
stat = treetable_add(tree, key, key);
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
@@ -122,11 +122,11 @@ static int equal_func(const void *key1, const void *key2)
|
||||
{
|
||||
const unsigned long pa = (uintptr_t) key1;
|
||||
const unsigned long pb = (uintptr_t) key2;
|
||||
return pa == pb;
|
||||
return (pa < pb) ? -1 : pa > pb;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
test_dict(size_t n)
|
||||
{
|
||||
HashTable *dict;
|
||||
enum cc_stat stat;
|
||||
@@ -138,8 +138,8 @@ test_dict(unsigned long n)
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *key = (void*)(uintptr_t) rand_get();
|
||||
void *value = (void*)(uintptr_t) rand_get();
|
||||
void *key = (void*)(uintptr_t) rand_get();
|
||||
stat = hashtable_add(dict, key, value );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
@@ -164,7 +164,7 @@ static int char_equal (const void* a, const void * b)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
return strcmp(*pa,*pb)==0;
|
||||
return strcmp(*pa,*pb);
|
||||
}
|
||||
|
||||
static size_t char_hash(const void *a, int l, uint32_t seed)
|
||||
@@ -178,7 +178,7 @@ static size_t char_hash(const void *a, int l, uint32_t seed)
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashTable *dict;
|
||||
enum cc_stat stat;
|
||||
@@ -189,9 +189,14 @@ test_dict_big(unsigned long n)
|
||||
stat = hashtable_new_conf(&htc, &dict);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
char_array_t **tab = malloc (sizeof(char_array_t *)*2*n);
|
||||
if (!tab) abort();
|
||||
size_t cpt = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t *key = malloc (sizeof (char_array_t));
|
||||
char_array_t *value = malloc (sizeof (char_array_t));
|
||||
tab[cpt++] = key;
|
||||
tab[cpt++] = value;
|
||||
sprintf(*key, "%u", rand_get());
|
||||
sprintf(*value, "%u", rand_get());
|
||||
stat = hashtable_add(dict, key, value );
|
||||
@@ -209,6 +214,9 @@ test_dict_big(unsigned long n)
|
||||
}
|
||||
g_result = s;
|
||||
hashtable_destroy(dict);
|
||||
if (cpt != 2*n) abort();
|
||||
for(size_t i = 0; i < 2*n;i++)
|
||||
free(tab[i]);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
@@ -242,20 +250,17 @@ static void test_sort(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 30)
|
||||
test_function("Rbtree time", 1000000, test_rbtree);
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
test("CollectionC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -6,11 +6,8 @@
|
||||
|
||||
#include "concurrentqueue.h"
|
||||
|
||||
#include "m-mutex.h"
|
||||
#define MULTI_THREAD_MEASURE
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
moodycamel::ConcurrentQueue<unsigned int> g_buff;
|
||||
moodycamel::ConcurrentQueue<unsigned long long> g_final;
|
||||
@@ -51,7 +48,7 @@ static void prod(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(size_t n)
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
@@ -88,11 +85,12 @@ static void test_buffer(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 60)
|
||||
test_function("Buffer time", 1000000, test_buffer);
|
||||
test("CONCURRENT-QUEUE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-core.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/********************************************************************************************/
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec_uint a1 = vec_uint_init();
|
||||
vec_uint a2 = vec_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_uint_push_back(&a1, rand_get() );
|
||||
vec_uint_push_back(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *vec_uint_at(&a1, i ) * *vec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
vec_uint_free(&a1);
|
||||
vec_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/forward_list.h"
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
slist_uint a1 = slist_uint_init();
|
||||
slist_uint a2 = slist_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
slist_uint_push_front(&a1, rand_get());
|
||||
slist_uint_push_front(&a2, rand_get());
|
||||
}
|
||||
unsigned int s = 0;
|
||||
slist_uint_it it1 = slist_uint_begin(&a1);
|
||||
slist_uint_it it2 = slist_uint_begin(&a2);
|
||||
for( ; !slist_uint_it_done(&it1) ;
|
||||
slist_uint_it_next(&it1), slist_uint_it_next(&it2)) {
|
||||
s += *slist_uint_it_ref(&it1) * *slist_uint_it_ref(&it2);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
slist_uint_free(&a1);
|
||||
slist_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T ulong
|
||||
#include "ctl/set.h"
|
||||
|
||||
static inline int
|
||||
int_cmp(ulong *a, ulong *b) {
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set_ulong tree = set_ulong_init (int_cmp);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set_ulong_insert (&tree, rand_get() );
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (set_ulong_find_node(&tree, j) != NULL)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
set_ulong_free(&tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} pair_ulong;
|
||||
|
||||
// Use of M*LIB hash function
|
||||
static inline size_t
|
||||
pair_ulong_hash(pair_ulong *a)
|
||||
{
|
||||
return M_HASH_DEFAULT(a->key);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pair_ulong_equal(pair_ulong *a, pair_ulong *b)
|
||||
{
|
||||
return a->key == b->key;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pair_ulong_free(pair_ulong *a) {
|
||||
(void) a;
|
||||
}
|
||||
|
||||
static inline pair_ulong
|
||||
pair_ulong_copy(pair_ulong *self) {
|
||||
return (pair_ulong) { .key = self->key, .value = self->value };
|
||||
}
|
||||
|
||||
#define T pair_ulong
|
||||
#include <ctl/unordered_map.h>
|
||||
|
||||
// It seems broken: it doesn't output the expected result.
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
umap_pair_ulong dict = umap_pair_ulong_init(pair_ulong_hash, pair_ulong_equal);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_insert(&dict, (pair_ulong) { rand_get(), rand_get() });
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_it it = umap_pair_ulong_find(&dict, (pair_ulong) { rand_get() , 0 } );
|
||||
if (!umap_pair_ulong_it_done(&it) )
|
||||
s += it.ref->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
umap_pair_ulong_free(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T float
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vec_float a1 = vec_float_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_float_push_back(&a1, rand_get());
|
||||
}
|
||||
vec_float_sort(&a1);
|
||||
g_result = *vec_float_at(&a1, 0);
|
||||
vec_float_free(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 50, "Sort", 10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CTL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ using namespace std;
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
dense_hash_map<unsigned long, unsigned long> dict;
|
||||
dict.set_empty_key(-1);
|
||||
@@ -75,7 +75,7 @@ namespace std {
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
dense_hash_map<char_array_s, char_array_s> dict;
|
||||
struct char_array_s empty, del;
|
||||
@@ -104,7 +104,7 @@ test_dict_big(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
dense_hash_map<string, string> dict;
|
||||
string empty, del;
|
||||
@@ -131,14 +131,14 @@ test_dict_str(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 42)
|
||||
test_function("Dict(u)time", 1000000, test_dict2);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 43)
|
||||
test_function("DictS(u) time", 1000000, test_dict_str);
|
||||
test("DENSE-HASPMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "emilib/hash_map.hpp"
|
||||
|
||||
using namespace emilib;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashMap<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
HashMap<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("EMILIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// program to find longest contiguous subsequence
|
||||
// based on https://www.geeksforgeeks.org/longest-consecutive-subsequence/
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int cpp_find_longest(int arr[], int n)
|
||||
{
|
||||
unordered_set<int> S;
|
||||
int ans = 0;
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
S.insert(arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
if (S.find(arr[i] - 1) == S.end()) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (S.find(j) != S.end())
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = max(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(int a, unsigned char c) { return a == ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
static inline void oor_set(int *a, unsigned char c) { *a = ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
|
||||
DICT_OASET_DEF(dict_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)))
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int mlib_find_longest(int arr[], int n)
|
||||
{
|
||||
dict_int_t S;
|
||||
int ans = 0;
|
||||
|
||||
dict_int_init(S);
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
dict_int_push(S, arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
int *p = dict_int_get(S, arr[i]-1);
|
||||
if (p == NULL) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (dict_int_get(S, j) != NULL)
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = M_MAX(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
dict_int_clear(S);
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = argc == 1 ? 10000 : atoi(argv[1]);
|
||||
int *arr = (int*) malloc(n * sizeof(int));
|
||||
for(int i = 0; i < n; i++)
|
||||
arr[i] = rand_get();
|
||||
|
||||
unsigned long long t0 = cputime();
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< cpp_find_longest(arr, n) << endl;
|
||||
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< mlib_find_longest(arr, n) << endl;
|
||||
unsigned long long t2 = cputime();
|
||||
|
||||
cout << "Time C++: " << (t1-t0) << " Time M*LIB: " << (t2-t1) << endl;
|
||||
return 0;
|
||||
}
|
||||
+28
-10
@@ -26,7 +26,7 @@ using namespace std;
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
flat_hash_map<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
@@ -42,6 +42,23 @@ test_dict2(unsigned long n)
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
flat_hash_map<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
flat_hash_map<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
@@ -62,7 +79,7 @@ namespace std {
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
flat_hash_map<char_array_s, char_array_s> dict;
|
||||
|
||||
@@ -86,7 +103,7 @@ test_dict_big(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
flat_hash_map<string, string> dict;
|
||||
|
||||
@@ -108,14 +125,15 @@ test_dict_str(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 42)
|
||||
test_function("Dict(u)time", 1000000, test_dict2);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 43)
|
||||
test_function("DictS(u) time", 1000000, test_dict_str);
|
||||
test("FLAT-HASPMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+12
-15
@@ -97,7 +97,7 @@ static gboolean equal_func(gconstpointer a, gconstpointer b)
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
test_dict(size_t n)
|
||||
{
|
||||
GHashTable *dict = g_hash_table_new_full(hash_func, equal_func, free, free);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
@@ -140,7 +140,7 @@ static guint char_hash(gconstpointer a)
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
GHashTable *dict = g_hash_table_new_full(char_hash, char_equal, free, free);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
@@ -186,20 +186,17 @@ static void test_sort(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 30)
|
||||
test_function("Rbtree time", 1000000, test_rbtree);
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
test("GLIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "src/hopscotch_map.h"
|
||||
#include "hopscotch_map.h"
|
||||
|
||||
using namespace tsl;
|
||||
using namespace std;
|
||||
@@ -25,7 +25,7 @@ using namespace std;
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
tsl::hopscotch_map<unsigned long, unsigned long> dict;
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace std {
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
hopscotch_map<char_array_s, char_array_s> dict;
|
||||
|
||||
@@ -87,7 +87,7 @@ test_dict_big(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
hopscotch_map<string, string> dict;
|
||||
|
||||
@@ -109,14 +109,15 @@ test_dict_str(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 42)
|
||||
test_function("Dict(u)time", 1000000, test_dict2);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 43)
|
||||
test_function("DictS(u) time", 1000000, test_dict_str);
|
||||
test("HOPSCOTCHMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
|
||||
}
|
||||
+13
-16
@@ -82,7 +82,7 @@ static void test_rbtree(size_t n)
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = 0;
|
||||
unsigned long j = rand_get();
|
||||
if (kb_getp(kTree, tree, &j) != 0)
|
||||
s+= j;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ static void test_rbtree(size_t n)
|
||||
KHASH_INIT(iun, unsigned long, unsigned long, 1, hash_func, hash_eq)
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
test_dict(size_t n)
|
||||
{
|
||||
khash_t(iun) *dict = kh_init(iun);
|
||||
|
||||
@@ -137,7 +137,7 @@ static inline size_t char_hash(const char_array_t a) {
|
||||
KHASH_INIT(iub, char_array_t, char_array_t, 1, char_hash, char_equal_p)
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
khash_t(iub) *dict = kh_init(iub);
|
||||
|
||||
@@ -185,21 +185,18 @@ static void test_sort(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]): 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 30)
|
||||
test_function("B-tree time", 1000000, test_rbtree);
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
test("KLIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+42
-28
@@ -5,6 +5,10 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Needed due to compilation error in pool.h
|
||||
#include <pthread.h>
|
||||
|
||||
#include "dynamic.h"
|
||||
|
||||
@@ -29,30 +33,37 @@ static void test_array(size_t n)
|
||||
s += *(unsigned int*) vector_at(&a1, i) * *(unsigned int*) vector_at(&a2, i);
|
||||
}
|
||||
g_result = s;
|
||||
vector_destruct(&a1);
|
||||
vector_destruct(&a2);
|
||||
vector_destruct(&a1, NULL);
|
||||
vector_destruct(&a2, NULL);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static size_t hash_func (map *m, void *a)
|
||||
static size_t hash_func (void *a)
|
||||
{
|
||||
return hash_data(a, sizeof (unsigned long));
|
||||
}
|
||||
|
||||
static int equal_func(map *m, void *a, void *b)
|
||||
static int equal_func(void *a, void *b)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
if (b == NULL) {
|
||||
return *pa == -1U;
|
||||
}
|
||||
const unsigned long *pb = b;
|
||||
return *pa == *pb;
|
||||
}
|
||||
|
||||
static void set_func(map *m, void *a, void *b)
|
||||
static void set_func(void *a, void *b)
|
||||
{
|
||||
unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
*pa = *pb;
|
||||
if (b == NULL) {
|
||||
*pa = -1U;
|
||||
} else {
|
||||
const unsigned long *pb = b;
|
||||
*pa = *pb;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct map_element map_element;
|
||||
@@ -63,13 +74,13 @@ struct map_element
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
test_dict(size_t n)
|
||||
{
|
||||
map dict;
|
||||
map_construct(&dict, sizeof(map_element), (map_element[]) {{.key = -1}}, set_func);
|
||||
map_construct(&dict, sizeof(map_element), set_func);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
map_insert(&dict, (map_element[]) {{.key = rand_get(), .value = rand_get()}}, hash_func, equal_func, set_func, NULL);
|
||||
map_insert(&dict, (map_element[]) {{.key = rand_get(), .value = rand_get()}}, hash_func, set_func, equal_func, NULL);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
@@ -86,24 +97,30 @@ test_dict(unsigned long n)
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
static int char_equal (map *m, void *a, void *b)
|
||||
static int char_equal (void *a, void *b)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
if (b == NULL)
|
||||
return strcmp(*pa, "") == 0;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
return strcmp(*pa,*pb)==0;
|
||||
}
|
||||
|
||||
static size_t char_hash(map *m, void *a)
|
||||
static size_t char_hash(void *a)
|
||||
{
|
||||
char_array_t *pa = (char_array_t *)a;
|
||||
return hash_string(*pa);
|
||||
}
|
||||
|
||||
static void char_set(map *m, void *a, void *b)
|
||||
static void char_set(void *a, void *b)
|
||||
{
|
||||
char_array_t *pa = (char_array_t *)a;
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
strcpy(*pa,*pb);
|
||||
if (b == NULL) {
|
||||
strcpy(*pa, "");
|
||||
} else {
|
||||
const char_array_t *pb = (const char_array_t *)b;
|
||||
strcpy(*pa,*pb);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct big_map_element big_map_element;
|
||||
@@ -114,19 +131,16 @@ struct big_map_element
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
map dict;
|
||||
big_map_element empty;
|
||||
strcpy(empty.key, "");
|
||||
strcpy(empty.value, "");
|
||||
map_construct(&dict, sizeof(big_map_element), &empty, char_set);
|
||||
map_construct(&dict, sizeof(big_map_element), char_set);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
big_map_element el;
|
||||
sprintf(el.key, "%u", rand_get());
|
||||
sprintf(el.value, "%u", rand_get());
|
||||
map_insert(&dict, &el, char_hash, char_equal, char_set, NULL);
|
||||
map_insert(&dict, &el, char_hash, char_set, char_equal, NULL);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
@@ -143,14 +157,14 @@ test_dict_big(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 41)
|
||||
test_function("Dict B time", 1000000, test_dict_big);
|
||||
test("LIBDYNAMIC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+14
-28
@@ -6,11 +6,8 @@
|
||||
|
||||
#include "liblfds711.h"
|
||||
|
||||
#include "m-mutex.h"
|
||||
#define MULTI_THREAD_MEASURE
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct lfds711_queue_bmm_state g_buff;
|
||||
@@ -23,12 +20,9 @@ static void final(void *arg)
|
||||
unsigned long long j, s = 0;
|
||||
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
for(int i = 0; i < n;i++) {
|
||||
int rv;
|
||||
do {
|
||||
void *p;
|
||||
rv = lfds711_queue_bmm_dequeue(&g_final, &p, NULL);
|
||||
j = (uintptr_t)p;
|
||||
} while (rv == 0);
|
||||
void *p;
|
||||
while (0 == lfds711_queue_bmm_dequeue(&g_final, &p, NULL)) { m_thread_yield(); }
|
||||
j = (uintptr_t)p;
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
@@ -42,18 +36,12 @@ static void conso(void *arg)
|
||||
unsigned long long s = 0;
|
||||
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
for(int i = 0; i < n;i++) {
|
||||
int rv;
|
||||
do {
|
||||
void *p;
|
||||
rv = lfds711_queue_bmm_dequeue(&g_buff, &p, NULL);
|
||||
j = (uintptr_t) p;
|
||||
} while (rv == 0);
|
||||
void *p;
|
||||
while (0 == lfds711_queue_bmm_dequeue(&g_buff, &p, NULL)) { m_thread_yield(); }
|
||||
j = (uintptr_t) p;
|
||||
s += j;
|
||||
}
|
||||
int rv;
|
||||
do {
|
||||
rv = lfds711_queue_bmm_enqueue(&g_final, (void*)(uintptr_t)s, NULL);
|
||||
} while (rv == 0);
|
||||
while (0 == lfds711_queue_bmm_enqueue(&g_final, (void*)(uintptr_t)s, NULL)) { m_thread_yield(); }
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
@@ -63,15 +51,12 @@ static void prod(void *arg)
|
||||
size_t r = n;
|
||||
LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
int rv;
|
||||
do {
|
||||
rv = lfds711_queue_bmm_enqueue(&g_buff, (void*)(uintptr_t)r, NULL);
|
||||
} while (rv == 0);
|
||||
while (0 == lfds711_queue_bmm_enqueue(&g_buff, (void*)(uintptr_t)r, NULL)) { m_thread_yield(); }
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(size_t n)
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
@@ -120,11 +105,12 @@ static void test_buffer(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 60)
|
||||
test_function("Buffer time", 1000000, test_buffer);
|
||||
test("LIBLFDS", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+10
-8
@@ -14,8 +14,8 @@
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
sv_t *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
sv_t *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
srt_vector *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
srt_vector *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
@@ -48,7 +48,7 @@ static int cmp_float (const void *a, const void *b)
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
sv_t *a1 = sv_alloc(sizeof(float), 16, cmp_float);
|
||||
srt_vector *a1 = sv_alloc(sizeof(float), 16, cmp_float);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
sv_push(&a1, &value );
|
||||
@@ -60,13 +60,15 @@ static void test_sort(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 50, "sort", 10000000, 0, test_sort, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
test("LIBSRT", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
+665
-82
@@ -7,12 +7,19 @@
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-bptree.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-mempool.h"
|
||||
#include "m-string.h"
|
||||
#include "m-buffer.h"
|
||||
#include "m-mutex.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-concurrent.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-serial-bin.h"
|
||||
#include "m-serial-json.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -37,6 +44,30 @@ static void test_array(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
DEQUE_DEF(deque_uint, unsigned int)
|
||||
|
||||
static void test_deque(size_t n)
|
||||
{
|
||||
M_LET(a1, a2, DEQUE_OPLIST(deque_uint)) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
deque_uint_push_back(a1, rand_get() );
|
||||
deque_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
deque_uint_it_t it1, it2;
|
||||
deque_uint_it(it1, a1);
|
||||
deque_uint_it(it2, a2);
|
||||
while (!deque_uint_end_p(it1)) {
|
||||
s += *deque_uint_cref(it1 ) * *deque_uint_cref(it2 );
|
||||
deque_uint_next(it1);
|
||||
deque_uint_next(it2);
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// Two benched mode: with or without mempool
|
||||
#ifdef USE_MEMPOOL
|
||||
LIST_DEF(list_uint, unsigned int, (MEMPOOL( list_mpool), MEMPOOL_LINKAGE(static)))
|
||||
@@ -68,6 +99,37 @@ static void test_list (size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// Two benched mode: with or without mempool
|
||||
#ifdef USE_MEMPOOL
|
||||
LIST_DUAL_PUSH_DEF(dlist_uint, unsigned int, (MEMPOOL( dlist_mpool), MEMPOOL_LINKAGE(static)))
|
||||
#else
|
||||
LIST_DUAL_PUSH_DEF(dlist_uint, unsigned int)
|
||||
#endif
|
||||
|
||||
static void test_dlist (size_t n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
dlist_uint_mempool_init(dlist_mpool);
|
||||
#endif
|
||||
M_LET(a1, a2, LIST_OPLIST(dlist_uint)) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
dlist_uint_push_back(a1, rand_get() );
|
||||
dlist_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
dlist_uint_it_t it1, it2;
|
||||
for(dlist_uint_it(it1, a1), dlist_uint_it(it2,a2); !dlist_uint_end_p(it1); dlist_uint_next(it1), dlist_uint_next(it2)) {
|
||||
s += *dlist_uint_cref(it1) * *dlist_uint_cref(it2);
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
#ifdef USE_MEMPOOL
|
||||
dlist_uint_mempool_clear(dlist_mpool);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
RBTREE_DEF(rbtree_ulong, unsigned long, (MEMPOOL( rbtree_mpool), MEMPOOL_LINKAGE(static)))
|
||||
#else
|
||||
@@ -99,6 +161,27 @@ static void test_rbtree(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
BPTREE_DEF(bptree_ulong, 21, unsigned long, M_DEFAULT_OPLIST)
|
||||
|
||||
static void test_bptree(size_t n)
|
||||
{
|
||||
M_LET(tree, BPTREE_OPLIST(bptree_ulong)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
bptree_ulong_push(tree, rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *p = bptree_ulong_get(tree, rand_get());
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
DICT_DEF2(dict_ulong, unsigned long, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(dict_mpool), MEMPOOL_LINKAGE(static)), unsigned long, M_DEFAULT_OPLIST)
|
||||
#else
|
||||
@@ -106,15 +189,16 @@ DICT_DEF2(dict_ulong, unsigned long, M_DEFAULT_OPLIST, unsigned long, M_DEFAULT_
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
test_dict(size_t n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_ulong_list_pair_mempool_init(dict_mpool);
|
||||
#endif
|
||||
M_LET(dict, DICT_OPLIST(dict_ulong)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
dict_ulong_set_at(dict, key, rand_get() );
|
||||
dict_ulong_set_at(dict, key, value);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
@@ -147,7 +231,7 @@ DICT_OA_DEF2(dict_oa_ulong,
|
||||
unsigned long, M_DEFAULT_OPLIST)
|
||||
|
||||
static void
|
||||
test_dict_oa(unsigned long n)
|
||||
test_dict_oa(size_t n)
|
||||
{
|
||||
M_LET(dict, DICT_OPLIST(dict_oa_ulong)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
@@ -164,26 +248,46 @@ test_dict_oa(unsigned long n)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_oa_linear(size_t n)
|
||||
{
|
||||
M_LET(dict, DICT_OPLIST(dict_oa_ulong)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict_oa_ulong_set_at(dict, i, rand_get() );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *p = dict_oa_ulong_get(dict, i);
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
#ifndef CHAR_ARRAY_SIZE
|
||||
#define CHAR_ARRAY_SIZE 256
|
||||
#endif
|
||||
typedef char char_array_t[CHAR_ARRAY_SIZE];
|
||||
static void char_init (char_array_t a) { a[0] = 0; }
|
||||
static void char_set (char_array_t a, const char_array_t b) { strcpy(a, b); }
|
||||
static bool char_equal_p (const char_array_t a, const char_array_t b) { return strcmp(a,b)==0; }
|
||||
static size_t char_hash(const char_array_t a) { return m_core_hash (a, strlen(a)); }
|
||||
|
||||
// NOTE: Can't use the name OPLIST as a macro!
|
||||
#define CHAR_OPLIST (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p))
|
||||
static bool char_oor_equal_p(const char_array_t a, unsigned char n) { return a[0] == 1+n; }
|
||||
static void char_oor_set(char_array_t a, unsigned char n) { a[0] = 1+n; }
|
||||
#define M_OPL_char_array_t() (INIT(char_init), INIT_SET(char_set), SET(char_set), CLEAR(char_init), HASH(char_hash), EQUAL(char_equal_p), OOR_EQUAL(char_oor_equal_p), OOR_SET(char_oor_set))
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
DICT_DEF2(dict_char, char_array_t, M_OPEXTEND(CHAR_OPLIST,MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, CHAR_OPLIST)
|
||||
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPEXTEND(M_OPL_char_array_t(),MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, M_OPL_char_array_t())
|
||||
#else
|
||||
DICT_DEF2(dict_char, char_array_t, CHAR_OPLIST, char_array_t, CHAR_OPLIST)
|
||||
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPL_char_array_t(), char_array_t, M_OPL_char_array_t())
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_char_list_pair_mempool_init(dict_mpool2);
|
||||
@@ -211,6 +315,31 @@ test_dict_big(unsigned long n)
|
||||
#endif
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_oa_char, char_array_t, char_array_t)
|
||||
|
||||
static void
|
||||
test_dict_oa_big(size_t n)
|
||||
{
|
||||
M_LET(dict, DICT_OPLIST(dict_oa_char)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1, "%u", rand_get());
|
||||
sprintf(s2, "%u", rand_get());
|
||||
dict_oa_char_set_at(dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1, "%u", rand_get());
|
||||
char_array_t *p = dict_oa_char_get(dict, s1);
|
||||
if (p)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
@@ -220,7 +349,7 @@ DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_str_list_pair_mempool_init(dict_mpool3);
|
||||
@@ -263,75 +392,89 @@ static void test_sort(size_t n)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_stable_sort(size_t n)
|
||||
{
|
||||
M_LET(a1, ARRAY_OPLIST(array_float)) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
array_float_push_back(a1, rand_get() );
|
||||
}
|
||||
array_float_special_stable_sort(a1);
|
||||
g_result = *array_float_get(a1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define SIZE_LIMIT (UINT_MAX/2)
|
||||
|
||||
BUFFER_DEF(buffer_uint, unsigned int, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
|
||||
buffer_uint_t g_buff;
|
||||
buffer_uint_t g_buff_lock;
|
||||
|
||||
BUFFER_DEF(buffer_ull, unsigned long long, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
|
||||
buffer_ull_t g_final;
|
||||
buffer_ull_t g_final_lock;
|
||||
|
||||
static void final(void *arg)
|
||||
static void final_lock(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
buffer_ull_pop(&j, g_final);
|
||||
buffer_ull_pop(&j, g_final_lock);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
static void conso_lock(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
buffer_uint_pop(&j, g_buff);
|
||||
buffer_uint_pop(&j, g_buff_lock);
|
||||
s += j;
|
||||
}
|
||||
buffer_ull_push(g_final, s);
|
||||
buffer_ull_push(g_final_lock, s);
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
static void prod_lock(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
buffer_uint_push(g_buff, r );
|
||||
buffer_uint_push(g_buff_lock, r );
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int cpu_count = n > SIZE_LIMIT ? 2 : get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
n = n > SIZE_LIMIT ? n - SIZE_LIMIT : n;
|
||||
// Init
|
||||
buffer_uint_init(g_buff, 64*cpu_count);
|
||||
buffer_ull_init (g_final, 64*cpu_count);
|
||||
buffer_uint_init(g_buff_lock, 64*cpu_count);
|
||||
buffer_ull_init (g_final_lock, 64*cpu_count);
|
||||
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
m_thread_create (idx_p[i], prod_lock, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
m_thread_create (idx_c[i], conso_lock, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
m_thread_create(idx_final, final_lock, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
@@ -343,79 +486,80 @@ static void test_buffer(size_t n)
|
||||
m_thread_join(idx_final);
|
||||
|
||||
// Clear & quit
|
||||
buffer_ull_clear(g_final);
|
||||
buffer_uint_clear(g_buff);
|
||||
buffer_ull_clear(g_final_lock);
|
||||
buffer_uint_clear(g_buff_lock);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE)
|
||||
queue_uint_t g_buff2;
|
||||
queue_uint_t g_buff_mpmc;
|
||||
|
||||
QUEUE_MPMC_DEF(queue_ull, unsigned long long, BUFFER_QUEUE)
|
||||
queue_ull_t g_final2;
|
||||
queue_ull_t g_final_mpmc;
|
||||
|
||||
static void final2(void *arg)
|
||||
static void final_mpmc(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
while (!queue_ull_pop(&j, g_final2));
|
||||
while (!queue_ull_pop(&j, g_final_mpmc)) m_thread_yield();
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso2(void *arg)
|
||||
static void conso_mpmc(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
while (!queue_uint_pop(&j, g_buff2));
|
||||
while (!queue_uint_pop(&j, g_buff_mpmc)) m_thread_yield();
|
||||
s += j;
|
||||
}
|
||||
while (!queue_ull_push(g_final2, s));
|
||||
while (!queue_ull_push(g_final_mpmc, s));
|
||||
}
|
||||
|
||||
static void prod2(void *arg)
|
||||
static void prod_mpmc(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!queue_uint_push(g_buff2, r ));
|
||||
while (!queue_uint_push(g_buff_mpmc, r )) m_thread_yield();
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int cpu_count = n > SIZE_LIMIT ? 2 : get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Queue performance.\n");
|
||||
return;
|
||||
}
|
||||
n = n > SIZE_LIMIT ? n - SIZE_LIMIT : n;
|
||||
// Init
|
||||
queue_uint_init(g_buff2, 64*cpu_count);
|
||||
queue_ull_init (g_final2, 64*cpu_count);
|
||||
queue_uint_init(g_buff_mpmc, 64*cpu_count);
|
||||
queue_ull_init (g_final_mpmc, 64*cpu_count);
|
||||
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod2, &n);
|
||||
m_thread_create (idx_p[i], prod_mpmc, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso2, &n);
|
||||
m_thread_create (idx_c[i], conso_mpmc, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final2, &n2);
|
||||
m_thread_create(idx_final, final_mpmc, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
@@ -427,8 +571,265 @@ static void test_queue(size_t n)
|
||||
m_thread_join(idx_final);
|
||||
|
||||
// Clear & quit
|
||||
queue_ull_clear(g_final2);
|
||||
queue_uint_clear(g_buff2);
|
||||
queue_ull_clear(g_final_mpmc);
|
||||
queue_uint_clear(g_buff_mpmc);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
QUEUE_SPSC_DEF(queue_single_uint, unsigned int, BUFFER_QUEUE)
|
||||
queue_single_uint_t g_buff_spsc;
|
||||
|
||||
QUEUE_SPSC_DEF(queue_single_ull, unsigned long long, BUFFER_QUEUE)
|
||||
queue_single_ull_t g_final_spsc;
|
||||
|
||||
static void final_spsc(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
while (!queue_single_ull_pop(&j, g_final_spsc)) m_thread_yield();
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso_spsc(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
while (!queue_single_uint_pop(&j, g_buff_spsc)) m_thread_yield();
|
||||
s += j;
|
||||
}
|
||||
while (!queue_single_ull_push(g_final_spsc, s));
|
||||
}
|
||||
|
||||
static void prod_spsc(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
while (!queue_single_uint_push(g_buff_spsc, r )) m_thread_yield();
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue_single(size_t n)
|
||||
{
|
||||
const int cpu_count = 2;
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
// Init
|
||||
queue_single_uint_init(g_buff_spsc, 64*cpu_count);
|
||||
queue_single_ull_init (g_final_spsc, 64*cpu_count);
|
||||
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod_spsc, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso_spsc, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final_spsc, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
// Clear & quit
|
||||
queue_single_ull_clear(g_final_spsc);
|
||||
queue_single_uint_clear(g_buff_spsc);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define BULK_SIZE 20
|
||||
|
||||
static void final_spsc_bulk(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
while (!queue_single_ull_pop(&j, g_final_spsc)) m_thread_yield();
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso_spsc_bulk(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
unsigned tab[BULK_SIZE];
|
||||
for(int i = 0; i < n;i+= BULK_SIZE) {
|
||||
unsigned k = queue_single_uint_pop_bulk(BULK_SIZE, tab, g_buff_spsc);
|
||||
while (k != BULK_SIZE) {
|
||||
m_thread_yield();
|
||||
k += queue_single_uint_pop_bulk(BULK_SIZE-k, tab+k, g_buff_spsc);
|
||||
}
|
||||
for(k = 0; k < BULK_SIZE;k++)
|
||||
s += tab[k];
|
||||
}
|
||||
while (!queue_single_ull_push(g_final_spsc, s));
|
||||
}
|
||||
|
||||
static void prod_spsc_bulk(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
if ((n % BULK_SIZE) != 0) abort();
|
||||
size_t r = n;
|
||||
unsigned tab[BULK_SIZE];
|
||||
for(unsigned int i = 0; i < n;i+= BULK_SIZE) {
|
||||
for(unsigned k = 0; k < BULK_SIZE; k++) {
|
||||
tab[k] = r;
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
unsigned k = queue_single_uint_push_bulk(g_buff_spsc, BULK_SIZE, tab);
|
||||
while (k != BULK_SIZE) {
|
||||
m_thread_yield();
|
||||
k += queue_single_uint_push_bulk(g_buff_spsc, BULK_SIZE-k, tab+k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue_single_bulk(size_t n)
|
||||
{
|
||||
const int cpu_count = 2;
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
// Init
|
||||
queue_single_uint_init(g_buff_spsc, 64*cpu_count);
|
||||
queue_single_ull_init (g_final_spsc, 64*cpu_count);
|
||||
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod_spsc_bulk, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso_spsc_bulk, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final_spsc_bulk, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
// Clear & quit
|
||||
queue_single_ull_clear(g_final_spsc);
|
||||
queue_single_uint_clear(g_buff_spsc);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
CONCURRENT_DEF(cdeque_uint, deque_uint_t, M_OPEXTEND(DEQUE_OPLIST(deque_uint, M_DEFAULT_OPLIST), PUSH(deque_uint_push_front)))
|
||||
|
||||
DEQUE_DEF(deque_ull, unsigned long long)
|
||||
CONCURRENT_DEF(cdeque_ull, deque_ull_t, M_OPEXTEND(DEQUE_OPLIST(deque_ull, M_DEFAULT_OPLIST), PUSH(deque_ull_push_front)))
|
||||
|
||||
cdeque_uint_t g_buff_conc;
|
||||
cdeque_ull_t g_final_conc;
|
||||
|
||||
static void final_conc(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
cdeque_ull_pop_blocking(&j, g_final_conc, true);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso_conc(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(int i = 0; i < n;i++) {
|
||||
cdeque_uint_pop_blocking(&j, g_buff_conc, true);
|
||||
s += j;
|
||||
}
|
||||
cdeque_ull_push(g_final_conc, s);
|
||||
}
|
||||
|
||||
static void prod_conc(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
cdeque_uint_push(g_buff_conc, r );
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue_concurrent(size_t n)
|
||||
{
|
||||
const int cpu_count = n > SIZE_LIMIT ? 2 : get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure CONCURRENT performance.\n");
|
||||
return;
|
||||
}
|
||||
n = n > SIZE_LIMIT ? n - SIZE_LIMIT : n;
|
||||
// Init
|
||||
cdeque_uint_init(g_buff_conc);
|
||||
cdeque_ull_init (g_final_conc);
|
||||
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod_conc, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso_conc, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final_conc, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
// Clear & quit
|
||||
cdeque_ull_clear(g_final_conc);
|
||||
cdeque_uint_clear(g_buff_conc);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
@@ -465,43 +866,225 @@ static void test_core_hash(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(vector_string, string_t)
|
||||
|
||||
vector_string_t vstring;
|
||||
vector_string_t vstring2;
|
||||
|
||||
static void
|
||||
bench_vector_string_init(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu", i, i, i, i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
vector_string_init(vstring2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_init_big(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
vector_string_init(vstring2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_bin_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_write_t) {
|
||||
vector_string_out_serial(serial, vstring);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.dat", "rb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_read_t) {
|
||||
vector_string_in_serial(vstring2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_write_t) {
|
||||
vector_string_out_serial(serial, vstring);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_read_t) {
|
||||
vector_string_in_serial(vstring2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (!vector_string_equal_p(vstring, vstring2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
vector_string_clear(vstring);
|
||||
vector_string_clear(vstring2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(vector_ulong, unsigned long)
|
||||
|
||||
vector_ulong_t vulong;
|
||||
vector_ulong_t vulong2;
|
||||
|
||||
static void
|
||||
bench_vector_ulong_init(size_t n)
|
||||
{
|
||||
vector_ulong_init(vulong);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
vector_ulong_push_back(vulong, i*i);
|
||||
}
|
||||
vector_ulong_init(vulong2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_bin_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_write_t) {
|
||||
vector_ulong_out_serial(serial, vulong);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.dat", "rb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_read_t) {
|
||||
vector_ulong_in_serial(vulong2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_write_t) {
|
||||
vector_ulong_out_serial(serial, vulong);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_read_t) {
|
||||
vector_ulong_in_serial(vulong2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (!vector_ulong_equal_p(vulong, vulong2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
vector_ulong_clear(vulong);
|
||||
vector_ulong_clear(vulong2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 11, "DPList", 10000000, 0, test_dlist, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 21, "Deque", 100000000, 0, test_deque, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 31, "B+tree", 1000000, 0, test_bptree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict(OA)", 1000000, 0, test_dict_oa, 0},
|
||||
{ 43,"DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "dictLinear(OA)", 1000000, 0, test_dict_oa_linear, 0},
|
||||
{ 47, "dictBig(OA)", 1000000, 0, test_dict_oa_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
{ 51, "Stable Sort",10000000, 0, test_stable_sort, 0},
|
||||
{ 60,"Buffer", 1000000, 0, test_buffer, 0},
|
||||
{ 61,"Queue MPMC", 1000000, 0, test_queue, 0},
|
||||
{ 62,"Buffer(P=2)", SIZE_LIMIT+1000000, 0, test_buffer, 0},
|
||||
{ 63,"Queue MPMC (P=2)", SIZE_LIMIT+1000000, 0, test_queue, 0},
|
||||
{ 64,"Queue SPSC (P=2)", 1000000, 0, test_queue_single, 0},
|
||||
{ 65,"Queue Concurrent", 1000000, 0, test_queue_concurrent, 0},
|
||||
{ 66,"Queue SPSC(Bulk)", 1000000, 0, test_queue_single_bulk, 0},
|
||||
{ 70,"M_HASH", 100000000, test_hash_prepare, test_hash, test_hash_final},
|
||||
{ 71,"Core Hash", 100000000, test_hash_prepare, test_core_hash, test_hash_final},
|
||||
{100, "serial-bin STR", 10000000, bench_vector_string_init, bench_vector_string_bin_run, bench_vector_string_clear},
|
||||
{101, "serial-bin STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_bin_run, bench_vector_string_clear},
|
||||
{102, "serial-bin INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_bin_run, bench_vector_ulong_clear},
|
||||
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 30)
|
||||
test_function("Rbtree time", 1000000, test_rbtree);
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 42)
|
||||
test_function("DictOA time", 1000000, test_dict_oa);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 43)
|
||||
test_function("DictS time", 1000000, test_dict_str);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
if (n == 60)
|
||||
test_function("Buffer time", 1000000, test_buffer);
|
||||
if (n == 61)
|
||||
test_function("Queue MPMC time", 1000000, test_queue);
|
||||
if (n == 70) {
|
||||
n = (argc > 2) ? atoi(argv[2]) : 100000000;
|
||||
test_hash_prepare(n);
|
||||
test_function("M_HASH time", n, test_hash);
|
||||
test_hash_final();
|
||||
}
|
||||
if (n == 71) {
|
||||
n = (argc > 2) ? atoi(argv[2]) : 100000000;
|
||||
test_hash_prepare(n);
|
||||
test_function("CORE_HASH time", n, test_core_hash);
|
||||
test_hash_final();
|
||||
}
|
||||
|
||||
test("M-LIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#define NDEBUG
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nedtrie.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct foo_s {
|
||||
NEDTRIE_ENTRY(foo_s) link;
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} foo_t;
|
||||
typedef struct foo_tree_s foo_tree_t;
|
||||
NEDTRIE_HEAD(foo_tree_s, foo_s);
|
||||
|
||||
static inline size_t fookeyfunct(const foo_t *r)
|
||||
{
|
||||
return r->key;
|
||||
}
|
||||
|
||||
NEDTRIE_GENERATE(static, foo_tree_s, foo_s, link, fookeyfunct, NEDTRIE_NOBBLEZEROS(foo_tree_s))
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
foo_tree_t footree;
|
||||
NEDTRIE_INIT(&footree);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long val = rand_get();
|
||||
foo_t * p = malloc(sizeof(foo_t));
|
||||
if (p == NULL) abort();
|
||||
p->key = key;
|
||||
p->value = val;
|
||||
NEDTRIE_INSERT(foo_tree_s, &footree, p);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
foo_t key = { .key = rand_get() };
|
||||
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
foo_t *r, *next;
|
||||
NEDTRIE_FOREACH_SAFE(r, foo_tree_s, &footree, next) {
|
||||
// Remove is needed, otherwise it segfault
|
||||
NEDTRIE_REMOVE(foo_tree_s, &footree, r);
|
||||
free(r);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_noalloc(size_t n)
|
||||
{
|
||||
foo_tree_t footree;
|
||||
NEDTRIE_INIT(&footree);
|
||||
|
||||
foo_t *tab = malloc(n*sizeof(foo_t));
|
||||
if (tab == NULL) abort();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long val = rand_get();
|
||||
tab[i].key = key;
|
||||
tab[i].value = val;
|
||||
NEDTRIE_INSERT(foo_tree_s, &footree, &tab[i]);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
foo_t key = { .key = rand_get() };
|
||||
foo_t *p = NEDTRIE_FIND(foo_tree_s, &footree, &key);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
free(tab);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 45, "dict(noalloc)", 1000000, 0, test_dict_noalloc, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("NEDTRIES", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+10
-7
@@ -1,4 +1,5 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -97,14 +98,16 @@ static void test_rbtree(size_t n)
|
||||
|
||||
/* qlibc hash functions only accept a string as the key */
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 30)
|
||||
test_function("Rbtree time", 1000000, test_rbtree);
|
||||
test("QLIBC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+14
-18
@@ -72,7 +72,7 @@ static void test_rbtree(size_t n)
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict1(unsigned long n)
|
||||
test_dict1(size_t n)
|
||||
{
|
||||
QMap<unsigned long, unsigned long> dict;
|
||||
|
||||
@@ -92,7 +92,7 @@ test_dict1(unsigned long n)
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
QHash<unsigned long, unsigned long> dict;
|
||||
|
||||
@@ -126,7 +126,7 @@ uint qHash(const char_array_s &k)
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
QHash<char_array_s, char_array_s> dict;
|
||||
|
||||
@@ -162,22 +162,18 @@ static void test_sort(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict(m)", 1000000, 0, test_dict1, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict(u)", 1000000, 0, test_dict2, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 30)
|
||||
test_function("Rbtree time", 1000000, test_rbtree);
|
||||
if (n == 40)
|
||||
test_function("Dict(m)time", 1000000, test_dict1);
|
||||
if (n == 42)
|
||||
test_function("Dict(u)time", 1000000, test_dict2);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
test("QT", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#define NDEBUG
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<string> vstring;
|
||||
vector<string> vstring2;
|
||||
|
||||
static void
|
||||
bench_vector_string_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu", i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_init_big(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vstring.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.String(vstring[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vstring2.push_back(s.GetString());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vstring2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (vstring != vstring2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<unsigned long> vulong;
|
||||
vector<unsigned long> vulong2;
|
||||
|
||||
static void
|
||||
bench_vector_ulong_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
vulong.push_back(i*i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vulong.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.Int64(vulong[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vulong2.push_back(s.GetInt64());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vulong2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (vulong != vulong2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RAPIDJSON", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rigtorp/HashMap.h"
|
||||
|
||||
using namespace rigtorp;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// Hash for using unsigned long as lookup key
|
||||
struct UL_Hash {
|
||||
size_t operator()(const unsigned long v) { return v * 7; }
|
||||
};
|
||||
|
||||
// Equal comparison for using unsigned long as lookup key
|
||||
struct UL_Equal {
|
||||
bool operator()(const unsigned long lhs, const unsigned long rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long, UL_Hash, UL_Equal> dict(16, -1UL);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long, UL_Hash, UL_Equal>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
struct BIG_Hash {
|
||||
size_t operator()(const char_array_s v) { return hash<char_array_s>()(v); }
|
||||
};
|
||||
|
||||
struct BIG_Equal {
|
||||
bool operator()(const char_array_s lhs, const char_array_s rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
char_array_s empty;
|
||||
HashMap<char_array_s, char_array_s, BIG_Hash, BIG_Equal> dict(16, empty);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s, BIG_Hash, BIG_Equal>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct STR_Hash {
|
||||
size_t operator()(const string v) { return hash<string>()(v); }
|
||||
};
|
||||
|
||||
struct STR_Equal {
|
||||
bool operator()(const string lhs, const string rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
string empty;
|
||||
HashMap<string, string, STR_Hash, STR_Equal> dict(16, empty);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string, STR_Hash, STR_Equal>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RIGTORP-HASHMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <rigtorp/MPMCQueue.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
rigtorp::MPMCQueue<unsigned int> g_buff(4*64);
|
||||
rigtorp::MPMCQueue<unsigned long long> g_final(4*64);
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*) arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_final.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_final.push(s);
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.push(r);
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
rand_get();
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RIGTORP-MPMC-QUEUE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+10
-10
@@ -25,7 +25,7 @@ using namespace std;
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
sparse_hash_map<unsigned long, unsigned long> dict;
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace std {
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
sparse_hash_map<char_array_s, char_array_s> dict;
|
||||
|
||||
@@ -87,7 +87,7 @@ test_dict_big(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
sparse_hash_map<string, string> dict;
|
||||
|
||||
@@ -109,14 +109,14 @@ test_dict_str(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 42)
|
||||
test_function("Dict(u)time", 1000000, test_dict2);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 43)
|
||||
test_function("DictS(u) time", 1000000, test_dict_str);
|
||||
test("SPARSEPP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+73
-30
@@ -1,6 +1,7 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
@@ -53,6 +54,23 @@ static void test_array(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_deque(size_t n)
|
||||
{
|
||||
deque<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(auto it1 = a1.cbegin(), it2 = a2.cbegin();
|
||||
it1 != a1.cend() ;it1++, it2++) {
|
||||
s += *it1 * *it2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set<unsigned long> tree;
|
||||
@@ -73,7 +91,7 @@ static void test_rbtree(size_t n)
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict1(unsigned long n)
|
||||
test_dict1(size_t n)
|
||||
{
|
||||
map<unsigned long, unsigned long> dict;
|
||||
|
||||
@@ -93,7 +111,7 @@ test_dict1(unsigned long n)
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
unordered_map<unsigned long, unsigned long> dict;
|
||||
|
||||
@@ -110,6 +128,24 @@ test_dict2(unsigned long n)
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
unordered_map<unsigned long, unsigned long> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unordered_map<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct char_array_s {
|
||||
@@ -131,7 +167,7 @@ namespace std {
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
unordered_map<char_array_s, char_array_s> dict;
|
||||
|
||||
@@ -155,19 +191,19 @@ test_dict_big(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
unordered_map<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s1 = to_string(rand_get());
|
||||
string s2 = to_string(rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s1 = to_string (rand_get());
|
||||
unordered_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
@@ -176,19 +212,19 @@ test_dict_str(unsigned long n)
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_str2(unsigned long n)
|
||||
test_dict_str2(size_t n)
|
||||
{
|
||||
map<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s1 = to_string(rand_get());
|
||||
string s2 = to_string(rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s1 = to_string(rand_get());
|
||||
map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
@@ -208,28 +244,35 @@ static void test_sort(size_t n)
|
||||
g_result = a1[0];
|
||||
}
|
||||
|
||||
static void test_stable_sort(size_t n)
|
||||
{
|
||||
vector<float> a1;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
}
|
||||
stable_sort(a1.begin(), a1.end());
|
||||
g_result = a1[0];
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 21, "Deque", 100000000, 0, test_deque, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict(m)", 1000000, 0, test_dict1, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict(u)", 1000000, 0, test_dict2, 0},
|
||||
{ 43,"DictStr(u)", 1000000, 0, test_dict_str, 0},
|
||||
{ 44,"DictStr(m)", 1000000, 0, test_dict_str2, 0},
|
||||
{ 46, "dictLinear(u)", 1000000, 0, test_dict2_linear, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
{ 51, "Stable Sort",10000000, 0, test_stable_sort, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 30)
|
||||
test_function("Rbtree time", 1000000, test_rbtree);
|
||||
if (n == 40)
|
||||
test_function("Dict(m)time", 1000000, test_dict1);
|
||||
if (n == 42)
|
||||
test_function("Dict(u)time", 1000000, test_dict2);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 43)
|
||||
test_function("DictS(u) time", 1000000, test_dict_str);
|
||||
if (n == 44)
|
||||
test_function("DictS(m) time", 1000000, test_dict_str2);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
test("STL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "m-string.h"
|
||||
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
extern "C" {
|
||||
#include "sds.h"
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
#include "bstrlib.h"
|
||||
#include "bstrwrap.h"
|
||||
#include "bstraux.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BENCH
|
||||
* 2000000
|
||||
* 1. Generate N strings of random numbers 32 bits.
|
||||
* 2. Concat all strings in a string usigned a random permutation of N.
|
||||
* 3. Replace "1234" in the string into "WELL" until nothing remains.
|
||||
* 4. Replace "56789" in the string into "DONE" until nothing remains.
|
||||
* Return the final string length.
|
||||
*/
|
||||
|
||||
unsigned *permutation_tab = NULL;
|
||||
|
||||
void random_permutation(unsigned n)
|
||||
{
|
||||
if (permutation_tab) free(permutation_tab);
|
||||
permutation_tab = (unsigned *) malloc(n * sizeof(unsigned));
|
||||
if (permutation_tab == NULL) abort();
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
permutation_tab[i] = i;
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
unsigned j = rand_get() % n;
|
||||
unsigned k = rand_get() % n;
|
||||
unsigned l = permutation_tab[j];
|
||||
permutation_tab[j] = permutation_tab[k];
|
||||
permutation_tab[k] = l;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void replace_all_stl(string &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_stl(unsigned n)
|
||||
{
|
||||
vector<string> tab;
|
||||
tab.resize(n);
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
tab[i] = to_string(rand_get());
|
||||
|
||||
string str;
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
replace_all_stl(str, "1234", "WELL");
|
||||
replace_all_stl(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
|
||||
size_t bench_mlib(unsigned n)
|
||||
{
|
||||
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_init(tab[i]);
|
||||
string_printf(tab[i], "%u", rand_get());
|
||||
}
|
||||
// P2
|
||||
string_t str;
|
||||
string_init(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_cat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
string_replace_all_str(str, "1234", "WELL");
|
||||
string_replace_all_str(str, "56789", "DONE");
|
||||
size_t length = string_size(str);
|
||||
// Clean
|
||||
string_clear(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_clear(tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
|
||||
static void replace_all_bstrlib(CBString &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_bstrlib(unsigned n)
|
||||
{
|
||||
vector<CBString> tab;
|
||||
tab.resize(n);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
char tmp[10];
|
||||
sprintf(tmp, "%u", rand_get());
|
||||
tab[i] = tmp;
|
||||
}
|
||||
|
||||
CBString str;
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
replace_all_bstrlib(str, "1234", "WELL");
|
||||
replace_all_bstrlib(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
sds SDS_replace_at(sds str, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
// simple implementation as replace is not available
|
||||
sds a = sdsnewlen((const void*) str, pos);
|
||||
a = sdscat(a, str2);
|
||||
a = sdscat(a, &str[pos+len]);
|
||||
sdsfree(str);
|
||||
return a;
|
||||
}
|
||||
|
||||
sds replace_all_sds(sds str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], pattern);
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != -1U);
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t bench_sds(unsigned n)
|
||||
{
|
||||
sds *tab = (sds*) malloc (n * sizeof (sds));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
tab[i] = sdsfromlonglong(rand_get());
|
||||
}
|
||||
// P2
|
||||
sds str = sdsempty();
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
str = sdscat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
str = replace_all_sds(str, "1234", "WELL");
|
||||
str = replace_all_sds(str, "56789", "DONE");
|
||||
// Clean
|
||||
size_t length = sdslen(str);
|
||||
sdsfree(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
sdsfree(tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
unsigned length, n = atoi(argv[1]);
|
||||
unsigned select = atoi(argv[2]);
|
||||
const char *name;
|
||||
random_permutation(n);
|
||||
rand_init();
|
||||
unsigned long long t0 = cputime();
|
||||
|
||||
switch (select) {
|
||||
case 0:
|
||||
length = bench_mlib(n);
|
||||
name = "MLIB";
|
||||
break;
|
||||
case 1:
|
||||
length = bench_stl(n);
|
||||
name = "STL";
|
||||
break;
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
case 2:
|
||||
length = bench_sds(n);
|
||||
name = "SDS";
|
||||
break;
|
||||
#endif
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
case 4:
|
||||
length = bench_bstrlib(n);
|
||||
name = "BSTRLIB";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit(0);
|
||||
}
|
||||
unsigned long long t1 = cputime();
|
||||
printf("%5.5s LENGTH=%u T= %f s\n", name, length, (t1-t0) / 1000000.0 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
+590
-168
@@ -35,14 +35,27 @@
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Update of integrating M*LIB done by Patrick Pelissier */
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS & GLIB
|
||||
Copyright (c) 2018-2021 Patrick Pelissier
|
||||
*/
|
||||
|
||||
/*
|
||||
* Benchmark based on the features tested by benchmark seen here:
|
||||
* http://www.utilitycode.com/str/performance.aspx
|
||||
*
|
||||
* The idea is to measure the performance empty constructors, char *
|
||||
* constructors, assignment, concatenation and scanning.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
#define NDEBUG
|
||||
#include "common.h"
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
#include "m-string.h"
|
||||
#endif
|
||||
|
||||
@@ -56,55 +69,66 @@
|
||||
#include "sstring.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Benchmark based on the features tested by benchmark seen here:
|
||||
* http://www.utilitycode.com/str/performance.aspx
|
||||
*
|
||||
* The idea is to measure the performance empty constructors, char *
|
||||
* constructors, assignment, concatenation and scanning. But rather than
|
||||
* comparing MFC's CString to Str Library, we are going to compare STL to
|
||||
* CBString.
|
||||
*
|
||||
* The results are interesting. CBString basically beats std::string quite
|
||||
* severely, except for the empty constructor.
|
||||
*/
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
extern "C" {
|
||||
#include "sds.h"
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined (BENCH_CAN_USE_STL)
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_GLIB)
|
||||
#include "gmodule.h"
|
||||
#endif
|
||||
|
||||
/* Time of a test */
|
||||
#define TEST_SECONDS (5)
|
||||
|
||||
/*
|
||||
* This macro puts a memory barrier and prevents the optimizer from
|
||||
* optimizing too much the inline functions and literraly breaking
|
||||
* the benchmark by doing nothing.
|
||||
* Better than nothing, but far from perfect.
|
||||
*/
|
||||
#define BARRIER(addr) compiler_barrier((void*) addr)
|
||||
|
||||
bool print_csv = false;
|
||||
|
||||
int timeTest (double &res, int (*testfn) (int count), int count) {
|
||||
clock_t t0, t1;
|
||||
int p = 0;
|
||||
double x, c = 0;
|
||||
|
||||
t0 = clock ();
|
||||
|
||||
do {
|
||||
p += testfn (count);
|
||||
t1 = clock ();
|
||||
|
||||
c += count;
|
||||
if (t1 == t0) {
|
||||
if (count < (INT_MAX / 2)) count += count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t1 - t0 >= TEST_SECONDS*CLOCKS_PER_SEC) break;
|
||||
|
||||
x = (TEST_SECONDS*CLOCKS_PER_SEC - (t1 - t0)) * c / (t1 - t0);
|
||||
|
||||
if (x > INT_MAX) x = INT_MAX;
|
||||
count = (int) x;
|
||||
if (count < 1000) count = 1000;
|
||||
|
||||
} while (1);
|
||||
|
||||
res = c * CLOCKS_PER_SEC / (t1 - t0);
|
||||
return p;
|
||||
clock_t t0, t1;
|
||||
int p = 0;
|
||||
double x, c = 0;
|
||||
|
||||
t0 = clock ();
|
||||
|
||||
do {
|
||||
p += testfn (count);
|
||||
t1 = clock ();
|
||||
|
||||
c += count;
|
||||
if (t1 == t0) {
|
||||
if (count < (INT_MAX / 2)) count += count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t1 - t0 >= TEST_SECONDS*CLOCKS_PER_SEC) break;
|
||||
|
||||
x = (TEST_SECONDS*CLOCKS_PER_SEC - (t1 - t0)) * c / (t1 - t0);
|
||||
|
||||
if (x > INT_MAX) x = INT_MAX;
|
||||
count = (int) x;
|
||||
if (count < 1000) count = 1000;
|
||||
|
||||
} while (1);
|
||||
|
||||
res = c * CLOCKS_PER_SEC / (t1 - t0);
|
||||
return p;
|
||||
}
|
||||
|
||||
#define SMALLTESTSTRING1 ("hello")
|
||||
|
||||
#define TESTSTRING1 ("<sometag name=\"John Doe\" position=\"Executive VP Marketing\"/>")
|
||||
|
||||
#if defined (BENCH_CAN_USE_STL)
|
||||
@@ -112,6 +136,7 @@ int testSTL_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
std::string b;
|
||||
BARRIER(&b);
|
||||
c += b.length () ^ i;
|
||||
}
|
||||
return c;
|
||||
@@ -121,6 +146,17 @@ int testSTL_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
std::string b (TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += b.length () ^ i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSTL_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
std::string b (SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += b.length () ^ i;
|
||||
}
|
||||
return c;
|
||||
@@ -132,6 +168,7 @@ int testSTL_cstrAssignment (int count) {
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
b = TESTSTRING1;
|
||||
BARRIER(&b);
|
||||
c += b.length () ^ i;
|
||||
}
|
||||
return c;
|
||||
@@ -145,6 +182,7 @@ int testSTL_extraction (int count) {
|
||||
c += b[(i & 7)];
|
||||
c += b[(i & 7) ^ 8];
|
||||
c += b.c_str()[(i & 7) ^ 4] ^ i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -157,6 +195,7 @@ int i, c = 0;
|
||||
c += b.find ('.');
|
||||
c += b.find ("123");
|
||||
c += b.find_first_of ("sm") ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -171,6 +210,7 @@ int testSTL_concat (int count) {
|
||||
for (i=0; i < 250; i++) {
|
||||
accum += a;
|
||||
accum += "!!";
|
||||
BARRIER(&accum);
|
||||
c += accum.length() ^i;
|
||||
}
|
||||
}
|
||||
@@ -185,6 +225,7 @@ int testSTL_replace (int count) {
|
||||
a.replace (11, 4, "XXXXXX");
|
||||
a.replace (23, 2, "XXXXXX");
|
||||
a.replace ( 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += a.length () ^ j;
|
||||
}
|
||||
return c;
|
||||
@@ -197,6 +238,7 @@ int testCBS_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
CBString b;
|
||||
BARRIER(&b);
|
||||
c += b.length ()^i;
|
||||
}
|
||||
return c;
|
||||
@@ -206,6 +248,17 @@ int testCBS_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
CBString b (TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += b.length () ^i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testCBS_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
CBString b (SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += b.length () ^i;
|
||||
}
|
||||
return c;
|
||||
@@ -217,6 +270,7 @@ int testCBS_cstrAssignment (int count) {
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
b = TESTSTRING1;
|
||||
BARRIER(&b);
|
||||
c += b.length () ^i;
|
||||
}
|
||||
return c;
|
||||
@@ -230,6 +284,7 @@ int testCBS_extraction (int count) {
|
||||
c += b[(i & 7)];
|
||||
c += b[(i & 7) ^ 8];
|
||||
c += ((const char *)b)[(i & 7) ^ 4] ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -242,6 +297,7 @@ int testCBS_scan (int count) {
|
||||
c += b.find ('.');
|
||||
c += b.find ("123");
|
||||
c += b.findchr ("sm") ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -256,6 +312,7 @@ int testCBS_concat (int count) {
|
||||
for (i=0; i < 250; i++) {
|
||||
accum += a;
|
||||
accum += "!!";
|
||||
BARRIER(&accum);
|
||||
c+= accum.length() ^i;
|
||||
}
|
||||
}
|
||||
@@ -270,6 +327,7 @@ int testCBS_replace (int count) {
|
||||
a.replace (11, 4, "XXXXXX");
|
||||
a.replace (23, 2, "XXXXXX");
|
||||
a.replace ( 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += a.length () ^j;
|
||||
}
|
||||
return c;
|
||||
@@ -280,7 +338,8 @@ int testCBS_replace (int count) {
|
||||
int testSRT_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
ss_t *b = ss_alloc(0);
|
||||
srt_string *b = ss_alloc(0);
|
||||
BARRIER(b);
|
||||
c += ss_size(b) ^i;
|
||||
ss_free(&b);
|
||||
}
|
||||
@@ -290,7 +349,19 @@ int testSRT_emptyCtor (int count) {
|
||||
int testSRT_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
ss_t *b = ss_dup_c(TESTSTRING1);
|
||||
srt_string *b = ss_dup_c(TESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += ss_size(b) ^i;
|
||||
ss_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSRT_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
srt_string *b = ss_dup_c(SMALLTESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += ss_size(b) ^i;
|
||||
ss_free(&b);
|
||||
}
|
||||
@@ -299,9 +370,10 @@ int testSRT_nonemptyCtor (int count) {
|
||||
|
||||
int testSRT_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
ss_t *b = ss_alloc(0);
|
||||
srt_string *b = ss_alloc(0);
|
||||
for (c=i=0; i < count; i++) {
|
||||
ss_cpy_cn(&b, TESTSTRING1, strlen(TESTSTRING1));
|
||||
BARRIER(b);
|
||||
c += ss_size(b) ^i;
|
||||
}
|
||||
ss_free(&b);
|
||||
@@ -310,11 +382,12 @@ int testSRT_cstrAssignment (int count) {
|
||||
|
||||
int testSRT_extraction (int count) {
|
||||
int i, c = 0;
|
||||
ss_t *b = ss_dup_c(TESTSTRING1);
|
||||
srt_string *b = ss_dup_c(TESTSTRING1);
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += ss_at(b,(i & 7));
|
||||
c += ss_at(b,(i & 7) ^ 8);
|
||||
c += ss_at(b,(i & 7) ^ 4) ^i;
|
||||
BARRIER(b);
|
||||
}
|
||||
ss_free(&b);
|
||||
return c;
|
||||
@@ -322,12 +395,13 @@ int testSRT_extraction (int count) {
|
||||
|
||||
int testSRT_scan (int count) {
|
||||
int i, c = 0;
|
||||
ss_t *b = ss_dup_c("Dot. 123. Some more data.");
|
||||
srt_string *b = ss_dup_c("Dot. 123. Some more data.");
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += ss_findc (b, 0, '.');
|
||||
c += ss_find_cn (b, 0, "123", strlen("123"));
|
||||
//c += ss_pbrk (b, 0, "sm") ^i;
|
||||
c += ss_findb (b, 0) ^i;
|
||||
BARRIER(b);
|
||||
}
|
||||
ss_free(&b);
|
||||
return c;
|
||||
@@ -336,14 +410,15 @@ int testSRT_scan (int count) {
|
||||
|
||||
int testSRT_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
ss_t *a = ss_dup_c(TESTSTRING1);
|
||||
ss_t *accum = ss_alloc(0);
|
||||
srt_string *a = ss_dup_c(TESTSTRING1);
|
||||
srt_string *accum = ss_alloc(0);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
ss_cpy_c(&accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
ss_cat(&accum, a, NULL);
|
||||
ss_cat_c(&accum, "!!", NULL);
|
||||
BARRIER(accum);
|
||||
c += ss_size(accum) ^i;
|
||||
}
|
||||
}
|
||||
@@ -360,6 +435,7 @@ int testMLIB_emptyCtor (int count) {
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init(b);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
}
|
||||
@@ -371,6 +447,19 @@ int testMLIB_nonemptyCtor (int count) {
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_set_str(b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_set_str(b, SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
}
|
||||
@@ -383,6 +472,7 @@ int testMLIB_cstrAssignment (int count) {
|
||||
string_init(b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_set_str(b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
}
|
||||
string_clear(b);
|
||||
@@ -399,6 +489,7 @@ int testMLIB_extraction (int count) {
|
||||
c += string_get_char(b, (i & 7));
|
||||
c += string_get_char(b, (i & 7) ^ 8);
|
||||
c += string_get_char(b, (i & 7) ^ 4) ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(b);
|
||||
return c;
|
||||
@@ -413,12 +504,12 @@ int testMLIB_scan (int count) {
|
||||
c += string_search_char (b, '.');
|
||||
c += string_search_str (b, "123");
|
||||
c += string_search_pbrk (b, "sm") ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int testMLIB_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
string_t a, accum;
|
||||
@@ -430,6 +521,7 @@ int testMLIB_concat (int count) {
|
||||
for (i=0; i < 250; i++) {
|
||||
string_cat(accum, a);
|
||||
string_cat_str(accum, "!!");
|
||||
BARRIER(&accum);
|
||||
c += string_size(accum) ^i;
|
||||
}
|
||||
}
|
||||
@@ -447,6 +539,7 @@ int testMLIB_replace (int count) {
|
||||
string_replace_at(a, 11, 4, "XXXXXX");
|
||||
string_replace_at(a, 23, 2, "XXXXXX");
|
||||
string_replace_at(a, 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += string_size(a) ^j;
|
||||
}
|
||||
|
||||
@@ -455,141 +548,470 @@ int testMLIB_replace (int count) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NTESTS 7
|
||||
struct flags {
|
||||
int runtest[NTESTS];
|
||||
};
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
int testSDS_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
sds b;
|
||||
b = sdsempty();
|
||||
BARRIER(b);
|
||||
c += sdslen(b) ^ i;
|
||||
sdsfree(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int benchTest (const struct flags * runflags) {
|
||||
int c = 0;
|
||||
double cps;
|
||||
int testSDS_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
sds b;
|
||||
b = sdsnew(TESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += sdslen(b) ^i;
|
||||
sdsfree(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSDS_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
sds b;
|
||||
b = sdsnew(SMALLTESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += sdslen(b) ^i;
|
||||
sdsfree(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSDS_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
sds b;
|
||||
b = sdsempty();
|
||||
for (c=i=0; i < count; i++) {
|
||||
b = sdscpy(b, TESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += sdslen(b) ^i;
|
||||
}
|
||||
sdsfree(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSDS_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
sds b;
|
||||
b = sdsnew(TESTSTRING1);
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += b[(i & 7)];
|
||||
c += b[(i & 7) ^ 8];
|
||||
c += b[(i & 7) ^ 4] ^i;
|
||||
BARRIER(b);
|
||||
}
|
||||
sdsfree(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSDS_scan (int count) {
|
||||
int i, c = 0;
|
||||
sds b;
|
||||
b = sdsnew("Dot. 123. Some more data.");
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += (intptr_t) strchr(b, '.');
|
||||
c += (intptr_t) strstr (b, "123");
|
||||
c += (intptr_t) strpbrk (b, "sm") ^i;
|
||||
BARRIER(b);
|
||||
}
|
||||
sdsfree(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int testSDS_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
sds a, accum;
|
||||
a = sdsnew(TESTSTRING1);
|
||||
accum = sdsempty();
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
accum = sdscpy(accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
accum = sdscat(accum, a);
|
||||
accum = sdscat(accum, "!!");
|
||||
BARRIER(accum);
|
||||
c += sdslen(accum) ^i;
|
||||
}
|
||||
}
|
||||
sdsfree(a);
|
||||
sdsfree(accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
sds SDS_replace_at(sds str, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
// simple implementation as replace is not available
|
||||
sds a = sdsnewlen((const void*) str, pos);
|
||||
a = sdscat(a, str2);
|
||||
a = sdscat(a, &str[pos+len]);
|
||||
sdsfree(str);
|
||||
return a;
|
||||
}
|
||||
|
||||
int testSDS_replace (int count) {
|
||||
int j, c = 0;
|
||||
sds a;
|
||||
a = sdsnew(TESTSTRING1);
|
||||
for (j=0; j < count; j++) {
|
||||
a = SDS_replace_at(a, 11, 4, "XXXXXX");
|
||||
a = SDS_replace_at(a, 23, 2, "XXXXXX");
|
||||
a = SDS_replace_at(a, 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += sdslen(a) ^j;
|
||||
}
|
||||
sdsfree(a);
|
||||
return c;
|
||||
}
|
||||
|
||||
#if defined (BENCH_CAN_USE_STL)
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testSTL_emptyCtor, 100000);
|
||||
printf ("std::string empty constructor: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testSTL_nonemptyCtor, 100000);
|
||||
printf ("std::string non-empty constructor: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testSTL_cstrAssignment, 100000);
|
||||
printf ("std::string char * assignment: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testSTL_extraction, 100000);
|
||||
printf ("std::string char extraction: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testSTL_scan, 100000);
|
||||
printf ("std::string scan: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testSTL_concat, 10);
|
||||
printf ("std::string concatenation: %20.1f per second\n", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testSTL_replace, 10000);
|
||||
printf ("std::string replace: %20.1f per second\n", cps);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BENCH_CAN_USE_GLIB
|
||||
int testGLIB_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
GString *b = g_string_new("");
|
||||
BARRIER(b);
|
||||
c += b->len;
|
||||
g_string_free(b, TRUE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testGLIB_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
GString *b = g_string_new(TESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += b->len;
|
||||
g_string_free(b, TRUE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testGLIB_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
GString *b = g_string_new(SMALLTESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += b->len;
|
||||
g_string_free(b, TRUE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testGLIB_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
GString *b = g_string_new("");
|
||||
for (c=i=0; i < count; i++) {
|
||||
b = g_string_assign(b, TESTSTRING1);
|
||||
BARRIER(b);
|
||||
c += b->len ^i;
|
||||
}
|
||||
g_string_free(b, TRUE);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testGLIB_extraction (int count) {
|
||||
int i, c = 0;
|
||||
GString *b = g_string_new(TESTSTRING1);
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += b->str[(i & 7)];
|
||||
c += b->str[(i & 7) ^ 8];
|
||||
c += b->str[(i & 7) ^ 4] ^i;
|
||||
BARRIER(b);
|
||||
}
|
||||
g_string_free(b, TRUE);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testGLIB_scan (int count) {
|
||||
int i, c = 0;
|
||||
GString *b = g_string_new("Dot. 123. Some more data.");
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += (strchr(b->str, '.')-b->str);
|
||||
c += (strstr (b->str, "123")-b->str);
|
||||
c += (strpbrk (b->str, "sm")-b->str) ^i;
|
||||
BARRIER(b);
|
||||
}
|
||||
g_string_free(b, TRUE);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int testGLIB_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
GString *a = g_string_new(TESTSTRING1);
|
||||
GString *accum = g_string_new("");
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
accum = g_string_assign(accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
accum = g_string_append(accum, a->str);
|
||||
accum = g_string_append(accum, "!!");
|
||||
BARRIER(accum);
|
||||
c += accum->len ^i;
|
||||
}
|
||||
}
|
||||
g_string_free(a, TRUE);
|
||||
g_string_free(accum, TRUE);
|
||||
return c;
|
||||
}
|
||||
|
||||
//int testGLIB_replace (int count): not available
|
||||
#endif
|
||||
|
||||
|
||||
#define NTESTS 8
|
||||
struct flags {
|
||||
int runtest[NTESTS];
|
||||
};
|
||||
|
||||
static void
|
||||
print(const char library[], const char function[], double cps)
|
||||
{
|
||||
if (print_csv == false)
|
||||
{
|
||||
printf ("%16s %30s : %20.1f per second\n", library, function, cps);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("\"%s\";\"%s\";%f\n", library, function, cps);
|
||||
}
|
||||
}
|
||||
|
||||
int benchTest (const struct flags * runflags) {
|
||||
int c = 0;
|
||||
double cps;
|
||||
|
||||
#if defined (BENCH_CAN_USE_STL)
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testSTL_emptyCtor, 100000);
|
||||
print ("std::string", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testSTL_nonemptyCtor, 100000);
|
||||
print ("std::string", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testSTL_smallnonemptyCtor, 100000);
|
||||
print ("std::string", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testSTL_cstrAssignment, 100000);
|
||||
print ("std::string", "char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testSTL_extraction, 100000);
|
||||
print ("std::string", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testSTL_scan, 100000);
|
||||
print ("std::string", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testSTL_concat, 10);
|
||||
print ("std::string", "concatenation", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[7]) {
|
||||
c += timeTest (cps, testSTL_replace, 10000);
|
||||
print ("std::string", "replace", cps);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testCBS_emptyCtor, 100000);
|
||||
printf ("CBString empty constructor: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testCBS_nonemptyCtor, 100000);
|
||||
printf ("CBString non-empty constructor: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testCBS_cstrAssignment, 100000);
|
||||
printf ("CBString char * assignment: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testCBS_extraction, 100000);
|
||||
printf ("CBString char extraction: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testCBS_scan, 100000);
|
||||
printf ("CBString scan: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testCBS_concat, 10);
|
||||
printf ("CBString concatenation: %20.1f per second\n", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testCBS_replace, 10000);
|
||||
printf ("CBString replace: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testCBS_emptyCtor, 100000);
|
||||
print ("CBString", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testCBS_nonemptyCtor, 100000);
|
||||
print ("CBString", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testCBS_smallnonemptyCtor, 100000);
|
||||
print ("CBString", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testCBS_cstrAssignment, 100000);
|
||||
print ("CBString", "char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testCBS_extraction, 100000);
|
||||
print ("CBString", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testCBS_scan, 100000);
|
||||
print ("CBString", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testCBS_concat, 10);
|
||||
print ("CBString", "concatenation", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[7]) {
|
||||
c += timeTest (cps, testCBS_replace, 10000);
|
||||
print ("CBString", "replace", cps);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_LIBSRT
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testSRT_emptyCtor, 100000);
|
||||
printf ("LIBSRT string empty constructor: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testSRT_nonemptyCtor, 100000);
|
||||
printf ("LIBSRT string non-empty constructor:%20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testSRT_cstrAssignment, 100000);
|
||||
printf ("LIBSRT string char * assignment: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testSRT_extraction, 100000);
|
||||
printf ("LIBSRT string char extraction: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testSRT_scan, 100000);
|
||||
printf ("LIBSRT string scan: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testSRT_concat, 10);
|
||||
printf ("LIBSRT string concatenation: %20.1f per second\n", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testSRT_emptyCtor, 100000);
|
||||
print ("LIBSRT", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testSRT_nonemptyCtor, 100000);
|
||||
print ("LIBSRT", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testSRT_smallnonemptyCtor, 100000);
|
||||
print ("LIBSRT", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testSRT_cstrAssignment, 100000);
|
||||
print ("LIBSRT", "char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testSRT_extraction, 100000);
|
||||
print ("LIBSRT", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testSRT_scan, 100000);
|
||||
print ("LIBSRT", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testSRT_concat, 10);
|
||||
print ("LIBSRT", "concatenation", cps * 250);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testMLIB_emptyCtor, 100000);
|
||||
print ("M*LIB", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testMLIB_nonemptyCtor, 100000);
|
||||
print ("M*LIB", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testMLIB_smallnonemptyCtor, 100000);
|
||||
print ("M*LIB", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testMLIB_cstrAssignment, 100000);
|
||||
print ("M*LIB", "Char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testMLIB_extraction, 100000);
|
||||
print ("M*LIB", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testMLIB_scan, 100000);
|
||||
print ("M*LIB", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testMLIB_concat, 10);
|
||||
print ("M*LIB", "concatenation", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[7]) {
|
||||
c += timeTest (cps, testMLIB_replace, 10000);
|
||||
print ("M*LIB", "replace", cps);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testMLIB_emptyCtor, 100000);
|
||||
printf ("M*LIB string empty constructor: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testMLIB_nonemptyCtor, 100000);
|
||||
printf ("M*LIB string non-empty constructor:%20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testMLIB_cstrAssignment, 100000);
|
||||
printf ("M*LIB string char * assignment: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testMLIB_extraction, 100000);
|
||||
printf ("M*LIB string char extraction: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testMLIB_scan, 100000);
|
||||
printf ("M*LIB string scan: %20.1f per second\n", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testMLIB_concat, 10);
|
||||
printf ("M*LIB string concatenation: %20.1f per second\n", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testMLIB_replace, 10000);
|
||||
printf ("M*LIB string replace: %20.1f per second\n", cps);
|
||||
}
|
||||
#ifdef BENCH_CAN_USE_SDS
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testSDS_emptyCtor, 100000);
|
||||
print ("SDS", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testSDS_nonemptyCtor, 100000);
|
||||
print ("SDS", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testSDS_smallnonemptyCtor, 100000);
|
||||
print ("SDS", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testSDS_cstrAssignment, 100000);
|
||||
print ("SDS", "char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testSDS_extraction, 100000);
|
||||
print ("SDS", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testSDS_scan, 100000);
|
||||
print ("SDS", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testSDS_concat, 10);
|
||||
print ("SDS", "concatenation", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[7]) {
|
||||
c += timeTest (cps, testSDS_replace, 10);
|
||||
print ("SDS", "replace", cps);
|
||||
}
|
||||
#endif
|
||||
return c;
|
||||
|
||||
#ifdef BENCH_CAN_USE_GLIB
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testGLIB_emptyCtor, 100000);
|
||||
print ("GLIB", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testGLIB_nonemptyCtor, 100000);
|
||||
print ("GLIB", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testGLIB_smallnonemptyCtor, 100000);
|
||||
print ("GLIB", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testGLIB_cstrAssignment, 100000);
|
||||
print ("GLIB", "Char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testGLIB_extraction, 100000);
|
||||
print ("GLIB", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testGLIB_scan, 100000);
|
||||
print ("GLIB", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testGLIB_concat, 10);
|
||||
print ("GLIB", "concatenation", cps * 250);
|
||||
}
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
struct flags runflags;
|
||||
int i, j;
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--csv") == 0) {
|
||||
print_csv = true;
|
||||
argc --;
|
||||
argv++;
|
||||
}
|
||||
|
||||
for (i=0; i < NTESTS; i++) runflags.runtest[i] = argc < 2;
|
||||
for (i=1; i < argc; i++) {
|
||||
if (1 == sscanf (argv[i], "%d", &j)) {
|
||||
|
||||
+11
-13
@@ -124,7 +124,7 @@ static int equal_func(const void* arg, const void *obj_p)
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
test_dict(size_t n)
|
||||
{
|
||||
tommy_hashlin dict;
|
||||
tommy_hashlin_init(&dict);
|
||||
@@ -174,7 +174,7 @@ static size_t char_hash(const char *s)
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
tommy_hashlin dict;
|
||||
tommy_hashlin_init(&dict);
|
||||
@@ -206,18 +206,16 @@ test_dict_big(unsigned long n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 30)
|
||||
test_function("Rbtree time", 1000000, test_rbtree);
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
test("TommyDS", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+12
-14
@@ -1,4 +1,5 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -85,7 +86,7 @@ struct hash_i_node_s {
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
test_dict(size_t n)
|
||||
{
|
||||
struct hash_i_node_s *dict = NULL;
|
||||
|
||||
@@ -131,7 +132,7 @@ struct hash_b_node_s {
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
struct hash_b_node_s *dict = NULL;
|
||||
|
||||
@@ -199,19 +200,16 @@ static void test_sort(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "sort", 10000000, 0, test_sort, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]): 0;
|
||||
if (n == 10)
|
||||
test_function("List time",10000000, test_list);
|
||||
if (n == 20)
|
||||
test_function("Array time", 100000000, test_array);
|
||||
if (n == 40 || n == 42)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 41)
|
||||
test_function("DictB time", 1000000, test_dict_big);
|
||||
if (n == 50)
|
||||
test_function("Sort time", 10000000, test_sort);
|
||||
test("UT-HASH", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static unsigned long *g_p;
|
||||
|
||||
static void test_hash_prepare(size_t n)
|
||||
{
|
||||
g_p = malloc (n * sizeof(unsigned long));
|
||||
if (g_p == NULL) abort();
|
||||
for(size_t i = 0; i < n ; i++)
|
||||
g_p[i] = ((rand_get()*RAND_MAX + rand_get())*RAND_MAX+rand_get())*RAND_MAX + rand_get();
|
||||
}
|
||||
|
||||
|
||||
static void test_hash_final(void)
|
||||
{
|
||||
free(g_p);
|
||||
}
|
||||
|
||||
static void test_hash(size_t n)
|
||||
{
|
||||
g_result = XXH64(g_p, sizeof(unsigned long)*n, 0);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 70,"XXHASH64", 100000000, test_hash_prepare, test_hash, test_hash_final}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("XXHASH", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
|
||||
// Maximum supported value for repeat argument
|
||||
#define MAX_REPEAT 10000
|
||||
|
||||
// The global result
|
||||
unsigned long g_result;
|
||||
|
||||
// The rand value
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
M_THREAD_ATTR
|
||||
#endif
|
||||
unsigned int randValue = 0;
|
||||
|
||||
void compiler_barrier(void *p)
|
||||
{
|
||||
// Do nothing, but let the compiler thinks that we did.
|
||||
(void) p;
|
||||
// Can be used for FLTO building
|
||||
// asm volatile("": "+r" (p) : :"memory");
|
||||
}
|
||||
|
||||
struct parse_opt_s {
|
||||
int test_function;
|
||||
double from, to, step, grow;
|
||||
double within;
|
||||
unsigned repeat;
|
||||
bool graph, best, best_within, average, quiet;
|
||||
};
|
||||
|
||||
static void
|
||||
parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
|
||||
{
|
||||
char *end;
|
||||
|
||||
opt->test_function = 0;
|
||||
opt->from = 0.0;
|
||||
opt->to = 0.0;
|
||||
opt->step = 0.0;
|
||||
opt->grow = 1.1;
|
||||
opt->graph = false;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
opt->average = false;
|
||||
opt->quiet = false;
|
||||
opt->repeat = 1;
|
||||
opt->within = .05;
|
||||
|
||||
for(int i = 1; i < argc ; i++)
|
||||
{
|
||||
if (argv[i][0] == '-') {
|
||||
if (strcmp(argv[i], "--from") == 0){
|
||||
i++;
|
||||
opt->from = strtod(argv[i], &end);
|
||||
opt->to = opt->from;
|
||||
} else if (strcmp(argv[i], "--to") == 0) {
|
||||
i++;
|
||||
opt->to = strtod(argv[i], &end);
|
||||
opt->grow = 1.1;
|
||||
} else if (strcmp(argv[i], "--step") == 0) {
|
||||
i++;
|
||||
opt->step = strtod(argv[i], &end);
|
||||
opt->grow = 0;
|
||||
} else if (strcmp(argv[i], "--grow") == 0) {
|
||||
i++;
|
||||
opt->grow = strtod(argv[i], &end);
|
||||
opt->step = 0;
|
||||
} else if (strcmp(argv[i], "--repeat") == 0) {
|
||||
i++;
|
||||
opt->repeat = strtol(argv[i], &end, 10);
|
||||
opt->repeat = (opt->repeat > MAX_REPEAT) ? MAX_REPEAT : opt->repeat;
|
||||
} else if (strcmp(argv[i], "--graph") == 0) {
|
||||
opt->graph = true;
|
||||
} else if (strcmp(argv[i], "--best") == 0) {
|
||||
opt->best = true;
|
||||
opt->average = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--best-within") == 0) {
|
||||
opt->best_within = true;
|
||||
opt->best = false;
|
||||
opt->average = false;
|
||||
i++;
|
||||
opt->within = strtod(argv[i], &end) / 100.0;
|
||||
} else if (strcmp(argv[i], "--average") == 0) {
|
||||
opt->average = true;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--quiet") == 0) {
|
||||
opt->quiet = true;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Option unkown: %s.\n",
|
||||
argv[i]);
|
||||
exit(-1);
|
||||
}
|
||||
if (*end != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot parse %s. Expected float\n",
|
||||
argv[i]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
} else {
|
||||
opt->test_function = strtol (argv[i], &end, 10);
|
||||
if (*end != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot parse %s. Expected function number\n",
|
||||
argv[i]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
select_config(int func, size_t n, const config_func_t functions[])
|
||||
{
|
||||
for(size_t i = 0; i < n;i++) {
|
||||
if (functions[i].num == func)
|
||||
return i;
|
||||
}
|
||||
fprintf(stderr, "ERROR: Function number %d not found. Available functions are:\n", func);
|
||||
for(size_t i = 0; i < n;i++) {
|
||||
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--grapĥ]\n"
|
||||
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Utility function for qsort
|
||||
static int cmp_double(const void *pa, const void *pb)
|
||||
{
|
||||
const double *a = (const double *) pa, *b = (const double *)pb;
|
||||
return (*a < *b) ? -1 : *a > *b;
|
||||
}
|
||||
|
||||
/* Get the longest sequence of values within 'f'% */
|
||||
static int
|
||||
get_sequence(int i, int n, double tab[], double f)
|
||||
{
|
||||
int j;
|
||||
for(j = i + 1; j < n; j++) {
|
||||
if (tab[j] > f * tab[i])
|
||||
break;
|
||||
}
|
||||
return j-i;
|
||||
}
|
||||
|
||||
/* Return the minimum of the longest sequence of values with 'f'% */
|
||||
static double
|
||||
get_best_within(int n, double tab[], double f)
|
||||
{
|
||||
qsort(tab, n, sizeof(double), cmp_double);
|
||||
int best_i = 0;
|
||||
int best_seq = get_sequence(0, n, tab, f);
|
||||
for(int i = 1; i < n && (n-i) > best_seq ; i++) {
|
||||
int seq = get_sequence(i, n, tab, f);
|
||||
if (seq > best_seq) {
|
||||
best_i = i;
|
||||
best_seq = seq;
|
||||
}
|
||||
}
|
||||
return tab[best_i];
|
||||
}
|
||||
|
||||
// Integer sqrt function (to avoid depending on libm)
|
||||
static unsigned integer_sqrt(unsigned n)
|
||||
{
|
||||
// Find greatest shift.
|
||||
int shift = 2;
|
||||
unsigned nShifted = n >> shift;
|
||||
// We check for nShifted being n, since some implementations
|
||||
// perform shift operations modulo the word size.
|
||||
while (nShifted != 0 && nShifted != n){
|
||||
shift += 2;
|
||||
nShifted = n >> shift;
|
||||
}
|
||||
shift -= 2;
|
||||
// Find digits of result.
|
||||
unsigned result = 0;
|
||||
while (shift >= 0) {
|
||||
result = result << 1;
|
||||
unsigned candidateResult = result + 1;
|
||||
if (candidateResult*candidateResult <= n >> shift) {
|
||||
result = candidateResult;
|
||||
}
|
||||
shift -= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[])
|
||||
{
|
||||
// Init & parse arguments
|
||||
// NUMBER
|
||||
// --from NUMBER --to NUMBER --step NUMBER --grow NUMBER
|
||||
// --graph --best --average --quiet
|
||||
// --repeat N
|
||||
struct parse_opt_s arg;
|
||||
parse_config(&arg, argc, argv);
|
||||
int i = select_config(arg.test_function, n, functions);
|
||||
double from = (arg.from == 0) ? functions[i].default_n : arg.from;
|
||||
double to = (arg.to == 0) ? functions[i].default_n : arg.to;
|
||||
|
||||
// Open plot file if needed
|
||||
FILE *graph_file = NULL;
|
||||
if (arg.graph) {
|
||||
char filename[100];
|
||||
sprintf(filename, "plot-%s-%d.dat", library, arg.test_function);
|
||||
graph_file = fopen(filename, "wt");
|
||||
if (!graph_file) {
|
||||
fprintf(stderr, "ERROR: Cannot create plot.dat\n");
|
||||
exit(-2);
|
||||
}
|
||||
fprintf(graph_file, "# plotting %s-%d : %s\n# N T", library, arg.test_function, functions[i].funcname);
|
||||
}
|
||||
|
||||
// Do the bench
|
||||
for(double n = from; n <= to ; n = ((arg.grow == 0) ? n + arg.step : n * arg.grow))
|
||||
{
|
||||
double best = (1.0/0.0);
|
||||
double avg = 0.0;
|
||||
double variance = 0.0;
|
||||
static double measure[MAX_REPEAT];
|
||||
double ba = 0.0;
|
||||
|
||||
if (functions[i].init != NULL)
|
||||
functions[i].init(n);
|
||||
|
||||
// Measure the time of the test_function
|
||||
for(unsigned r = 0; r < arg.repeat; r++) {
|
||||
double t0 = test_function( (arg.graph|arg.best|arg.average|arg.quiet) ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
|
||||
best = (t0 < best) ? t0 : best;
|
||||
avg += t0;
|
||||
variance += t0 * t0;
|
||||
measure[r] = t0;
|
||||
}
|
||||
|
||||
// Closure of the tests
|
||||
if (functions[i].clear != NULL)
|
||||
functions[i].clear();
|
||||
|
||||
// Finish computing the different times
|
||||
if (arg.repeat > 1) {
|
||||
avg /= arg.repeat;
|
||||
variance = (variance - arg.repeat * avg * avg) / (arg.repeat - 1);
|
||||
ba = get_best_within(arg.repeat, measure, 1. + arg.within);
|
||||
}
|
||||
|
||||
// The average value shall be around best_within (and greater)
|
||||
// otherwise the result doesn't seem reliable.
|
||||
bool reliable = (ba <= avg && ba * (1.0+arg.within/2) + 0.5 > avg);
|
||||
|
||||
// Print the result
|
||||
if (arg.graph) {
|
||||
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : arg.best ? best : ba);
|
||||
} else if (arg.quiet) {
|
||||
printf("%ld\n", (long)(arg.average ? avg : arg.best ? best : reliable ? ba : -1));
|
||||
} else if (arg.repeat > 1) {
|
||||
if (arg.average == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST ***\n", functions[i].funcname, (unsigned long) best, (unsigned long) n);
|
||||
if (arg.best == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms +/- %u ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, 2*integer_sqrt(variance), (unsigned long) n);
|
||||
if (arg.best == false && arg.average == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST within %d%% *** %s\n", functions[i].funcname, (unsigned long) ba, (unsigned long) n, (int)(100*arg.within), reliable ? "" : "(unreliable result)");
|
||||
}
|
||||
}
|
||||
|
||||
// Close the FILE if needed
|
||||
if (arg.graph) {
|
||||
fclose(graph_file);
|
||||
printf("File plot-%s-%d.dat generated.\n"
|
||||
"Run in gnuplot the following command:\n"
|
||||
"\tplot 'plot-%s-%d.dat' with linespoints linestyle 1\n",
|
||||
library, arg.test_function, library, arg.test_function);
|
||||
}
|
||||
return;
|
||||
}
|
||||
+81
-32
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -25,35 +25,59 @@
|
||||
#ifndef __COMMON_BENCH__H
|
||||
#define __COMMON_BENCH__H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Needed for M_THREAD_ATTR
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
#include "m-mutex.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/types.h>
|
||||
# include <sys/resource.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
# define USE_SYSCTL
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/resource.h>
|
||||
# include <sys/time.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Number of elements of a table
|
||||
#define numberof(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
/* Get the current CPU time. */
|
||||
#if defined(_WIN32)
|
||||
/* WINDOWS variant */
|
||||
#include <windows.h>
|
||||
|
||||
static unsigned long long
|
||||
static inline unsigned long long
|
||||
cputime (void)
|
||||
{
|
||||
LARGE_INTEGER freq, val;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
QueryPerformanceCounter(&val);
|
||||
return (unsigned long long) (1000000. * (double) val.QuadPart / (double) freq.QuadPart);
|
||||
LARGE_INTEGER freq, val;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
QueryPerformanceCounter(&val);
|
||||
return (unsigned long long) (1000000. * (double) val.QuadPart / (double) freq.QuadPart);
|
||||
}
|
||||
|
||||
#else
|
||||
/* UNIX variant */
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static unsigned long long
|
||||
static inline unsigned long long
|
||||
cputime (void)
|
||||
{
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
// Multi thread
|
||||
// Multi thread: Uses real time
|
||||
struct timeval tv;
|
||||
gettimeofday (&tv, NULL);
|
||||
return tv.tv_sec * 1000000ULL + tv.tv_usec;
|
||||
#else
|
||||
// Single thread
|
||||
// Single thread: Uses process usage time
|
||||
struct rusage rus;
|
||||
getrusage (0, &rus);
|
||||
return rus.ru_utime.tv_sec * 1000000ULL + rus.ru_utime.tv_usec;
|
||||
@@ -62,41 +86,61 @@ cputime (void)
|
||||
|
||||
#endif
|
||||
|
||||
unsigned long g_result;
|
||||
unsigned int randValue = 0;
|
||||
// The result of the bench
|
||||
extern unsigned long g_result;
|
||||
|
||||
static void rand_init(void)
|
||||
// The rand value
|
||||
extern
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
M_THREAD_ATTR
|
||||
#endif
|
||||
unsigned int randValue;
|
||||
|
||||
// Pseudo rand value generator.
|
||||
// Not very random but sufficient and fast enough for the bench
|
||||
static inline void rand_init(void)
|
||||
{
|
||||
randValue = 0;
|
||||
}
|
||||
static unsigned int rand_get(void)
|
||||
static inline unsigned int rand_get(void)
|
||||
{
|
||||
randValue = randValue * 31421U + 6927U;
|
||||
return randValue;
|
||||
}
|
||||
|
||||
static void test_function(const char str[], size_t n, void (*func)(size_t))
|
||||
// The function that performs the bench
|
||||
static inline double
|
||||
test_function(const char *str, size_t n, void (*func)(size_t))
|
||||
{
|
||||
double result;
|
||||
unsigned long long start, end;
|
||||
rand_init();
|
||||
start = cputime();
|
||||
(*func)(n);
|
||||
end = cputime();
|
||||
result = (double)(end-start) / 1000.0;
|
||||
end = (end - start) / 1000U;
|
||||
printf ("%s %lu ms for n = %lu [r=%lu]\n", str, (unsigned long) end, (unsigned long) n, g_result);
|
||||
if (str != NULL) {
|
||||
printf ("%20.20s time %lu ms for n = %lu [r=%lu]\n", str, (unsigned long) end, (unsigned long) n, g_result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
# define USE_SYSCTL
|
||||
#else
|
||||
# include <unistd.h>
|
||||
// Configuration table
|
||||
typedef struct {
|
||||
int num;
|
||||
const char *funcname;
|
||||
size_t default_n;
|
||||
void (*init)(size_t);
|
||||
void (*func)(size_t);
|
||||
void (*clear)(void);
|
||||
} config_func_t;
|
||||
|
||||
// Perform a parsing of the given arguments and do the bench according to the table
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
void test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[]);
|
||||
|
||||
/* Return the number of CPU of the system */
|
||||
static inline int get_cpu_count(void)
|
||||
@@ -120,4 +164,9 @@ static inline int get_cpu_count(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
void compiler_barrier(void *p);
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -59,7 +59,7 @@ static void find_max(void)
|
||||
dict_int64_set_at (dict, get_rand(), get_rand());
|
||||
n++;
|
||||
if ((n & ((1<<20)-1)) == 0) {
|
||||
printf ("n=%lu\n", n);
|
||||
printf ("n=%zu\n", n);
|
||||
}
|
||||
}
|
||||
dict_int64_clear(dict);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
CC=cc -std=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
CPPFLAGS=-I../..
|
||||
|
||||
all: k-nucleotide
|
||||
|
||||
k-nucleotide: k-nucleotide.exe data.txt
|
||||
./k-nucleotide.exe < data.txt
|
||||
|
||||
k-nucleotide.exe: nucleotide.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) nucleotide.c -o k-nucleotide.exe -lpthread
|
||||
|
||||
data.txt: fasta.exe
|
||||
./fasta.exe 25000000 > data.txt
|
||||
|
||||
fasta.exe: fasta.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -fopenmp fasta.c -o fasta.exe
|
||||
|
||||
clean:
|
||||
rm -f *.exe *~ *.o data.txt
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// contributed by Jeremy Zerfas
|
||||
// rewritten by Аноним Легионов, inspired by fasta Rust #2 program
|
||||
// use two OpenMP locks instead of one critical section
|
||||
// decouples IO activity from random number generation
|
||||
//
|
||||
// modified by Josh Goldfoot, adding use of a buffer for fasta_repeat
|
||||
|
||||
|
||||
// This controls the width of lines that are output by this program.
|
||||
#define MAXIMUM_LINE_WIDTH 60
|
||||
|
||||
// This program will generate the random nucleotide sequences in parallel which
|
||||
// are worked on in blocks of lines. The number of lines in those blocks is
|
||||
// controlled by this setting.
|
||||
#define LINES_PER_BLOCK 1024
|
||||
|
||||
#define CHARACTERS_PER_BLOCK (MAXIMUM_LINE_WIDTH*LINES_PER_BLOCK)
|
||||
|
||||
#define THREADS_TO_USE 4
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
// intptr_t should be the native integer type on most sane systems.
|
||||
typedef intptr_t intnative_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char letter;
|
||||
float probability;
|
||||
} nucleotide_info;
|
||||
|
||||
|
||||
// Repeatedly print string_To_Repeat until it has printed
|
||||
// number_Of_Characters_To_Create. The output is also wrapped to
|
||||
// MAXIMUM_LINE_WIDTH columns.
|
||||
static char* make_Sequence_Buffer(const char string_To_Repeat[])
|
||||
{
|
||||
const intnative_t string_To_Repeat_Length = strlen(string_To_Repeat);
|
||||
|
||||
// JG: Changed to that this writes a sequence to a buffer, which is used
|
||||
intnative_t number_Of_Characters_To_Create = string_To_Repeat_Length * MAXIMUM_LINE_WIDTH;
|
||||
char* buffer = (char*) malloc(number_Of_Characters_To_Create +
|
||||
number_Of_Characters_To_Create / MAXIMUM_LINE_WIDTH + 1);
|
||||
if (buffer == NULL)
|
||||
exit(-1);
|
||||
char* bufferOffset = buffer;
|
||||
|
||||
// Create an extended_String_To_Repeat which is a copy of string_To_Repeat
|
||||
// but extended with another copy of the first MAXIMUM_LINE_WIDTH characters
|
||||
// of string_To_Repeat appended to the end. Later on this allows us to
|
||||
// generate a line of output just by doing simple memory copies using an
|
||||
// appropriate offset into extended_String_To_Repeat.
|
||||
char extended_String_To_Repeat[string_To_Repeat_Length + MAXIMUM_LINE_WIDTH];
|
||||
for (intnative_t column = 0; column<string_To_Repeat_Length + MAXIMUM_LINE_WIDTH;
|
||||
column++)
|
||||
extended_String_To_Repeat[column] =
|
||||
string_To_Repeat[column%string_To_Repeat_Length];
|
||||
intnative_t offset = 0;
|
||||
|
||||
char line[MAXIMUM_LINE_WIDTH + 1];
|
||||
line[MAXIMUM_LINE_WIDTH] = '\n';
|
||||
|
||||
for (intnative_t current_Number_Of_Characters_To_Create =
|
||||
number_Of_Characters_To_Create;
|
||||
current_Number_Of_Characters_To_Create>0;)
|
||||
{
|
||||
// Figure out the length of the line we need to write. If it's less than
|
||||
// MAXIMUM_LINE_WIDTH then we also need to add a line feed in the right
|
||||
// spot too.
|
||||
intnative_t line_Length = MAXIMUM_LINE_WIDTH;
|
||||
if (current_Number_Of_Characters_To_Create<MAXIMUM_LINE_WIDTH)
|
||||
{
|
||||
line_Length = current_Number_Of_Characters_To_Create;
|
||||
line[line_Length] = '\n';
|
||||
}
|
||||
|
||||
memcpy(line, extended_String_To_Repeat + offset, line_Length);
|
||||
|
||||
// Update the offset, reducing it by string_To_Repeat_Length if
|
||||
// necessary.
|
||||
offset += line_Length;
|
||||
if (offset>string_To_Repeat_Length)
|
||||
offset -= string_To_Repeat_Length;
|
||||
|
||||
// "Output" that line to our buffer and update the
|
||||
// current_Number_Of_Characters_To_Create.
|
||||
memcpy(bufferOffset, line, line_Length + 1); // JG: used to be fwrite(line, line_Length + 1, 1, stdout);
|
||||
bufferOffset += line_Length + 1;
|
||||
current_Number_Of_Characters_To_Create -= line_Length;
|
||||
}
|
||||
*bufferOffset = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void repeat_And_Wrap_String(const char string_To_Repeat[], intnative_t number_Of_Characters_To_Create)
|
||||
{
|
||||
/* JG: fasta_repeat repeats every len(alu) * line-length = 287 * 61 = 17507 characters.
|
||||
So, calculate this once, then just print that buffer over and over. */
|
||||
char* sequence = make_Sequence_Buffer(string_To_Repeat);
|
||||
intnative_t sequenceLen = (intnative_t) strlen(sequence);
|
||||
intnative_t outputBytes = number_Of_Characters_To_Create + number_Of_Characters_To_Create / 60;
|
||||
while (outputBytes >= sequenceLen) {
|
||||
fwrite(sequence, sequenceLen, 1, stdout);
|
||||
outputBytes -= sequenceLen;
|
||||
}
|
||||
if (outputBytes > 0) {
|
||||
fwrite(sequence, outputBytes, 1, stdout);
|
||||
printf("\n");
|
||||
}
|
||||
free(sequence);
|
||||
}
|
||||
|
||||
|
||||
// Generate a pseudorandom number from 0 to max using a linear
|
||||
// congruential generator.
|
||||
#define IM 139968
|
||||
#define IA 3877
|
||||
#define IC 29573
|
||||
uint32_t seed = 42;
|
||||
|
||||
int rng_tid; //Thread ID
|
||||
int rng_tnum = 1; //Thread number
|
||||
intnative_t rng_cnt = 0;
|
||||
|
||||
#ifdef _OPENMP
|
||||
omp_lock_t rng_lock;
|
||||
#define RNG_LOCK_INIT() omp_init_lock(&rng_lock)
|
||||
#define RNG_LOCK() omp_set_lock(&rng_lock)
|
||||
#define RNG_FREE() omp_unset_lock(&rng_lock)
|
||||
#else
|
||||
#define RNG_LOCK_INIT() do{}while(0)
|
||||
#define RNG_LOCK() do{}while(0)
|
||||
#define RNG_FREE() do{}while(0)
|
||||
#endif
|
||||
|
||||
static void rng_init(void)
|
||||
{
|
||||
RNG_LOCK_INIT();
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
static intnative_t rng_gen_blk(uint32_t * buf, intnative_t len, int curr_tid)
|
||||
{
|
||||
intnative_t gen_cnt = -1;//Error by default
|
||||
RNG_LOCK();
|
||||
|
||||
if (rng_tid == curr_tid)
|
||||
{
|
||||
if (++rng_tid >= rng_tnum)
|
||||
{
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
gen_cnt = (len<rng_cnt) ? len : rng_cnt;
|
||||
rng_cnt -= gen_cnt;
|
||||
|
||||
len = gen_cnt;
|
||||
|
||||
while (0 != len--)
|
||||
{
|
||||
seed = (seed*IA + IC) % IM;
|
||||
*(buf++) = seed;//This is stupid actually!
|
||||
}
|
||||
}
|
||||
|
||||
RNG_FREE();
|
||||
return gen_cnt;
|
||||
}
|
||||
|
||||
int out_tid; //Thread ID
|
||||
int out_tnum = 1; //Thread number
|
||||
#ifdef _OPENMP
|
||||
omp_lock_t out_lock;
|
||||
#define OUT_LOCK_INIT() omp_init_lock(&out_lock)
|
||||
#define OUT_LOCK() omp_set_lock(&out_lock)
|
||||
#define OUT_FREE() omp_unset_lock(&out_lock)
|
||||
#else
|
||||
#define OUT_LOCK_INIT() do{}while(0)
|
||||
#define OUT_LOCK() do{}while(0)
|
||||
#define OUT_FREE() do{}while(0)
|
||||
#endif
|
||||
|
||||
static void out_init(void)
|
||||
{
|
||||
OUT_LOCK_INIT();
|
||||
rng_tid = 0;
|
||||
}
|
||||
|
||||
static intnative_t out_write(char * buf, intnative_t len, int curr_tid)
|
||||
{
|
||||
intnative_t wr_cnt = -1;//Error by default
|
||||
OUT_LOCK();
|
||||
|
||||
if (out_tid == curr_tid)
|
||||
{
|
||||
if (++out_tid >= out_tnum)
|
||||
{
|
||||
out_tid = 0;
|
||||
}
|
||||
wr_cnt = fwrite(buf, len, 1, stdout);
|
||||
}
|
||||
|
||||
OUT_FREE();
|
||||
return wr_cnt; //-1 - thread error, 0 - IO error, 1 - ОК
|
||||
}
|
||||
|
||||
static void generate_And_Wrap_Pseudorandom_DNA_Sequence(
|
||||
const nucleotide_info nucl_info[],
|
||||
const intnative_t nucl_num,
|
||||
const intnative_t char_num)
|
||||
{
|
||||
uint32_t cumul_p[nucl_num];
|
||||
float cumul_acc = 0.0;
|
||||
|
||||
for (intnative_t i = 0; i<nucl_num; i++)
|
||||
{
|
||||
cumul_acc += nucl_info[i].probability;
|
||||
cumul_p[i] = 1ul + (uint32_t)(cumul_acc*(float)IM); //Compensate rounding errors on test file
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
intnative_t tnum = omp_get_num_procs();
|
||||
if (tnum>THREADS_TO_USE) tnum = THREADS_TO_USE;
|
||||
omp_set_num_threads(tnum);
|
||||
rng_tnum = tnum;
|
||||
out_tnum = tnum;
|
||||
#endif
|
||||
rng_tid = 0;
|
||||
out_tid = 0;
|
||||
rng_cnt = char_num;
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
char block[CHARACTERS_PER_BLOCK + LINES_PER_BLOCK];
|
||||
char * line;
|
||||
uint32_t rnd[CHARACTERS_PER_BLOCK], r;
|
||||
intnative_t cnt, col, prid, nid, ncnt;
|
||||
int cur_tid;
|
||||
#ifdef _OPENMP
|
||||
cur_tid = omp_get_thread_num();
|
||||
#else
|
||||
cur_tid = 0;
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
do
|
||||
{
|
||||
cnt = rng_gen_blk(rnd, CHARACTERS_PER_BLOCK, cur_tid);
|
||||
} while (-1 == cnt);
|
||||
|
||||
if (0 == cnt)
|
||||
{
|
||||
break;//Work finished!
|
||||
}
|
||||
|
||||
line = block;
|
||||
|
||||
for (col = 0, prid = 0; prid < cnt; prid++)
|
||||
{
|
||||
r = rnd[prid];
|
||||
|
||||
ncnt = 0;
|
||||
for (nid = 0; nid < nucl_num; nid++)
|
||||
{
|
||||
if (cumul_p[nid] <= r)
|
||||
{
|
||||
ncnt++;
|
||||
}
|
||||
}
|
||||
|
||||
*line++ = nucl_info[ncnt].letter;
|
||||
if (++col >= MAXIMUM_LINE_WIDTH)
|
||||
{
|
||||
col = 0;
|
||||
*line++ = '\n';
|
||||
}
|
||||
}
|
||||
//Check if we need to end the line
|
||||
if (0 != col)
|
||||
{
|
||||
//Last iteration didn't end the line, so finish the job.
|
||||
*line++ = '\n';
|
||||
}
|
||||
//Print results
|
||||
do
|
||||
{
|
||||
cnt = out_write(block, line - block, cur_tid);
|
||||
} while (-1 == cnt);
|
||||
//Check fot IO error
|
||||
if (0 == cnt)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
const intnative_t n = atoi(argv[1]);
|
||||
|
||||
fputs(">ONE Homo sapiens alu\n", stdout);
|
||||
const char homo_Sapiens_Alu[] =
|
||||
"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC"
|
||||
"AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG"
|
||||
"TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG"
|
||||
"AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
|
||||
repeat_And_Wrap_String(homo_Sapiens_Alu, 2 * n);
|
||||
|
||||
rng_init();
|
||||
out_init();
|
||||
|
||||
fputs(">TWO IUB ambiguity codes\n", stdout);
|
||||
nucleotide_info iub_Nucleotides_Information[] =
|
||||
{
|
||||
{ 'a', 0.27 },{ 'c', 0.12 },{ 'g', 0.12 },{ 't', 0.27 },{ 'B', 0.02 },
|
||||
{ 'D', 0.02 },{ 'H', 0.02 },{ 'K', 0.02 },{ 'M', 0.02 },{ 'N', 0.02 },
|
||||
{ 'R', 0.02 },{ 'S', 0.02 },{ 'V', 0.02 },{ 'W', 0.02 },{ 'Y', 0.02 }
|
||||
};
|
||||
generate_And_Wrap_Pseudorandom_DNA_Sequence(iub_Nucleotides_Information,
|
||||
sizeof(iub_Nucleotides_Information) / sizeof(nucleotide_info), 3 * n);
|
||||
|
||||
fputs(">THREE Homo sapiens frequency\n", stdout);
|
||||
nucleotide_info homo_Sapien_Nucleotides_Information[] =
|
||||
{
|
||||
{ 'a', 0.3029549426680 },{ 'c', 0.1979883004921 },
|
||||
{ 'g', 0.1975473066391 },{ 't', 0.3015094502008 }
|
||||
};
|
||||
generate_And_Wrap_Pseudorandom_DNA_Sequence(homo_Sapien_Nucleotides_Information,
|
||||
sizeof(homo_Sapien_Nucleotides_Information) / sizeof(nucleotide_info), 5 * n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// Original version Contributed by Jeremy Zerfas
|
||||
// M*LIB port contributed by Patrick Pélissier
|
||||
#define NDEBUG
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "m-worker.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-bptree.h"
|
||||
|
||||
// This controls the maximum length for each set of oligonucleotide frequencies
|
||||
// and each oligonucleotide count output by this program.
|
||||
#define MAXIMUM_OUTPUT_LENGTH 4096
|
||||
|
||||
// Number of outputs to display
|
||||
#define MAXMUM_NUMBER_OUTPUT 7
|
||||
|
||||
/* Define the needed containers */
|
||||
/* Define Open Addressing dictionary of uint64_t --> uint32_t. Need to define how to handle out of bound data. */
|
||||
static inline bool my_oor_equal_p(uint64_t k, unsigned char n)
|
||||
{
|
||||
return k == ~(uint64_t) n;
|
||||
}
|
||||
static inline void my_oor_set(uint64_t *k, unsigned char n)
|
||||
{
|
||||
*k = ~(uint64_t)n;
|
||||
}
|
||||
static inline size_t my_hash(uint64_t key)
|
||||
{
|
||||
return ((key) ^ (key)>>7);
|
||||
}
|
||||
DICT_OA_DEF2(dict_oligonucleotide,
|
||||
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)),
|
||||
uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_oligonucleotide_t() DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)), M_DEFAULT_OPLIST)
|
||||
|
||||
// Define a B*TREE-21 of uint32_t --> uint64_t and register its oplist
|
||||
#define TREE_CMP(a,b) ((a) > (b) ? -1 : (a) < (b)) /* reverse natural order */
|
||||
BPTREE_DEF2(tree_dict_oligonucleotide, 21, uint32_t, M_OPEXTEND(M_DEFAULT_OPLIST, CMP(TREE_CMP)), uint64_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_tree_dict_oligonucleotide_t() BPTREE_OPLIST2(tree_dict_oligonucleotide, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Define the data to analyse (a plain array) */
|
||||
ARRAY_DEF(polynucleotide, unsigned char)
|
||||
|
||||
// Macro to convert a nucleotide character to a code. Note that upper and lower
|
||||
// case ASCII letters only differ in the fifth bit from the right and we only
|
||||
// need the three least significant bits to differentiate the letters 'A', 'C',
|
||||
// 'G', and 'T'. Spaces in this array/string will never be used as long as
|
||||
// characters other than 'A', 'C', 'G', and 'T' aren't used.
|
||||
#define CODE_FOR_NUCLEOTIDE(nucleotide) (" \0 \1\3 \2"[nucleotide & 0x7])
|
||||
|
||||
// And one more macro to convert the codes back to nucleotide characters.
|
||||
#define NUCLEOTIDE_FOR_CODE(code) ("ACGT"[code & 0x3])
|
||||
|
||||
static worker_t worker;
|
||||
|
||||
// Read from the given stream the data and fill in the array with the converted one.
|
||||
static void polynucleotide_init_stream(polynucleotide_t p, FILE *stream)
|
||||
{
|
||||
char buffer[MAXIMUM_OUTPUT_LENGTH], c;
|
||||
|
||||
polynucleotide_init(p);
|
||||
polynucleotide_reserve(p, MAXIMUM_OUTPUT_LENGTH);
|
||||
// Find the start of the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stream) && memcmp(">THREE", buffer, 6));
|
||||
// Start reading and encoding the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stream) && buffer[0]!='>'){
|
||||
for(size_t i = 0; (c = buffer[i]) !='\0'; i++) {
|
||||
if (c != '\n') {
|
||||
polynucleotide_push_back(p, CODE_FOR_NUCLEOTIDE(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is the function which does 95% of the work.
|
||||
/* NOTE: paralelisation is not done by cutting the input set in two.
|
||||
This is not efficient as the size of the output table will be the same
|
||||
as for the whole table. */
|
||||
static void init_hash(dict_oligonucleotide_t hash_Table, const size_t size, const unsigned char tab[size], const size_t desiredLength, const size_t offset, const size_t skip)
|
||||
{
|
||||
uint64_t key = 0;
|
||||
const uint64_t mask = (1ULL<<(2*desiredLength))-1;
|
||||
assert (2*desiredLength < 64 && desiredLength < size);
|
||||
assert ((1 == skip || 4 == skip) && offset < size);
|
||||
|
||||
// For the first several nucleotides we only need to append them to key in
|
||||
// preparation for the insertion of complete oligonucleotides to hash.
|
||||
for(size_t i = 0; i < desiredLength - 1 + offset; i++)
|
||||
key = (key<<2) | tab[i];
|
||||
key &= mask;
|
||||
|
||||
dict_oligonucleotide_t hash;
|
||||
dict_oligonucleotide_init(hash);
|
||||
|
||||
// Add all the complete oligonucleotides of
|
||||
// desiredLength to hash, updating their count
|
||||
if (skip == 1) {
|
||||
for(size_t i = desiredLength-1+offset ; i < size; i++) {
|
||||
key = (key<<2) | tab[i+0];
|
||||
key &= mask;
|
||||
uint32_t *p = dict_oligonucleotide_get(hash, key);
|
||||
if (p != NULL) {
|
||||
(*p) ++;
|
||||
} else {
|
||||
dict_oligonucleotide_set_at(hash, key, 1);
|
||||
}
|
||||
}
|
||||
} else { // skip = 4
|
||||
for(size_t i = desiredLength-1+offset ; i < size; i+=4) {
|
||||
for (size_t j = 0; j < 4; j++)
|
||||
key = (key<<2) | tab[i+j];
|
||||
key &= mask;
|
||||
uint32_t *p = dict_oligonucleotide_get(hash, key);
|
||||
if (p != NULL) {
|
||||
(*p) ++;
|
||||
} else {
|
||||
dict_oligonucleotide_set_at(hash, key, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
dict_oligonucleotide_init_move(hash_Table, hash);
|
||||
}
|
||||
|
||||
static void compute_hash(dict_oligonucleotide_t hash_Table, const polynucleotide_t p, const size_t desiredLength)
|
||||
{
|
||||
size_t size = polynucleotide_size(p);
|
||||
unsigned char *tab = polynucleotide_get(p, 0);
|
||||
if (desiredLength < 8) {
|
||||
init_hash(hash_Table, size, tab, desiredLength, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
worker_sync_t block; // Define a synchronization block
|
||||
worker_start(block, worker);
|
||||
dict_oligonucleotide_t hash_Table3, *p_hash_Table3 = &hash_Table3;
|
||||
dict_oligonucleotide_t hash_Table2, *p_hash_Table2 = &hash_Table2;
|
||||
dict_oligonucleotide_t hash_Table1, *p_hash_Table1 = &hash_Table1;
|
||||
WORKER_SPAWN(block, (p_hash_Table1, size, tab, desiredLength), {
|
||||
init_hash(*p_hash_Table1, size, tab, desiredLength, 3, 4);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (p_hash_Table2, size, tab, desiredLength), {
|
||||
init_hash(*p_hash_Table2, size, tab, desiredLength, 2, 4);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (p_hash_Table3, size, tab, desiredLength), {
|
||||
init_hash(*p_hash_Table3, size, tab, desiredLength, 1, 4);
|
||||
}, (/*no output*/));
|
||||
init_hash(hash_Table, size, tab, desiredLength, 0, 4);
|
||||
worker_sync(block);
|
||||
|
||||
// Merge all hashtables
|
||||
dict_oligonucleotide_splice(hash_Table, hash_Table1);
|
||||
dict_oligonucleotide_splice(hash_Table, hash_Table2);
|
||||
dict_oligonucleotide_splice(hash_Table, hash_Table3);
|
||||
// Clear extra hashtables
|
||||
dict_oligonucleotide_clear(hash_Table3);
|
||||
dict_oligonucleotide_clear(hash_Table2);
|
||||
dict_oligonucleotide_clear(hash_Table1);
|
||||
}
|
||||
|
||||
// Generate frequencies for all oligonucleotides in polynucleotide that are of
|
||||
// desiredLength and then save it to output.
|
||||
static void compute_freq(const polynucleotide_t p, const size_t desiredLength, char output[])
|
||||
{
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
compute_hash(hash_Table, p, desiredLength);
|
||||
|
||||
// Order key is the count frequency (inverse value & key)
|
||||
tree_dict_oligonucleotide_t tree;
|
||||
tree_dict_oligonucleotide_init(tree);
|
||||
for M_EACH(item, hash_Table, dict_oligonucleotide_t) {
|
||||
tree_dict_oligonucleotide_set_at (tree, item->value, item->key);
|
||||
}
|
||||
|
||||
// Create Output
|
||||
char oligonucleotide[64];
|
||||
const double invSum = 100.0 / (double) (polynucleotide_size(p) - desiredLength + 1);
|
||||
int output_Position = 0;
|
||||
for M_EACH(item, tree, tree_dict_oligonucleotide_t) {
|
||||
// Convert the key for the oligonucleotide to a string.
|
||||
uint64_t freq = *item->value_ptr;
|
||||
uint32_t count = *item->key_ptr;
|
||||
for(size_t j = desiredLength-1; j < desiredLength; j--){
|
||||
oligonucleotide[j]=NUCLEOTIDE_FOR_CODE(freq);
|
||||
freq>>=2;
|
||||
}
|
||||
oligonucleotide[desiredLength]='\0';
|
||||
// Output the frequency for oligonucleotide to output.
|
||||
output_Position+=snprintf(output+output_Position, MAXIMUM_OUTPUT_LENGTH-output_Position,
|
||||
"%s %.3f\n", oligonucleotide, invSum * count);
|
||||
}
|
||||
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
tree_dict_oligonucleotide_clear(tree);
|
||||
}
|
||||
|
||||
// Generate a count for the number of times oligonucleotide appears in
|
||||
// polynucleotide and then save it to output.
|
||||
static void compute_count(polynucleotide_t p, const char oligonucleotide[], char output[])
|
||||
{
|
||||
const size_t oligonucleotide_Length = strlen(oligonucleotide);
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
compute_hash(hash_Table, p, oligonucleotide_Length);
|
||||
|
||||
// Generate the key for oligonucleotide.
|
||||
uint64_t key=0;
|
||||
for(size_t i=0; i<oligonucleotide_Length; i++)
|
||||
key = (key<<2) | CODE_FOR_NUCLEOTIDE(oligonucleotide[i]);
|
||||
|
||||
// Output the count for oligonucleotide to output.
|
||||
uint32_t *val = dict_oligonucleotide_get(hash_Table, key);
|
||||
uintmax_t count= val== NULL ? 0 : *val;
|
||||
snprintf(output, MAXIMUM_OUTPUT_LENGTH, "%ju\t%s", count, oligonucleotide);
|
||||
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialize the different worker threads by auto-detecting the number of cores of the system
|
||||
worker_init(worker, -1, 0, NULL);
|
||||
|
||||
// Read the input
|
||||
polynucleotide_t p, *ptr = &p;
|
||||
polynucleotide_init_stream(p, stdin);
|
||||
|
||||
// Prepare outputs
|
||||
char outputBuffer[MAXMUM_NUMBER_OUTPUT][MAXIMUM_OUTPUT_LENGTH];
|
||||
char (*output)[MAXIMUM_OUTPUT_LENGTH] = outputBuffer;
|
||||
|
||||
// Do the following functions in parallel.
|
||||
worker_sync_t block; // Define a synchronization block
|
||||
worker_start(block, worker);
|
||||
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTATTTTAATTTATAGT", output[6]);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTATTTTAATT", output[5]);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTATT", output[4]);
|
||||
}, (/*no output*/));
|
||||
WORKER_SPAWN(block, (ptr, output), {
|
||||
compute_count(*ptr, "GGTA", output[3]);
|
||||
}, (/*no output*/));
|
||||
compute_count(*ptr, "GGT", output[2]);
|
||||
compute_freq(*ptr, 2, output[1]);
|
||||
compute_freq(p, 1, output[0]);
|
||||
worker_sync(block);
|
||||
|
||||
// Output the results to stdout.
|
||||
for(int i=0; i<MAXMUM_NUMBER_OUTPUT; i++)
|
||||
printf("%s\n", outputBuffer[i]);
|
||||
|
||||
polynucleotide_clear(p);
|
||||
worker_clear(worker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+18
-5
@@ -51,9 +51,13 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef USE_BOOST
|
||||
#include <boost/pool/object_pool.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
static const size_t PAGE_SIZE = 4096;
|
||||
|
||||
@@ -115,6 +119,8 @@ benchmark(std::string &&desc, std::function<void ()> cb)
|
||||
* Boost::pool
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_BOOST
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_boost_pool()
|
||||
@@ -166,6 +172,7 @@ benchmark_boost_pool_create_and_destroy()
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
@@ -220,6 +227,7 @@ benchmark_mallocfree_free()
|
||||
* GLib slices
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_GLIB
|
||||
template<class T>
|
||||
void
|
||||
benchmark_glib_slices()
|
||||
@@ -262,6 +270,7 @@ benchmark_glib_slices_free()
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
@@ -798,7 +807,7 @@ benchmark_mempool_small()
|
||||
mempool_small_init (p);
|
||||
mempool_small_t *ptr = &p; // C++ lambda !
|
||||
|
||||
benchmark(std::move(Small() + "mempool"), [=]() {
|
||||
benchmark(std::move(Small() + "M*LIB mempool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Small); ++i) {
|
||||
Small *o = mempool_small_alloc(*ptr);
|
||||
touch_obj(o);
|
||||
@@ -815,7 +824,7 @@ benchmark_mempool_big()
|
||||
mempool_big_init (p);
|
||||
mempool_big_t *ptr = &p; // C++ lambda !
|
||||
|
||||
benchmark(std::move(Big() + "mempool"), [=]() {
|
||||
benchmark(std::move(Big() + "M*LIB mempool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(Big); ++i) {
|
||||
Big *o = mempool_big_alloc(*ptr);
|
||||
touch_obj(o);
|
||||
@@ -836,7 +845,7 @@ benchmark_mempool_mix_free()
|
||||
mempool_big_init (b);
|
||||
mempool_huge_init (h);
|
||||
|
||||
benchmark(std::move(std::string("mempool w/ free (Mix)")), [=]() {
|
||||
benchmark(std::move(std::string("M*LIB mempool w/ free (Mix)")), [=]() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (__builtin_expect(!(i & 0xfff), 0)) {
|
||||
Huge *o = mempool_huge_alloc (*ptr_h);
|
||||
@@ -892,19 +901,23 @@ main()
|
||||
benchmark_mallocfree_free<Big>();
|
||||
std::cout << std::endl;
|
||||
|
||||
#ifdef USE_GLIB
|
||||
benchmark_glib_slices<Small>();
|
||||
benchmark_glib_slices_free<Small>();
|
||||
benchmark_glib_slices<Big>();
|
||||
benchmark_glib_slices_free<Big>();
|
||||
std::cout << std::endl;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_BOOST
|
||||
benchmark_boost_pool<Small>();
|
||||
benchmark_boost_pool_free<Small>();
|
||||
benchmark_boost_pool<Big>();
|
||||
benchmark_boost_pool_free<Big>();
|
||||
benchmark_boost_pool_create_and_destroy();
|
||||
std::cout << std::endl;
|
||||
|
||||
#endif
|
||||
|
||||
benchmark_ngx_pool<Small>();
|
||||
benchmark_ngx_pool<Big>();
|
||||
benchmark_ngx_pool_mix_free();
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
CC= gcc
|
||||
CXX= g++
|
||||
CFLAGS= -g -Wall -O2 -fomit-frame-pointer -march=native -lm -include stddef.h
|
||||
CXXFLAGS= $(CFLAGS)
|
||||
LDFLAGS=
|
||||
OBJS=
|
||||
LIBS= -lm
|
||||
|
||||
all: run
|
||||
|
||||
benchmarks:
|
||||
git clone https://github.com/attractivechaos/benchmarks.git
|
||||
|
||||
build: benchmarks
|
||||
mkdir -p benchmarks/udb/mlib
|
||||
cp test-mlib.c benchmarks/udb/mlib/test.c
|
||||
cp Makefile-mlib benchmarks/udb/mlib/Makefile
|
||||
mkdir -p benchmarks/udb/mlib-oa
|
||||
cp test-mlib-oa.c benchmarks/udb/mlib-oa/test.c
|
||||
cp Makefile-mlib benchmarks/udb/mlib-oa/Makefile
|
||||
touch build
|
||||
|
||||
all-recur: build
|
||||
cd benchmarks/udb; \
|
||||
wdir=`pwd`; \
|
||||
list_c=`find . -name 'test.c'`; \
|
||||
list_cc=`find . -name 'test.cc'`; \
|
||||
for t in $$list_c $$list_cc ; do \
|
||||
subdir=`dirname $$t`; \
|
||||
cd $$subdir; \
|
||||
$(MAKE) CC="$(CC)" CXX="$(CXX)" DFLAGS="$(DFLAGS)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" || exit 1; \
|
||||
cd $$wdir; \
|
||||
done;
|
||||
|
||||
run: all-recur
|
||||
@cd benchmarks/udb; \
|
||||
echo ; echo "LIBRARY | INT TIME | STR TIME" ; \
|
||||
for i in `find . -name 'test'` ; do \
|
||||
printf "%s|" `dirname $$i|sed -e 's+./++g'`; \
|
||||
$$i -is | awk ' \
|
||||
/\[int data\] # element/ { nbInt= $$5 } \
|
||||
/\[int data\] CPU time/ {timeInt= $$5 } \
|
||||
/\[str data\] # element/ { nbStr= $$5 } \
|
||||
/\[str data\] CPU time/ {timeStr= $$5 } \
|
||||
END { \
|
||||
if (nbInt != 624444) timeInt="BRK" ; \
|
||||
if (nbStr != 624444) timeStr="BRK" ; \
|
||||
print timeInt,"|" ,timeStr \
|
||||
}' ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -rf benchmarks build
|
||||
@@ -0,0 +1,22 @@
|
||||
CC= gcc
|
||||
CFLAGS= -g -Wall -O2 -march=native
|
||||
OBJS= ../benchmark/benchmark.o ../runit/runlib.o test.o
|
||||
DFLAGS=
|
||||
INCLUDES= -I../benchmark -I../runit -I../../../../..
|
||||
LIBS=
|
||||
|
||||
.SUFFIXES:.c .o
|
||||
|
||||
.c.o:
|
||||
$(CC) -std=gnu11 -DNDEBUG -c $(INCLUDES) $(CFLAGS) $(DFLAGS) $< -o $@
|
||||
|
||||
all:test
|
||||
|
||||
test:$(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
||||
cleanlocal:
|
||||
rm -f *.o a.out *~ test
|
||||
|
||||
clean:cleanlocal
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-mempool.h"
|
||||
|
||||
static inline bool oor_equal_p(int k, unsigned char n)
|
||||
{
|
||||
return k == (int)-n - 1;
|
||||
}
|
||||
|
||||
static inline void oor_set(int *k, unsigned char n)
|
||||
{
|
||||
*k = (int)-n - 1;
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_int,
|
||||
int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
static const char *const oor[2] = { "EMPTY", "DELETED" };
|
||||
|
||||
static inline bool str_oor_equal_p(const char *k, unsigned char n)
|
||||
{
|
||||
return k == oor[n];
|
||||
}
|
||||
|
||||
static inline void str_oor_set(const char * *k, unsigned char n)
|
||||
{
|
||||
*k = oor[n];
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_str, const char *,
|
||||
M_OPEXTEND (M_CSTR_OPLIST, OOR_EQUAL(str_oor_equal_p), OOR_SET(str_oor_set M_IPTR)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
|
||||
int test_int(int N, const unsigned *data)
|
||||
{
|
||||
int ret;
|
||||
M_LET(h, DICT_OPLIST(dict_int)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_str(int N, char * const *data)
|
||||
{
|
||||
int ret;
|
||||
M_LET(h, DICT_OPLIST(dict_str)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return udb_benchmark(argc, argv, test_int, test_str);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-mempool.h"
|
||||
|
||||
DICT_STOREHASH_DEF2(dict_int,
|
||||
int, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(mpool_int), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
DICT_STOREHASH_DEF2(dict_str,
|
||||
const char *, M_OPEXTEND (M_CSTR_OPLIST, MEMPOOL(mpool_str), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
int test_int(int N, const unsigned *data)
|
||||
{
|
||||
int ret;
|
||||
dict_int_list_pair_mempool_init(mpool_int);
|
||||
M_LET(h, DICT_OPLIST(dict_int)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
}
|
||||
dict_int_list_pair_mempool_clear(mpool_int);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_str(int N, char * const *data)
|
||||
{
|
||||
int ret;
|
||||
dict_str_list_pair_mempool_init(mpool_str);
|
||||
M_LET(h, DICT_OPLIST(dict_str)) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
}
|
||||
dict_str_list_pair_mempool_clear(mpool_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return udb_benchmark(argc, argv, test_int, test_str);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
CC= gcc
|
||||
CXX= g++
|
||||
CFLAGS= -g -Wall -O2 -fomit-frame-pointer -march=native -lm -include stddef.h
|
||||
CXXFLAGS= $(CFLAGS)
|
||||
LDFLAGS=
|
||||
OBJS=
|
||||
LIBS=
|
||||
|
||||
all: run
|
||||
|
||||
udb2:
|
||||
git clone https://github.com/attractivechaos/udb2.git
|
||||
|
||||
build: udb2
|
||||
mkdir -p udb2/mlib
|
||||
cp test-mlib.c udb2/mlib/test.c
|
||||
cp Makefile-mlib udb2/mlib/Makefile
|
||||
touch build
|
||||
|
||||
all-recur: build
|
||||
cd udb2/stb && make CC="gcc -lm"
|
||||
cd udb2 && for dir in `ls | egrep -v '^(Makefile|common.c|_)'`; do cd $$dir && make && cd -; done
|
||||
|
||||
run: all-recur
|
||||
@cd udb2; \
|
||||
echo ; echo RUNNING BENCH ; echo ; \
|
||||
for i in `find . -name 'run-test'` ; do \
|
||||
echo ; echo `dirname $$i|sed -e 's+./++g'`; \
|
||||
$$i ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -rf udb2 build *~
|
||||
@@ -0,0 +1,8 @@
|
||||
all:run-test
|
||||
|
||||
run-test:test.c ../common.c
|
||||
$(CC) -std=gnu99 -O2 -Wall -I../../../.. $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f run-test* *~
|
||||
rm -rf mlib
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "../common.c"
|
||||
#define M_USE_DICT_OA_PROBING(s) 1
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(unsigned int k, unsigned char n)
|
||||
{
|
||||
return k == (unsigned int)n;
|
||||
}
|
||||
static inline void oor_set(unsigned int *k, unsigned char n)
|
||||
{
|
||||
*k = (unsigned int)n;
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_oa_uint,
|
||||
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(hash_fn), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
unsigned int, M_DEFAULT_OPLIST)
|
||||
|
||||
uint32_t test_int(uint32_t n, uint32_t x0)
|
||||
{
|
||||
uint32_t i, x, z = 0;
|
||||
dict_oa_uint_t h;
|
||||
dict_oa_uint_init(h);
|
||||
for (i = 0, x = x0; i < n; ++i) {
|
||||
x = hash32(x);
|
||||
unsigned int key = get_key(n, x);
|
||||
unsigned int *ptr = dict_oa_uint_get_at(h, key);
|
||||
(*ptr)++;
|
||||
z += *ptr;
|
||||
}
|
||||
fprintf(stderr, "# unique keys: %d; checksum: %u\n", (int) dict_oa_uint_size(h), z);
|
||||
z = dict_oa_uint_size(h);
|
||||
dict_oa_uint_clear(h);
|
||||
return z;
|
||||
}
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB |
+75
@@ -0,0 +1,75 @@
|
||||
API incompatibility
|
||||
-------------------
|
||||
|
||||
V0.1.*: * First formal version of API
|
||||
|
||||
V0.2.*: * worker_start takes a 'worker_t' as an additional parameter
|
||||
(This enables to perform a wait-on-event instead of a busy waiting).
|
||||
* worker_spawn doesn't take into a 'worker_t' anymore.
|
||||
* worker_init takes an int as numWorker instead of an unsigned int.
|
||||
* RBTREE pop method has been renamed into _pop_at (as it takes a key parameter).
|
||||
* SNAPSHOT_DEF has been removed. use SNAPSHOT_SPSC_DEF
|
||||
* array's _set_at2 has been replaced by array's _get_at.
|
||||
The interface is similar to dict _get_at, making the API cleaner and more generic.
|
||||
_set_at2(a,i,x) ==> set(*_get_at(a,i),x)
|
||||
* DICT_SET:
|
||||
- Rename method _set_at as _push
|
||||
Since there is no key, it is a push method, not a _set_at method.
|
||||
- Rename DICT_SET_DEF2 as DICT_SET_DEF
|
||||
since it only requires one argument.
|
||||
- The method _ref returns a pointer to the data,
|
||||
instead of a pointer to a single tuple like other DICT_SET interface.
|
||||
- The format of the output to character string as changed.
|
||||
* ALGO:
|
||||
- Rename _contains as _contain_p
|
||||
since it is a predicate '_p' and it shall be in infinitive form.
|
||||
- Rename _map as _for_each (Standard name).
|
||||
* M_PRINT_ARG & M_FPRINT_ARG don't put a final semicolon at the end
|
||||
of their expansion anymore (cleaner and no longer needed with the
|
||||
new available tools).
|
||||
* For the TUPLE and the VARIANT
|
||||
change name of _get_ ## field into _get_at_ ## fields
|
||||
Since there is a name collision with other methods
|
||||
if a field is named 'str'.
|
||||
* Rename method _remove into _erase for dictionary & B+TREE (adding a compatibility layer) for API uniformization.
|
||||
The provided _remove doesn't use an iterator but a 'key', incompatible with the one of array or list.
|
||||
But is like the one provided by the priority queue.
|
||||
|
||||
V0.3.*: * Remove B+TREE _remove method as it has been deprecated (use _erase instead)
|
||||
* Remove DICT _remove method as it has been deprecated (use _erase instead)
|
||||
* Make _it_to_p method of B+TREE / RB-TREE as deprecated (uses _it_until_p instead ).
|
||||
* Deprecated buffer options BUFFER_BLOCKING* and BUFFER_UNBLOCKING*
|
||||
as the _push_blocking and _pop_blocking functions can do the same and are more versatil.
|
||||
* Iteration over the items of a dictionnary/tree returns const iterators for access through
|
||||
OPLIST (impact: algorithm & M_EACH) as the IT_REF operator is no longer exported.
|
||||
The _it_ref method is still defined and can be used, so you can still modify the values
|
||||
but it won't be automatically used anymore (as the keys CANNOT be modified).
|
||||
(Previously it generates incorrect algorithm when used with m-dict).
|
||||
|
||||
V0.4.*: * The order of a list initialized using M_LET is reversed
|
||||
to match what is done for ARRAY (and the C++ forward_list).
|
||||
* Rename M_SKIP, M_KEEP & M_MID into M_SKIP_ARGS, M_KEEP_ARGS & M_MID_ARGS
|
||||
due to conflict with glibc malloc.h (that defines M_KEEP for compatibility).
|
||||
* Method write_string of m_serial expects a new argument (number of characters).
|
||||
* Method _init_set2 of m-i-shared is removed.
|
||||
* Operator _it_insert updates it_insertion iterator to reference the inserted element.
|
||||
* Dereference Type of an iterator of a dict / B+Tree is suffixed by _itref_t instead of _type_t.
|
||||
* Rename TUPLE _init_set2 in _init_emplace & _set2 in _emplace.
|
||||
* Rename Priority Queue method _update_further in _update.
|
||||
|
||||
V0.5.*: * M_INVERT is renamed into M_REVERSE to be more coherent with the REVERSE operator.
|
||||
M_INVERT is marked as obsolete.
|
||||
* Remove _it_to_p method of B+TREE / RB-TREE as it has been deprecated.
|
||||
* Remove ALGO_INIT_VA & M_ALG0_LET_INIT_VAI of m-algo as it has been deprecated (Use of M_LET instead).
|
||||
* Some Internal name of user modifiable macros have been renamed to be properly
|
||||
customizable by the user.
|
||||
* Rename M_HASH_SEED into M_USE_HASH_SEED (as it is a user macro).
|
||||
* M_LET: for initialization of variable with arguments, if there is only one argument,
|
||||
it will default to use INIT_SET instead of INIT_WITH.
|
||||
==> Encapsulate the argument between () to force use of INIT_WITH.
|
||||
* Remove of UPDATE operator. Use of SET for RBTREE or ADD for DICT instead.
|
||||
* Make the _clean suffix for reseting the container to empty deprecated. Use new _reset suffix instead.
|
||||
* Make the _get_at suffix for always getting a value deprecated. Use new _safe_get suffix instead.
|
||||
* Rename CLEAN operator in RESET operator.
|
||||
* Rename GET_SET_KEY operator in SAFE_GET_KEY operator.
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><!--This file was converted to xhtml by LibreOffice - see http://cgit.freedesktop.org/libreoffice/core/tree/filter/source/xslt for the code.--><head profile="http://dublincore.org/documents/dcmi-terms/"><meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8"/><title xml:lang="en-US">- no title specified</title><meta name="DCTERMS.title" content="" xml:lang="en-US"/><meta name="DCTERMS.language" content="en-US" scheme="DCTERMS.RFC4646"/><meta name="DCTERMS.source" content="http://xml.openoffice.org/odf2xhtml"/><meta name="DCTERMS.issued" content="2018-07-01T11:06:00.978729880" scheme="DCTERMS.W3CDTF"/><meta name="DCTERMS.provenance" content="" xml:lang="en-US"/><meta name="DCTERMS.subject" content="," xml:lang="en-US"/><link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" hreflang="en"/><link rel="schema.DCTERMS" href="http://purl.org/dc/terms/" hreflang="en"/><link rel="schema.DCTYPE" href="http://purl.org/dc/dcmitype/" hreflang="en"/><link rel="schema.DCAM" href="http://purl.org/dc/dcam/" hreflang="en"/><style type="text/css">
|
||||
@page { }
|
||||
table { border-collapse:collapse; border-spacing:0; empty-cells:show }
|
||||
td, th { vertical-align:top; font-size:10pt;}
|
||||
h1, h2, h3, h4, h5, h6 { clear:both }
|
||||
ol, ul { margin:0; padding:0;}
|
||||
li { list-style: none; margin:0; padding:0;}
|
||||
<!-- "li span.odfLiEnd" - IE 7 issue-->
|
||||
li span. { clear: both; line-height:0; width:0; height:0; margin:0; padding:0; }
|
||||
span.footnodeNumber { padding-right:1em; }
|
||||
span.annotation_style_by_filter { font-size:95%; font-family:Arial; background-color:#fff000; margin:0; border:0; padding:0; }
|
||||
* { margin:0;}
|
||||
.ta1 { writing-mode:lr-tb; }
|
||||
.Default { font-family:Liberation Sans; }
|
||||
.ce100 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce101 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce102 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce103 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
|
||||
.ce104 { font-family:Liberation Sans; background-color:#e6e6e6; font-size:11pt; text-decoration:underline; font-weight:bold; }
|
||||
.ce57 { font-family:Liberation Sans; background-color:transparent; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
|
||||
.ce58 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:transparent; border-left-style:none; border-right-style:none; border-top-style:none; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
|
||||
.ce59 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; font-size:11pt; text-decoration:underline; font-weight:bold; }
|
||||
.ce60 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
|
||||
.ce61 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
|
||||
.ce62 { font-family:Liberation Sans; background-color:#e6e6e6; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
|
||||
.ce63 { font-family:Liberation Sans; background-color:#e6e6e6; border-width:0,0621cm; border-style:solid; border-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; font-weight:bold; }
|
||||
.ce64 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; font-weight:bold; }
|
||||
.ce65 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
|
||||
.ce66 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
|
||||
.ce67 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6ff; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
|
||||
.ce68 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6ff; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; font-weight:bold; }
|
||||
.ce69 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6ff; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; font-weight:bold; }
|
||||
.ce70 { font-family:Liberation Sans; background-color:#e6e6e6; font-weight:bold; }
|
||||
.ce71 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:underline; font-weight:bold; }
|
||||
.ce72 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
|
||||
.ce73 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
|
||||
.ce74 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce75 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce76 { font-family:Liberation Sans; border-bottom-style:none; background-color:transparent; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce77 { font-family:Liberation Sans; text-align:center ! important; margin-left:0cm; }
|
||||
.ce78 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:underline; font-weight:bold; }
|
||||
.ce79 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
|
||||
.ce80 { font-family:Liberation Sans; border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
|
||||
.ce81 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce82 { font-family:Liberation Sans; background-color:transparent; text-align:center ! important; margin-left:0cm; }
|
||||
.ce83 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:transparent; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce84 { font-family:Liberation Sans; background-color:#ffff00; text-align:center ! important; margin-left:0cm; }
|
||||
.ce85 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#ffff00; border-left-style:none; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce86 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-style:none; border-right-style:none; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
|
||||
.ce87 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:underline; font-weight:bold; }
|
||||
.ce88 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
|
||||
.ce89 { font-family:Liberation Sans; border-bottom-style:none; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
|
||||
.ce90 { font-family:Liberation Sans; border-bottom-style:none; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce91 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce92 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce93 { font-family:Liberation Sans; border-bottom-style:none; background-color:#ffff00; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-style:none; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce94 { font-family:Liberation Sans; border-bottom-style:none; background-color:transparent; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce95 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:transparent; border-left-style:none; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.ce96 { font-family:Liberation Sans; border-bottom-style:none; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; font-size:11pt; text-decoration:none ! important; font-weight:bold; }
|
||||
.ce97 { font-family:Liberation Sans; border-bottom-width:0,0621cm; border-bottom-style:solid; border-bottom-color:#000000; background-color:#e6e6e6; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; font-weight:bold; }
|
||||
.ce98 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-width:0,0621cm; border-top-style:solid; border-top-color:#000000; text-align:center ! important; margin-left:0cm; }
|
||||
.ce99 { font-family:Liberation Sans; border-bottom-style:none; border-left-width:0,0621cm; border-left-style:solid; border-left-color:#000000; border-right-width:0,0621cm; border-right-style:solid; border-right-color:#000000; border-top-style:none; text-align:center ! important; margin-left:0cm; }
|
||||
.co1 { width:3.399cm; }
|
||||
.co10 { width:1.304cm; }
|
||||
.co11 { width:1.942cm; }
|
||||
.co12 { width:1.815cm; }
|
||||
.co13 { width:1.348cm; }
|
||||
.co14 { width:1.432cm; }
|
||||
.co15 { width:2.258cm; }
|
||||
.co2 { width:6.281cm; }
|
||||
.co3 { width:1.475cm; }
|
||||
.co4 { width:1.277cm; }
|
||||
.co5 { width:1.602cm; }
|
||||
.co6 { width:1.39cm; }
|
||||
.co7 { width:1.686cm; }
|
||||
.co8 { width:1.644cm; }
|
||||
.co9 { width:2.452cm; }
|
||||
.ro1 { height:0.487cm; }
|
||||
.ro2 { height:0.885cm; }
|
||||
.ro3 { height:0.452cm; }
|
||||
<!-- ODF styles with no properties representable as CSS -->
|
||||
{ }
|
||||
</style></head><body dir="ltr" style="writing-mode:lr-tb; "><table border="0" cellspacing="0" cellpadding="0" class="ta1"><colgroup><col width="149"/><col width="274"/><col width="64"/><col width="56"/><col width="70"/><col width="61"/><col width="74"/><col width="72"/><col width="107"/><col width="57"/><col width="107"/><col width="107"/><col width="74"/><col width="85"/><col width="79"/><col width="79"/><col width="59"/><col width="61"/><col width="63"/><col width="99"/></colgroup><tr class="ro1"><td style="text-align:left;width:3.399cm; " class="ce57"> </td><td style="text-align:left;width:6.281cm; " class="ce57"> </td><td colspan="6" style="text-align:left;width:1.475cm; " class="ce71"><p>Sequence Containers</p></td><td colspan="4" style="text-align:left;width:2.452cm; " class="ce71"><p>Associative Containers</p></td><td style="text-align:left;width:1.686cm; " class="ce96"> </td><td colspan="6" style="text-align:left;width:1.942cm; " class="ce71"><p>Synchronization Containers</p></td><td style="text-align:left;width:2.258cm; " class="ce104"> </td></tr><tr class="ro2"><td style="text-align:left;width:3.399cm; " class="ce58"> </td><td style="text-align:left;width:6.281cm; " class="ce63"><p>Method</p></td><td style="text-align:left;width:1.475cm; " class="ce72"><p>ARRAY</p></td><td style="text-align:left;width:1.277cm; " class="ce79"><p>LIST</p></td><td style="text-align:left;width:1.602cm; " class="ce79"><p>DUALP</p><p>LIST</p></td><td style="text-align:left;width:1.39cm; " class="ce79"><p>I-LIST</p></td><td style="text-align:left;width:1.686cm; " class="ce79"><p>DEQUE</p></td><td style="text-align:left;width:1.644cm; " class="ce88"><p>BITSET</p></td><td style="text-align:left;width:2.452cm; " class="ce72"><p>B+TREE</p><p>DICT/SET</p></td><td style="text-align:left;width:1.304cm; " class="ce79"><p>R/B</p><p>TREE</p></td><td style="text-align:left;width:2.452cm; " class="ce79"><p>[S]HASH</p><p>DICT / SET</p></td><td style="text-align:left;width:2.452cm; " class="ce88"><p>OA DICT</p></td><td style="text-align:left;width:1.686cm; " class="ce97"><p>PRIO </p><p>QUEUE</p></td><td style="text-align:left;width:1.942cm; " class="ce72"><p>BUFFER</p></td><td style="text-align:left;width:1.815cm; " class="ce79"><p>QUEUE </p><p>MPMC</p></td><td style="text-align:left;width:1.815cm; " class="ce79"><p>QUEUE </p><p>SPSC</p></td><td style="text-align:left;width:1.348cm; " class="ce79"><p>SNAP</p><p>SPSC</p></td><td style="text-align:left;width:1.39cm; " class="ce79"><p>SNAP</p><p>SPMC</p></td><td style="text-align:left;width:1.432cm; " class="ce88"><p>SNAP </p><p>MPMC</p></td><td style="text-align:left;width:2.258cm; " class="ce70"> </td></tr><tr class="ro1"><td style="text-align:left;width:3.399cm; " class="ce59"><p>CONSTRUCTOR</p></td><td style="text-align:left;width:6.281cm; " class="ce64"><p>_init</p></td><td style="text-align:left;width:1.475cm; " class="ce73"><p>X</p></td><td style="text-align:left;width:1.277cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.602cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.39cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.686cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.644cm; " class="ce89"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce73"><p>X</p></td><td style="text-align:left;width:1.304cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce89"><p>X</p></td><td style="text-align:left;width:1.686cm; " class="ce98"><p>X</p></td><td style="text-align:left;width:1.942cm; " class="ce73"><p>X</p></td><td style="text-align:left;width:1.815cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.815cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.348cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.39cm; " class="ce80"><p>X</p></td><td style="text-align:left;width:1.432cm; " class="ce89"><p>X</p></td><td style="text-align:left;width:2.258cm; " class="Default"> </td></tr><tr class="ro1"><td style="text-align:left;width:3.399cm; " class="ce60"> </td><td style="text-align:left;width:6.281cm; " class="ce65"><p>_set</p></td><td style="text-align:left;width:1.475cm; " class="ce74"><p>X</p></td><td style="text-align:left;width:1.277cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:1.602cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:1.39cm; " class="ce77"> </td><td style="text-align:left;width:1.686cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:1.644cm; " class="ce90"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce74"><p>X</p></td><td style="text-align:left;width:1.304cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce77"><p>X</p></td><td style="text-align:left;width:2.452cm; " class="ce90"><p>X</p></td><td style="text-align:left;width:1.686cmLine truncated
|
||||
Binary file not shown.
+142
-21
@@ -2,34 +2,155 @@ How to make a release?
|
||||
======================
|
||||
|
||||
1) Check that all test pass on all primary systems.
|
||||
Run 'make check' on all primary systems.
|
||||
Run 'make check' or 'make checkall' on all primary systems.
|
||||
No error shall be reported.
|
||||
|
||||
2) Check that no memory leak is reported by valgrind:
|
||||
Run 'make valgrind' in tests folder on a system.
|
||||
|
||||
3) Check that no undefined behavior, nor data race, ... is reported by sanitizer:
|
||||
2) Check that no undefined behavior, nor data race, ... is reported by sanitizer:
|
||||
Run 'make sanitize' in tests folder on a system.
|
||||
This needs at least GCC 7
|
||||
|
||||
4) Check that no new warning is reported by static analyser:
|
||||
Run 'make scan-build' in tests folder on a system.
|
||||
This needs at least clang 4.
|
||||
Currently there is a false positive detected in m-shared:
|
||||
"Argument to free() is offset by 8 bytes from the start of memory allocated by malloc()"
|
||||
scan-build is not able to properly track that this case cannot open.
|
||||
|
||||
5) Check that coverage is reasonnable.
|
||||
3) Check that coverage is reasonable.
|
||||
Run 'make coverage' and analyze result.
|
||||
|
||||
In case of problem, open a problem error.
|
||||
4) Publish the release
|
||||
|
||||
List of primary systems
|
||||
=======================
|
||||
In case of problem, open a problem report.
|
||||
|
||||
* gcc 4.9 on linux/x86-64
|
||||
* gcc 7 on linux/x86-64
|
||||
* clang 3.5 on linux/x86-64
|
||||
* clang 4 on linux/x86-64
|
||||
* g++ 7 on linux/x86-64
|
||||
|
||||
List of automatically tested systems
|
||||
====================================
|
||||
|
||||
* gcc on linux/x86-64 (32 bits and 64 bits)
|
||||
* g++ on linux/x86-64 (32 bits and 64 bits)
|
||||
* clang on macos/x86-64
|
||||
* clang++ on macos/x86-64
|
||||
* tcc on linux/x86-64
|
||||
* gcc on windows/x86-64 (mingw)
|
||||
* msvc on windows/x86-64
|
||||
* clang on windows/x86-64
|
||||
|
||||
List of manually tested systems
|
||||
===============================
|
||||
|
||||
* clang on linux/x86-64
|
||||
* clang on linux/armv7l
|
||||
* gcc on linux/powerpc
|
||||
* gcc on linux/armv7l
|
||||
|
||||
Atomic library
|
||||
==============
|
||||
|
||||
For the targets armel, m68k, mips, mipsel, powerpc, powerpcspe or sh4,
|
||||
you may need to run the test suite by adding the atomic library:
|
||||
|
||||
make check LDFLAGS="-pthread -latomic"
|
||||
|
||||
since 'atomic' library is not automatically included for 32 bits systems.
|
||||
|
||||
|
||||
Cross compilation
|
||||
=================
|
||||
|
||||
There is no need to cross compile the library as it is a header only library.
|
||||
|
||||
However if you want to run the tests with a cross-compiler, do like the following
|
||||
command. It performs a cross-compilation of the test suite from linux to windows
|
||||
and run the test suite with wine:
|
||||
|
||||
make CC="i586-mingw32msvc-gcc -std=c99 -DWINVER=0x600 -D_WIN32_WINNT=0x600" LOG_COMPILER=wine check
|
||||
|
||||
|
||||
Handling issues
|
||||
===============
|
||||
|
||||
Issues are opened in the bug tracker of the project (typically https://github.com/P-p-H-d/mlib/issues )
|
||||
|
||||
If the issue cannot be taken into account quickly and are long term,
|
||||
it should be moved into the long term issues included in the repository:
|
||||
https://github.com/P-p-H-d/mlib/blob/master/doc/ISSUES.org
|
||||
This is a file in ORG mode: the issues are created with the proper tags.
|
||||
|
||||
The original issue in the tracker can then be closed with the issuer agreement.
|
||||
|
||||
This will have the following gains:
|
||||
|
||||
- no hard dependencies on any bug tracking infrastructure (can be migrated easily).
|
||||
- a release will automatically contain all its open problem reports.
|
||||
|
||||
Once one issue of ISSUES.org is taken into account,
|
||||
its state shall be changed to DONE (the issue shall not be removed).
|
||||
|
||||
|
||||
Debugging
|
||||
=========
|
||||
|
||||
Debugging the library can be quite difficult
|
||||
as it performs heavy preprocessing expansion
|
||||
and expands all code in one line.
|
||||
Different strategy for debugging the library itself are still possible:
|
||||
|
||||
1) Good old printf.
|
||||
Add printf of interresting values in the debugged function.
|
||||
|
||||
|
||||
2) Preprocess the library and then compile the preprocessed file like this:
|
||||
|
||||
cc -std=c99 -E test-file.c > test-file.i
|
||||
perl -pi -e 's/;/;\n/g' test-file.i
|
||||
cc -std=c99 -c -Wall test-file.i
|
||||
|
||||
The resulting executable can be debugged much more easily.
|
||||
|
||||
|
||||
3) To debug the preprocessing itself, the Boot Wave library can be used
|
||||
and in particular the [wave driver](https://www.boost.org/doc/libs/1_71_0/libs/wave/doc/wave_driver.html)
|
||||
|
||||
Add in the code the following pragmas around the code to debug:
|
||||
|
||||
#pragma wave trace(enable)
|
||||
ARRAY_DEF (array_charp, char *)
|
||||
#pragma wave trace(disable)
|
||||
|
||||
Run the wave driver:
|
||||
|
||||
./wave ex-array01.c -I .. --c99 -t test.trace
|
||||
|
||||
The different expansion performed by the library are described in test.trace
|
||||
|
||||
Coding rules
|
||||
============
|
||||
|
||||
* Use of non standard C shall be protected under a specific compiler test,
|
||||
so that the library remains compatible with a strict C99 compiler.
|
||||
|
||||
* C11 features shall be optional.
|
||||
|
||||
* Use 'make format' to format the header files properly.
|
||||
|
||||
* External types shall be suffixed by _t and in lower case
|
||||
but shall be optional if the user doesn't want then.
|
||||
|
||||
* Internal types shall be suffixed by _ct and in lower case
|
||||
(as confidential types)
|
||||
|
||||
* External / Internal functions shall be in lower case.
|
||||
|
||||
* External / Internal macros shall be in upper case.
|
||||
|
||||
* Internal macros / functions shall be prefixed by m_<container>
|
||||
with container is the name of the container with one letter transformed:
|
||||
o --> 0
|
||||
e --> 3
|
||||
i --> 1
|
||||
y --> 4
|
||||
This prevents the automatic completion to work when the user starts writing its function.
|
||||
|
||||
* Test functions shall be predicated and be suffixed by '_p'
|
||||
|
||||
|
||||
Misc
|
||||
====
|
||||
|
||||
To put a breakpoint for the thread sanitizer in case of error, in gdb add:
|
||||
|
||||
$ set env TSAN_OPTIONS=halt_on_error=1,abort_on_error=1
|
||||
+453
@@ -0,0 +1,453 @@
|
||||
*Long term issues*
|
||||
------------------
|
||||
|
||||
* TODO #26 : Hash-Map for huge objects :ENHANCEMENT:
|
||||
|
||||
Specialize Hashmap for huge objects on supported hardware:
|
||||
|
||||
Based on OA hash map with taggued pointer (needs space for tagging):
|
||||
low bits = high bits of hash
|
||||
pointer to object { key, hash, value }
|
||||
|
||||
Can solve collision without dereferencing object with 1/2^lowbits chances.
|
||||
NB: hash may be uneeded due to the small chances of collision.
|
||||
Reduce cache usage ==> Should be faster.
|
||||
Increase cache usage for very small object (integer).
|
||||
|
||||
Use of pointer to avoid moving object on GC.
|
||||
|
||||
On AMD64, only 48 bits of 64 bits are really used for addressing data.
|
||||
==> lowbits= 16
|
||||
Empty representation= 0 (hash can be 0. pointer cannot be it).
|
||||
Deleted representation = 1 (pointer cannot be zero)
|
||||
|
||||
<---- PTR ----><-HASH->
|
||||
|
||||
#+BEGIN_SRC C
|
||||
#define LOW_BITS 16
|
||||
#define ALIGNED_BITS 2
|
||||
void *get_ptr(int64_t x) {
|
||||
return (void*) ((x >> LOW_BITS) << ALIGNED_BITS);
|
||||
}
|
||||
unsigned get_small_hash(int64_t x) {
|
||||
return x & ((1<<LOW_BITS)-1);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
* TODO #25 : Support of error code model for error handling. :ENHANCEMENT:
|
||||
|
||||
Find a way to support error return code for the API in case of allocation
|
||||
failure.
|
||||
|
||||
Any service that returns void shall return a "int".
|
||||
In case of allocation failure, it shall return an error.
|
||||
M_CALL macro shall stop its execution if the service returns an error code
|
||||
and the error code represents an error (avoid rewritting everything)
|
||||
and throw back the error code (stopping the execution flow).
|
||||
|
||||
Services returning already something shall not be modified.
|
||||
|
||||
This model should be applied at the container level only and not globally.
|
||||
Different containers may need different levels of error handling.
|
||||
4 combinaison to take into account:
|
||||
|
||||
==> ABORT on container / ABORT on used type: The current model
|
||||
==> ABORT on container / RETCODE on used type: Needs to abort on reported error.
|
||||
==> RETCODE on container / ABORT on used type: Nothing particular to note.
|
||||
==> RETCODE on container / RETCODE on used type: Forward retcode to caller.
|
||||
|
||||
Find a way to make it while not making the code too complex
|
||||
(try to keep as simple as possible).
|
||||
|
||||
Using a specialized oplist for such containers (_OPLIST_RETCODE)
|
||||
using a specialized API for retcode:
|
||||
|
||||
API_RET_*: that expands to
|
||||
|
||||
if (func(args) == 0) goto handler_exit_failure;
|
||||
|
||||
Adding at the end of each service:
|
||||
M_END_FUNCTION(cleanup_code) that expands to different cases:
|
||||
M_END_FUNCTION_VALUE(cleanup_code, return_success, return_failure) that expands to different cases:
|
||||
|
||||
ABORT/ABORT:
|
||||
handler_exit_success:
|
||||
handler_exit_failure:
|
||||
return;
|
||||
|
||||
ABORT/RETCODE:
|
||||
handler_exit_success:
|
||||
return;
|
||||
handler_exit_failure:
|
||||
RAISE_FATAL_ERROR
|
||||
|
||||
RETCODE/ABORT
|
||||
handler_exit_success:
|
||||
return SUCESS;
|
||||
handler_exit_failure:
|
||||
cleanup_code
|
||||
return FAILURE;
|
||||
|
||||
RETCODE/RETCODE
|
||||
handler_exit_success:
|
||||
return SUCESS;
|
||||
handler_exit_failure:
|
||||
cleanup_code
|
||||
return FAILURE;
|
||||
|
||||
If really needed, the macro can be avoided and code can be hand written.
|
||||
|
||||
Open points:
|
||||
- How to handle warnings on unused labels?
|
||||
- What about M_LET/ M_EACH?
|
||||
|
||||
|
||||
* TODO #24 : New: Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
|
||||
See https://en.wikipedia.org/wiki/Min-max_heap
|
||||
as DPRIORITY_QUEUE_DEF ?
|
||||
|
||||
NOTE: Needs for such container?
|
||||
|
||||
|
||||
* TODO #23: Strict MOVE semantic to clarify :ENHANCEMENT:
|
||||
|
||||
Some type may need to have a force MOVE semantic (for example, they can store
|
||||
pointer to themselves). Currently the INIT_MOVE & MOVE operators are more
|
||||
a help for performance than a strict semantic usage.
|
||||
|
||||
** ARRAY container
|
||||
|
||||
The ARRAY container doesn't support strict MOVE semantic for example.
|
||||
It is not a simple matter as it performs a realloc of the table, thus
|
||||
moving the data before they can be moved using MOVE. Two solutions:
|
||||
|
||||
- New operator MOVE_SELF to fix a type after it has been moved.
|
||||
- If MOVE defined, force another table and then copy by hand the type. This will be slower and consumme more memory.
|
||||
|
||||
** MOVE in OPLIST :ENHANCEMENT:
|
||||
|
||||
Proposal: do not export INIT_MOVE / MOVE operator in OPLIST if the MOVE operator is
|
||||
compatible with a pure COPY semantic. An exported MOVE operator will tell
|
||||
other containers than the type shall be carefully moved using the provided
|
||||
MOVE operator.
|
||||
|
||||
For example for tuple, it shall
|
||||
|
||||
- create an init_move operator if no one has disabled INIT_MOVE,
|
||||
- export the init_move operator if at least one has exported a INIT_MOVE and no one has disabled INIT_MOVE.
|
||||
|
||||
** DO_INIT_MOVE operator
|
||||
|
||||
DO_INIT_MOVE macro is not also fully working for structure
|
||||
defined with [1] tricks but without an explicit INIT_MOVE / MOVE
|
||||
operators as it uses MOVE_DEFAULT which is not (fully compatible).
|
||||
==> Analyse limitation and possible constraint usages.
|
||||
|
||||
|
||||
* TODO #20: New: Bucket priority queue :ENHANCEMENT:
|
||||
|
||||
Add a new kind of priority queue.
|
||||
See https://en.wikipedia.org/wiki/Bucket_queue
|
||||
|
||||
Check if it will be better as intrusive or non-intrusive container.
|
||||
|
||||
To test if a bucket is empty or not, a bitfield can be used to check if
|
||||
the bit associated to the bucket is set or not. To get the highest bucket
|
||||
non empty, we can perform a CLZ of the bitset, which shall be much faster than
|
||||
performing a linear search of the buckets (algorithm complexity is the same,
|
||||
except that we can scan 64 entries at a time).
|
||||
|
||||
Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
|
||||
implementation.
|
||||
|
||||
|
||||
* TODO #19: New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
|
||||
Add intrusive red black tree.
|
||||
Look also for AVL tree (NOTE: Is there a performance difference between the two?)
|
||||
|
||||
|
||||
* TODO #18: Missing methods :ENHANCEMENT:
|
||||
|
||||
Some containers don't have all the methods they should.
|
||||
See the cells in yellow here:
|
||||
http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html
|
||||
|
||||
|
||||
* TODO #17: New: Ressource handler :ENHANCEMENT:
|
||||
|
||||
A global 'ressouce handler' which shall associated a unique handle to a ressource.
|
||||
The handle shall be unique for the ressource and shall not be reused.
|
||||
It is typically a 64 bits integers always incremented (even if the program
|
||||
creates one billion ressources per second, the counter won't overflow
|
||||
until 585 years).
|
||||
|
||||
The ressource handler shall make an association between a HANDLE 64 bits and:
|
||||
|
||||
- how much real owners claim to own the ressource
|
||||
(the ressource is only owned by the ressource handler, however
|
||||
it acts as a delegate of the real owner),
|
||||
- how much users keep a pointer to the ressource.
|
||||
- pointer to the resource itself.
|
||||
|
||||
This may be a better alternative than shared_ptr & weak_ptr:
|
||||
|
||||
- reduce fragmentation,
|
||||
- no cycle dependencies,
|
||||
- shared_ref & weak_ref becomes only HANDLE,
|
||||
- all ressources can be freed in one pass.
|
||||
|
||||
Needs lock free dictionnary or at least concurrent dictionnary.
|
||||
|
||||
How to handle multiple resource ?
|
||||
|
||||
* variant: works fine. Memory usage can be (much) higher than needed if there is a lot of dissimilarity between the size of the objects.
|
||||
* embedded the type in the ressource handler: more work, API more complex. Memory usage seems better.
|
||||
|
||||
|
||||
* TODO #16: New: Lock Free List :ENHANCEMENT:
|
||||
|
||||
Implement a lock free list. Most of the difficulty is the memory reclamation part.
|
||||
Typically this lock free list shall be compatible with RCU method.
|
||||
|
||||
** First step: backoff methods :DONE:
|
||||
** Second step: lock free node pool : :DONE:
|
||||
Done as m-c-mempool header.
|
||||
|
||||
** Third step: Implement generic lock free list on top of it.
|
||||
|
||||
The ABA problem is already taken into account by the memory alloctor
|
||||
provided that the lock free list doesn't try to be smart.
|
||||
|
||||
backoff has be used when using CAS.
|
||||
|
||||
Concurrent insertion / insertion and insertion / deletion and deletion / deletion shall be crefully analyzed when taken into account.
|
||||
|
||||
Questions:
|
||||
- singly or doubly or dual push?
|
||||
- needs to be logically deleted : needs a previous field
|
||||
(NULL if not logically deleted) ? TBC
|
||||
|
||||
|
||||
* TODO #15: Prologue / Epilogue for Constructor / Destructor for error handling :ENHANCEMENT:
|
||||
|
||||
Constructor (and destructor) need to use user-defined prologue / epilogue.
|
||||
This is in order to register the constructed object into a proper Exception
|
||||
Handling Stack so that throwing exceptions may work reliably.
|
||||
|
||||
Proposal:
|
||||
|
||||
- M_CONSTRUCTOR_PROLOGUE(object, oplist);
|
||||
- M_CONSTRUCTOR_EPILOGUE(object, oplist);
|
||||
- M_DESTRUCTOR_PROLOGUE(object, oplist);
|
||||
- M_DESTRUCTOR_EPILOGUE(object, oplist);
|
||||
|
||||
Object creation will need to add all sub-objects into the stack,
|
||||
then unstack all to push instead the root object (which recursively remove them).
|
||||
|
||||
See also http://freetype.sourceforge.net/david/reliable-c.html#cseh
|
||||
|
||||
- How to handle like allocation of the object?
|
||||
- How to avoid calling the destructor multiple times? (It is needed?)
|
||||
- How the code can be factorized with RETCODE needs?
|
||||
|
||||
|
||||
* TODO #14: Memory allocation enhancement :ENHANCEMENT:
|
||||
|
||||
Enhancement of the memory allocation scheme to find way to deal properly with advanced allocators:
|
||||
|
||||
- non-default alignment requirements for types,
|
||||
- instance-based allocator (may need instance based variable access),
|
||||
- expected life of created type (temporary or permanent),
|
||||
- stack based allocator,
|
||||
- global variable access for allocator,
|
||||
- maximum allocation before failure.
|
||||
|
||||
Most of theses are already more or less supported. Examples shall be created to show how to deal with this:
|
||||
|
||||
- alignement shall be implemented with the attributes of <stdalign.h>
|
||||
|
||||
However I sill don't know how to implement "instance-based allocator" which is what is missing.
|
||||
The problem is how to give to methods context local information store within the container itself.
|
||||
|
||||
Update:
|
||||
|
||||
API transformation support enables "instance-based allocator" to be made easily.
|
||||
Needs some formal operator in the oplist to support it fully and an example.
|
||||
|
||||
Can be supported using another API extension, some more operators and forcing some names:
|
||||
|
||||
* API_N: call like FUNC(obj->extra_data, type)
|
||||
|
||||
'obj' is a forced named corresponding to an alias to an object in the function.
|
||||
Operator needed:
|
||||
|
||||
- EXTRA_DATA: Add an extra-data field wihtin the container. Defines the type of data.
|
||||
|
||||
It is a kind of object inheritance where the container inherits some extra data from its base.
|
||||
|
||||
|
||||
* TODO #12: New: Atomic shared pointer :ENHANCEMENT:
|
||||
|
||||
Add an extension to the SHARED_PTR API:
|
||||
|
||||
- New type atomic_shared_ptr
|
||||
- name_init_atomic_set (&atomic_shared_ptr, shared_ptr);
|
||||
- name_init_set_atomic (shared_ptr, &atomic_shared_ptr);
|
||||
- name_init_atomic_set_atomic (&atomic_shared_ptr, &atomic_shared_ptr);
|
||||
- name_atomic_set (&atomic_shared_ptr, shared_ptr);
|
||||
- name_set_atomic (shared_ptr, &atomic_shared_ptr);
|
||||
- name_atomic_set_atomic (&atomic_shared_ptr, &atomic_shared_ptr);
|
||||
- name_atomic_clear
|
||||
|
||||
No _ref or direct _init: we need to init first a normal shared_ptr then the atomic (TBC)
|
||||
|
||||
** _atomic_set method:
|
||||
|
||||
It can be implemented by incrementing the non atomic shared pointer reference,
|
||||
then performs a compare_and_swap to the data of the atomic shared pointer,
|
||||
finally decrement and dec/free the swapped previous data of the atomic like a normal shared pointer.
|
||||
All 3 steps are safe.
|
||||
|
||||
** _set_atomic method:
|
||||
|
||||
It needs to perform the following atomic operation : <read the pointer, deref pointer and increment the pointed value> I don't known how to do it properly.
|
||||
|
||||
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4162.pdf
|
||||
|
||||
Proposition for _set_atomic we store temporary NULL to the atomic_ptr struct to request an exclusive access to the data (this looks like a lock and other operations need to handle NULL) :
|
||||
|
||||
#+BEGIN_SRC C
|
||||
void shared_ptr_set_atomic(ptr a, atomic_ptr *ptr)
|
||||
{
|
||||
// Get exclusive access to the data
|
||||
p = atomic_load(ptr);
|
||||
do {
|
||||
if (p == NULL) {
|
||||
// TODO: exponential backoff
|
||||
p = atomic_load(ptr);
|
||||
continue;
|
||||
}
|
||||
} while (!atomic_compare_exchange_weak(ptr, &p, NULL));
|
||||
// p has exclusive access to the pointer
|
||||
p->data->cpt ++;
|
||||
a->data = p->data;
|
||||
atomic_exchange (ptr, p);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
This prevents using NULL which obliges atomic shared pointer to point to a created object...
|
||||
|
||||
Other alternative solution is to use the bit 0 to mark the pointer as being updated, preventing other from using it (TBC only clear):
|
||||
|
||||
#+BEGIN_SRC C
|
||||
void shared_ptr_set_atomic(ptr a, atomic_ptr *ptr)
|
||||
{
|
||||
// Get exclusive access to the data
|
||||
p = atomic_load(ptr);
|
||||
do {
|
||||
if ( (p&1) != 0) {
|
||||
// TODO: exponential backoff
|
||||
p = atomic_load(ptr);
|
||||
continue;
|
||||
}
|
||||
} while (!atomic_compare_exchange_weak(ptr, &p, p|1));
|
||||
// Exclusive access (kind of lock).
|
||||
p->data->cpt ++;
|
||||
a->data = p->data;
|
||||
atomic_set (ptr, p);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
Other implementation seems to have it hard to be lock-free: cf. https://github.com/llvm-mirror/libcxx/commit/5fec82dc0db3623546038e4a86baa44f749e554f
|
||||
|
||||
|
||||
|
||||
* TODO #5: New: Concurrent dictionary Container :ENHANCEMENT:
|
||||
|
||||
Implement a more efficient dictionary than lock + std dictionary for all operations when dealing with threads.
|
||||
See https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
|
||||
|
||||
The best parallel algorithm is still when there is as few synchronization as possible. A concurrent dictionary will fail at this and will result in average performance at best.
|
||||
The typical best case will be in RCU context (a lot of readers, few writers), so the interface shall be compatible with such structure.
|
||||
|
||||
** Multiple locks within the dictionnary
|
||||
|
||||
A potential implementation may be to request at initialization time the number of concurrent thread N.
|
||||
Create a static array of N dictionnary with N mutex. Then to access the data will perform :
|
||||
|
||||
- compute hash of object,
|
||||
- access high bits of hash and select which dictionnary shall have the data,
|
||||
- lock it,
|
||||
- perform classic access to the data (check if the compiler can properly optimize the hash computation),
|
||||
- unlock it.
|
||||
|
||||
The property of the hash shall allow a good dispersion of the data across multiple locks, reducing the constraints on the lock. This implementation could be build easily upon the already existent dictionary.
|
||||
|
||||
To test.
|
||||
|
||||
See also https://github.com/simonhf/sharedhashfile
|
||||
|
||||
** Lock Free dictionnary
|
||||
|
||||
Evaluate also lock-free dictionary (easier with open addressing).
|
||||
It needs a complete rewrite of the inner loop through. The hard part is the dynamic resizing of the internal array.
|
||||
Ssee http://preshing.com/20160222/a-resizable-concurrent-map/ for a potential solution
|
||||
and http://www.cs.toronto.edu/~tomhart/papers/tomhart_thesis.pdf for memory reclamation techniques).
|
||||
and https://www.research.ibm.com/people/m/michael/spaa-2002.pdf
|
||||
https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2017.11.22a.pdf presents different techniques used by linux kernel.
|
||||
It needs before lock-free list: http://www.cse.yorku.ca/~ruppert/papers/lfll.pdf http://www.cse.yorku.ca/~ruppert/Mikhail.pdf
|
||||
|
||||
A good way maybe Open Addessing table used only for indirection and a freelist memory reclamation container for handle the entries
|
||||
(like a transaction).
|
||||
|
||||
Solution?
|
||||
--------
|
||||
|
||||
Use of the concurrent pool (m-c-mempool) to allocate items.
|
||||
The big table will only store pointers (+ part of hash in unused bits?) to such allocate items.
|
||||
Atomic update is done by allocating a new node, update it, and atomicaly store it in the dict, putting the old one as logically deleted and to reclaim later.
|
||||
(Other threads may still read its data so we cannot free immediatly).
|
||||
|
||||
|
||||
* DONE #22: Enhanced services for SPSC Queue :ENHANCEMENT:
|
||||
|
||||
Add services:
|
||||
|
||||
** DONE _push_bulk
|
||||
Test the capacity of the queue and push as much as possible in the queue
|
||||
with one check of the atomic structure.
|
||||
|
||||
** DONE _pop_bulk
|
||||
Test the capacity of the queue and push as much as possible in the queue
|
||||
with one check of the atomic structure.
|
||||
|
||||
** DONE _push_force:
|
||||
|
||||
If the capacity of the queue is full, pop one element and push it:
|
||||
push always succeed and the queue always keep the youngest element.
|
||||
|
||||
* DONE #21: Generic Binary serialization :ENHANCEMENT:
|
||||
|
||||
Based on issue #26 of https://github.com/P-p-H-d/mlib/issues/26
|
||||
|
||||
Some kind of "binary serialization" on the model of get_str/parse_str
|
||||
could be possible. It would be a great feature from the application
|
||||
point-of-view: binary representation is more bandwidth-efficient if
|
||||
used on network communications.
|
||||
|
||||
It will be good to have import/export methods to the
|
||||
XML/JSON/MSGPACK/PROTOBUF/BINARY format.
|
||||
However, adding all of them on by one in the M*LIB containers
|
||||
doesn't seem satisfactory.
|
||||
|
||||
Instead, adding a generic interface for the serialization of data
|
||||
that may be customized by the user to perform the import/export of
|
||||
objects in whatever format they want into what they want (FILE/memory/...).
|
||||
To simplify it, this interface could only support one kind of import/export
|
||||
per compilation unit.
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
+34
-5
@@ -1,18 +1,47 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# + Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# + Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
CC=cc -std=c99
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function
|
||||
CFLAGS=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
|
||||
GMP_DIR=
|
||||
CPPFLAGS=-I..
|
||||
LDFLAGS=-pthread -lgmp
|
||||
LDFLAGS=-pthread
|
||||
RM=rm -f
|
||||
|
||||
.SUFFIXES: .c .exe
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
|
||||
|
||||
all:
|
||||
all: config
|
||||
$(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'`
|
||||
if test "$(CC)" = "cc -std=c99" ; then $(MAKE) `ls ex11-*.c|sed -e 's/\.c/\.exe/g'` CC="cc -std=c11" ; fi
|
||||
|
||||
config:
|
||||
printf "#include <gmp.h>\nint main(void){mpz_t z; mpz_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp config-test.c -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0" > config
|
||||
$(RM) config-test.c config-test.exe
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
/* Define a dynamic array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this dynamic array globally */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
/* Define some standards algorithms on this dynamic array */
|
||||
ALGO_DEF(vector_int, vector_int_t)
|
||||
|
||||
/* Define a dynamic array of bool */
|
||||
ARRAY_DEF(vector_bool, bool, M_BOOL_OPLIST)
|
||||
/* Register the oplist of this dynamic array globally */
|
||||
#define M_OPL_vector_bool_t() ARRAY_OPLIST(vector_bool, M_BOOL_OPLIST)
|
||||
/* Define some standards algorithms on this dynamic array */
|
||||
ALGO_DEF(vector_bool, vector_bool_t)
|
||||
|
||||
/* ID function */
|
||||
static bool id(bool x) { return x ; }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define, init (& later clear) myvector & tmp as vector_int_t
|
||||
M_LET(myvector, tmp, vector_int_t) {
|
||||
// Fill myvector with 3 int equal to 20
|
||||
vector_int_fill_n(myvector, 3, 20);
|
||||
// Fill tmp with 3 int equal to 33
|
||||
vector_int_fill_n(tmp, 3, 33);
|
||||
// Append all tmp in myvector
|
||||
vector_int_splice(myvector, tmp);
|
||||
// Fill tmp with 2 int equal to 10
|
||||
vector_int_fill_n(tmp, 2, 10);
|
||||
// Append all tmp in myvector
|
||||
vector_int_splice(myvector, tmp);
|
||||
// Display the result
|
||||
printf("myvector contains:");
|
||||
// In C11, the for loop can be simplified as :
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
ALGO_FOR_EACH(myvector, vector_int_t, M_PRINT, " ");
|
||||
#else
|
||||
for M_EACH(it, myvector, vector_int_t) {
|
||||
printf(" %d", *it);
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Same thing but with booleans
|
||||
M_LET(myvector, tmp, vector_bool_t) {
|
||||
vector_bool_fill_n(myvector, 3, false);
|
||||
vector_bool_fill_n(tmp, 3, true);
|
||||
vector_bool_splice(myvector, tmp);
|
||||
vector_bool_fill_n(tmp, 2, false);
|
||||
vector_bool_splice(myvector, tmp);
|
||||
printf("myvector contains:");
|
||||
for M_EACH(it, myvector, vector_bool_t) {
|
||||
printf(" %d", (int)*it);
|
||||
}
|
||||
printf("\n");
|
||||
printf ("ALL: %d ANY: %d NONE: %d\n",
|
||||
vector_bool_all_of_p(myvector, id),
|
||||
vector_bool_any_of_p(myvector, id),
|
||||
vector_bool_none_of_p(myvector, id) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define a dictionnary (or hash_map or undordered_map)
|
||||
* from a string_t to int */
|
||||
DICT_DEF2(dict, string_t, int)
|
||||
/* Register the oplist of this dictionnary globally */
|
||||
#define M_OPL_dict_t() DICT_OPLIST(dict, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Define an array of integer */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this array of integer globally */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
/* Micro macro to detect if a string starts with the given pattern */
|
||||
#define start_with(pattern, item) \
|
||||
string_start_with_str_p((item).key, (pattern))
|
||||
|
||||
/* Micro macro to get the value of a pair of (key, value) */
|
||||
#define get_value(out, item) ((out) = (item).value)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int s;
|
||||
// Init keys as a vector_int_t, initialize it (and prepare its destruction)
|
||||
M_LET(keys, vector_int_t)
|
||||
// Initialize m as a dictionnary and initialize it with the given database
|
||||
// Initialize tmp as a dictionanry
|
||||
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) {
|
||||
|
||||
/* Extract all elements of 'm' that starts with 'b' */
|
||||
ALGO_EXTRACT(tmp, dict_t, m, dict_t, start_with, "b");
|
||||
/* Extract the values of theses elements */
|
||||
ALGO_TRANSFORM(keys, vector_int_t, tmp, dict_t, get_value);
|
||||
/* Sum theses values */
|
||||
ALGO_REDUCE(s, keys, vector_int_t, sum);
|
||||
printf("Sum of elements starting with 'b' is: %d\n", s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "m-algo.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define an array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this array of int globally */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
/* Set s (string_t) to the integer i */
|
||||
#define str_ui(s, i) string_printf(s, "%d", i)
|
||||
|
||||
/* Concat two strings by insertion a '-' within them */
|
||||
#define str_cat(s1, s2) (string_cat_str(s1, "-"), string_cat(s1, s2))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let s be a string_t and initilize it.
|
||||
M_LET(s, string_t)
|
||||
// Let v be a vector of integer and initialize it.
|
||||
M_LET( (v, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), vector_int_t) {
|
||||
int sum, product;
|
||||
|
||||
// Compute the sum of theses integers.
|
||||
ALGO_REDUCE(sum, v, vector_int_t, add);
|
||||
|
||||
// Compute the product of theses integers.
|
||||
ALGO_REDUCE(product, v, vector_int_t, mul);
|
||||
|
||||
/* Example of reduction with a transformation of the type from int to string_t */
|
||||
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, str_ui);
|
||||
|
||||
printf ("sum: %d\n"
|
||||
"product: %d\n"
|
||||
"dash str: %s\n", sum, product, string_get_cstr(s));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
/* Include M*LIB header */
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "m-tuple.h"
|
||||
|
||||
/* Provide several examples of different types usage with array,
|
||||
with the oplist to use for each case.
|
||||
|
||||
Each time it creates and initializes an array,
|
||||
fills it with some number,
|
||||
computes its sum,
|
||||
and returns it.
|
||||
|
||||
This is done for several basic C types:
|
||||
- integers,
|
||||
- floats,
|
||||
- pointers,
|
||||
- structures,
|
||||
- tuples
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Generate prototypes and inline functions
|
||||
for basic types.
|
||||
For integer and floats, there is no need to specify
|
||||
an oplist. M_DEFAULT_OPLIST will be used.
|
||||
*/
|
||||
ARRAY_DEF(r_bool, bool)
|
||||
|
||||
/* Basic usage of the type */
|
||||
static int
|
||||
test_bool(int n)
|
||||
{
|
||||
r_bool_t array;
|
||||
|
||||
r_bool_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
r_bool_push_back(array, i & 1);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
s += *r_bool_get(array, i);
|
||||
}
|
||||
|
||||
r_bool_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type char */
|
||||
ARRAY_DEF(r_char, char)
|
||||
|
||||
static int
|
||||
test_char(int n)
|
||||
{
|
||||
r_char_t array;
|
||||
|
||||
r_char_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
r_char_push_back(array, i & 255);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
s += *r_char_get(array, i);
|
||||
}
|
||||
|
||||
r_char_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type signed int. */
|
||||
ARRAY_DEF(r_int, signed int)
|
||||
|
||||
static int
|
||||
test_int(int n)
|
||||
{
|
||||
r_int_t array;
|
||||
|
||||
r_int_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
r_int_push_back(array, i);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
s += *r_int_get(array, i);
|
||||
}
|
||||
|
||||
r_int_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type signed int.
|
||||
But with an explicit oplist.
|
||||
This generates exactly the same code than r_int
|
||||
*/
|
||||
ARRAY_DEF(r_int2, signed int, M_DEFAULT_OPLIST)
|
||||
|
||||
static int
|
||||
test_int2(int n)
|
||||
{
|
||||
r_int2_t array;
|
||||
|
||||
r_int2_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
r_int2_push_back(array, i);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
s += *r_int2_get(array, i);
|
||||
}
|
||||
|
||||
r_int2_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type unsigned long long */
|
||||
ARRAY_DEF(r_ullong, unsigned long long)
|
||||
|
||||
static int
|
||||
test_ullong(int n)
|
||||
{
|
||||
r_ullong_t array;
|
||||
|
||||
r_ullong_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
r_ullong_push_back(array, i);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
s += *r_ullong_get(array, i);
|
||||
}
|
||||
|
||||
r_ullong_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type float */
|
||||
ARRAY_DEF(r_float, float)
|
||||
|
||||
static int
|
||||
test_float(int n)
|
||||
{
|
||||
r_float_t array;
|
||||
|
||||
r_float_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
r_float_push_back(array, i/4.0);
|
||||
}
|
||||
|
||||
float s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
s += *r_float_get(array, i);
|
||||
}
|
||||
|
||||
r_float_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type double and an explicit oplist*/
|
||||
ARRAY_DEF(r_double, double, M_DEFAULT_OPLIST)
|
||||
|
||||
static int
|
||||
test_double(int n)
|
||||
{
|
||||
r_double_t array;
|
||||
|
||||
r_double_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
r_double_push_back(array, i/4.0);
|
||||
}
|
||||
|
||||
float s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
s += *r_double_get(array, i);
|
||||
}
|
||||
|
||||
r_double_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Helper function strdup */
|
||||
static char *my_strdup(const char *p)
|
||||
{
|
||||
size_t s = strlen(p);
|
||||
char *d= malloc(s+1);
|
||||
if(!d) abort();
|
||||
strcpy(d, p);
|
||||
return d;
|
||||
}
|
||||
|
||||
/* Same with type const char *, representing a contant string.
|
||||
We *** need *** an explicit oplist to tell M*LIB
|
||||
to consider the type as a constant string.
|
||||
The oplist to use is M_CSTR_OPLIST.
|
||||
We could have used M_PTR_OPLIST too,
|
||||
but in this case, we won't get proper string order or
|
||||
string equality.
|
||||
*/
|
||||
ARRAY_DEF(r_cstring, const char *, M_CSTR_OPLIST)
|
||||
|
||||
static int
|
||||
test_cstring(int n)
|
||||
{
|
||||
r_cstring_t array;
|
||||
|
||||
r_cstring_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
char buffer[10];
|
||||
// Create a string from the integer
|
||||
sprintf(buffer, "%d", i);
|
||||
// We need to make an explicit copy of the string
|
||||
// since it is not supported by the basic type.
|
||||
char *p = my_strdup(buffer);
|
||||
// Push the copy in the container.
|
||||
r_cstring_push_back(array, p);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get back the string
|
||||
const char *p = *r_cstring_get(array, i);
|
||||
// Convert it to integer
|
||||
int j = atoi(p);
|
||||
s += j;
|
||||
}
|
||||
|
||||
// We also need a special unalloc pass
|
||||
// to free all constant strings we have allocated.
|
||||
for(int i = 0; i < n; i++) {
|
||||
const char *p = *r_cstring_get(array, i);
|
||||
free((void*)(uintptr_t)p);
|
||||
}
|
||||
|
||||
r_cstring_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type string_t of M*LIB, representing a variable string.
|
||||
We don't need explicit oplist to tell M*LIB!
|
||||
The oplist to use is STRING_OPLIST,
|
||||
but it has been registered globaly, so we don't need to explicit
|
||||
give it to array_def! */
|
||||
ARRAY_DEF(r_string, string_t)
|
||||
|
||||
static int
|
||||
test_string(int n)
|
||||
{
|
||||
r_string_t array;
|
||||
string_t str;
|
||||
|
||||
r_string_init(array);
|
||||
string_init (str);
|
||||
|
||||
for(int i = 0; i < n; i++) {
|
||||
// create a string from an integer
|
||||
string_printf(str, "%d", i);
|
||||
// No need to make a copy in the container!
|
||||
r_string_push_back(array, str);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get back the string and convert it back to an integer
|
||||
int j = atoi(string_get_cstr(*r_string_get(array, i)));
|
||||
s += j;
|
||||
}
|
||||
|
||||
// No need to explicit dealloc !
|
||||
string_clear(str);
|
||||
r_string_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with type string_t of M*LIB, representing a variable string
|
||||
and its explicit oplist. And said above, it generates exactly the
|
||||
same code. */
|
||||
ARRAY_DEF(r_string2, string_t, STRING_OPLIST)
|
||||
|
||||
|
||||
|
||||
/* Same with type 'volatile unsigned int *'
|
||||
The array stores pointers to another integer,
|
||||
allocated somewhere else.
|
||||
We need to tell M*LIB to handle the basic type
|
||||
as pointers without caring for what the value of
|
||||
the pointer is.
|
||||
So here, we **need** to specify the oplist of the type
|
||||
as M_PTR_OPLIST.
|
||||
*/
|
||||
ARRAY_DEF(r_vintptr, volatile unsigned int *, M_PTR_OPLIST)
|
||||
|
||||
static int
|
||||
test_vintptr(int n)
|
||||
{
|
||||
r_vintptr_t array;
|
||||
|
||||
// Allocate a secondary table to store the value.
|
||||
unsigned *tab = calloc(n, sizeof(volatile unsigned int));
|
||||
if (!tab) abort();
|
||||
|
||||
r_vintptr_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
tab[i] = i*i - i;
|
||||
// Push the pointer to this integer in the array
|
||||
r_vintptr_push_back(array, &tab[i]);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get the pointer to the integer.
|
||||
volatile unsigned *p = *r_vintptr_get(array, i);
|
||||
s += *p;
|
||||
}
|
||||
|
||||
r_vintptr_clear(array);
|
||||
free(tab);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with a structure type.
|
||||
We need to tell M*LIB to handle the basic type
|
||||
as POD;
|
||||
So here, we **need** to specify the oplist of the type
|
||||
as M_POD_OPLIST.
|
||||
*/
|
||||
struct rock_me_out {
|
||||
int n;
|
||||
float other;
|
||||
};
|
||||
|
||||
ARRAY_DEF(r_rockme, struct rock_me_out, M_POD_OPLIST)
|
||||
|
||||
static int
|
||||
test_rockme(int n)
|
||||
{
|
||||
r_rockme_t array;
|
||||
|
||||
r_rockme_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
struct rock_me_out rock;
|
||||
rock.n = i*i - i;
|
||||
// Push the struct in the array
|
||||
r_rockme_push_back(array, rock);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get the pointer to the struct
|
||||
struct rock_me_out *p = r_rockme_get(array, i);
|
||||
s += p->n;
|
||||
}
|
||||
|
||||
r_rockme_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with a structure type defined with [1]:
|
||||
We need to tell M*LIB to handle the basic type
|
||||
as a special array;
|
||||
So here, we **need** to specify the oplist of the type
|
||||
as M_A1_OPLIST.
|
||||
*/
|
||||
typedef struct rock_me_in {
|
||||
int n;
|
||||
float other;
|
||||
} rock_me_in[1];
|
||||
|
||||
ARRAY_DEF(r_rockme2, rock_me_in, M_A1_OPLIST)
|
||||
|
||||
static int
|
||||
test_rockme2(int n)
|
||||
{
|
||||
r_rockme2_t array;
|
||||
|
||||
r_rockme2_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
rock_me_in rock;
|
||||
rock->n = i*i - i;
|
||||
r_rockme2_push_back(array, rock);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get the pointer to the struct.
|
||||
rock_me_in *p = r_rockme2_get(array, i);
|
||||
s += (*p)->n;
|
||||
}
|
||||
|
||||
r_rockme2_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with a structure type defined with [1] and a global registeration.
|
||||
We need to tell M*LIB to handle the basic type
|
||||
as a special array.
|
||||
|
||||
To do so, we register the oplist of rock_us_t by defining a macro based
|
||||
on M_OPL_ + type name + () which expands with the oplist of the type.
|
||||
|
||||
Then we define the array, giving it only the type.
|
||||
M*LIB will look at the global registered oplist of the type, we don't
|
||||
need to give it explictly.
|
||||
|
||||
Global registeration makes easier code.
|
||||
Registeration should be done when the type is defined.
|
||||
*/
|
||||
#define M_OPL_rock_me_in() M_A1_OPLIST
|
||||
|
||||
ARRAY_DEF(r_rockme2b, rock_me_in)
|
||||
|
||||
static int
|
||||
test_rockme2b(int n)
|
||||
{
|
||||
r_rockme2b_t array;
|
||||
|
||||
r_rockme2b_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
rock_me_in rock;
|
||||
rock->n = i*i - i;
|
||||
r_rockme2b_push_back(array, rock);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get the pointer to the struct.
|
||||
rock_me_in *p = r_rockme2b_get(array, i);
|
||||
s += (*p)->n;
|
||||
}
|
||||
|
||||
r_rockme2b_clear(array);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with a structure type defined as a tuple.
|
||||
|
||||
We first define a tuple. No need to specify the oplist as it uses basic C types
|
||||
so M_DEFAULT_OPLIST is used.
|
||||
|
||||
Then we define the array, giving it the oplist definition of the tuple:
|
||||
the macro TUPLE_OPLIST is used to build it based on the tuple name,
|
||||
and the oplists of the tuple.
|
||||
*/
|
||||
TUPLE_DEF2(rock_you, (n, int), (other, float))
|
||||
|
||||
ARRAY_DEF(r_rockme3, rock_you_t, TUPLE_OPLIST(rock_you, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
|
||||
static int
|
||||
test_rockme3(int n)
|
||||
{
|
||||
r_rockme3_t array;
|
||||
rock_you_t x;
|
||||
|
||||
r_rockme3_init(array);
|
||||
rock_you_init(x);
|
||||
|
||||
for(int i = 0; i < n; i++) {
|
||||
rock_you_set_n(x, i*i - i);
|
||||
r_rockme3_push_back(array, x);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get the pointer to the structure containing the integer.
|
||||
rock_you_t *p = r_rockme3_get(array, i);
|
||||
s += (*p)->n;
|
||||
}
|
||||
|
||||
r_rockme3_clear(array);
|
||||
rock_you_clear(x);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Same with a structure type defined as a tuple using global registeration.
|
||||
|
||||
We first define a tuple. No need to specify the oplist as it uses basic C types
|
||||
so M_DEFAULT_OPLIST is used.
|
||||
|
||||
Then we register the oplist of rock_us_t by defining a macro based
|
||||
on M_OPL_ + type name + () which expands with the oplist of the type.
|
||||
|
||||
Then we define the array, giving it only the type.
|
||||
M*LIB will look at the global registered oplist of the type, we don't
|
||||
need to give it explictly.
|
||||
|
||||
Global registeration makes easier code.
|
||||
*/
|
||||
TUPLE_DEF2(rock_us, (n, int), (other, float))
|
||||
|
||||
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
ARRAY_DEF(r_rockme4, rock_us_t)
|
||||
|
||||
static int
|
||||
test_rockme4(int n)
|
||||
{
|
||||
r_rockme4_t array;
|
||||
rock_us_t x;
|
||||
|
||||
r_rockme4_init(array);
|
||||
rock_us_init(x);
|
||||
|
||||
for(int i = 0; i < n; i++) {
|
||||
rock_us_set_n(x, i*i - i);
|
||||
r_rockme4_push_back(array, x);
|
||||
}
|
||||
|
||||
int s = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get the pointer to the structure containing the integer.
|
||||
rock_us_t *p = r_rockme4_get(array, i);
|
||||
s += (*p)->n;
|
||||
}
|
||||
|
||||
r_rockme4_clear(array);
|
||||
rock_us_clear(x);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, const char *argv[])
|
||||
{
|
||||
int n = argc == 1 ? 10 : atoi(argv[1]);
|
||||
int s;
|
||||
|
||||
s = test_bool(n);
|
||||
printf ("S[bool] = %d\n", s);
|
||||
|
||||
s = test_char(n);
|
||||
printf ("S[char] = %d\n", s);
|
||||
|
||||
s = test_int(n);
|
||||
printf ("S[int] = %d\n", s);
|
||||
|
||||
s = test_int2(n);
|
||||
printf ("S[int2] = %d\n", s);
|
||||
|
||||
s = test_ullong(n);
|
||||
printf ("S[ullong] = %d\n", s);
|
||||
|
||||
s = test_float(n);
|
||||
printf ("S[float] = %d\n", s);
|
||||
|
||||
s = test_double(n);
|
||||
printf ("S[double] = %d\n", s);
|
||||
|
||||
s = test_cstring(n);
|
||||
printf ("S[cstring] = %d\n", s);
|
||||
|
||||
s = test_string(n);
|
||||
printf ("S[string] = %d\n", s);
|
||||
|
||||
s = test_vintptr(n);
|
||||
printf ("S[vintptr] = %d\n", s);
|
||||
|
||||
s = test_rockme(n);
|
||||
printf ("S[rockme] = %d\n", s);
|
||||
|
||||
s = test_rockme2(n);
|
||||
printf ("S[rockme2] = %d\n", s);
|
||||
|
||||
s = test_rockme2b(n);
|
||||
printf ("S[rockme2b] = %d\n", s);
|
||||
|
||||
s = test_rockme3(n);
|
||||
printf ("S[rockme3] = %d\n", s);
|
||||
|
||||
s = test_rockme3(n);
|
||||
printf ("S[rockme4] = %d\n", s);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#include <stdlib.h>
|
||||
#include "m-array.h"
|
||||
|
||||
// Let's define an array of 'int' named 'int'
|
||||
// Let's define an array of 'int' named 'array_int'
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
const int n = 100000;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Declare and initilize the array
|
||||
// Declare and initialize the array
|
||||
array_int_t x;
|
||||
array_int_init(x);
|
||||
|
||||
|
||||
+13
-1
@@ -1,9 +1,13 @@
|
||||
#if HAVE_GMP
|
||||
|
||||
#include <gmp.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
/* Define an array of mpz_t */
|
||||
ARRAY_DEF(array_mpz, mpz_t, M_CLASSIC_OPLIST(mpz))
|
||||
/* Define some algorithm functions on array_mpz_t */
|
||||
ALGO_DEF(array_mpz, ARRAY_OPLIST(array_mpz, M_CLASSIC_OPLIST(mpz)))
|
||||
|
||||
static inline void my_mpz_inc(mpz_t *d, const mpz_t a){
|
||||
@@ -19,14 +23,22 @@ int main(void)
|
||||
mpz_init_set_ui(z, 1);
|
||||
array_mpz_t a;
|
||||
array_mpz_init(a);
|
||||
|
||||
array_mpz_push_back(a, z);
|
||||
for(size_t i = 2 ; i < 1000; i++) {
|
||||
mpz_mul_ui(z, z, i);
|
||||
array_mpz_push_back(a, z);
|
||||
}
|
||||
/* z = sum (a[i]^2) */
|
||||
|
||||
/* Compute z = sum (a[i]^2) */
|
||||
array_mpz_map_reduce (&z, a, my_mpz_inc, my_mpz_sqr);
|
||||
gmp_printf ("Z=%Zd\n", z);
|
||||
|
||||
array_mpz_clear(a);
|
||||
mpz_clear(z);
|
||||
}
|
||||
|
||||
#else
|
||||
// Nothing to do
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* This example show how to use complex structure with array
|
||||
embedding another library */
|
||||
|
||||
/* This is a typical trivial library with its interface */
|
||||
typedef struct lib_ext_struct {
|
||||
int id;
|
||||
// Other data may be added
|
||||
} lib_ext_struct;
|
||||
|
||||
/* Method to create a duplicate of the object.
|
||||
The new object is heap allocated */
|
||||
static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj)
|
||||
{
|
||||
lib_ext_struct *p = malloc(sizeof(lib_ext_struct));
|
||||
if (!p) abort();
|
||||
p->id = obj->id;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Method to delete any object */
|
||||
static void lib_ext_struct_Delete(lib_ext_struct *obj)
|
||||
{
|
||||
free(obj);
|
||||
}
|
||||
|
||||
/* This is the complex structure */
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
string_t type;
|
||||
lib_ext_struct* properties;
|
||||
} data_node;
|
||||
|
||||
/* This method shall initialize the object data_node to
|
||||
the init state.
|
||||
It takes as first argument the object to initialize,
|
||||
and since it takes by reference through a pointer,
|
||||
it is compatible with 'API_2' convention for oplist */
|
||||
static void data_node_init(data_node *obj)
|
||||
{
|
||||
obj->id = 0;
|
||||
string_init(obj->type);
|
||||
obj->properties = NULL;
|
||||
}
|
||||
|
||||
/* This method shall initialize the object data_node to
|
||||
the same state as the 'src' object (creating a copy, a duplicate) .
|
||||
It takes as first argument the object to initialize,
|
||||
and as second argument the source object.
|
||||
It takes both object by reference through pointers,
|
||||
as such it is compatible with 'API_6' convention for oplist */
|
||||
static void data_node_init_set(data_node *obj, const data_node *src)
|
||||
{
|
||||
obj->id = src->id;
|
||||
string_init_set(obj->type, src->type);
|
||||
if (src->properties)
|
||||
obj->properties = lib_ext_struct_Duplicate(src->properties);
|
||||
else
|
||||
obj->properties = NULL;
|
||||
}
|
||||
|
||||
/* This method shall set the object data_node to
|
||||
the same state as the 'src' object (creating a copy, a duplicate) .
|
||||
THe object was already initialized.
|
||||
It takes as first argument the object to initialize,
|
||||
and as second argument the source object.
|
||||
It takes both object by reference through pointers,
|
||||
as such it is compatible with 'API_6' convention for oplist */
|
||||
static void data_node_set(data_node *obj, const data_node *src)
|
||||
{
|
||||
obj->id = src->id;
|
||||
string_set(obj->type, src->type);
|
||||
if (obj->properties)
|
||||
lib_ext_struct_Delete(obj->properties);
|
||||
if (src->properties)
|
||||
obj->properties = lib_ext_struct_Duplicate(src->properties);
|
||||
else
|
||||
obj->properties = NULL;
|
||||
}
|
||||
|
||||
/* This method shall clear the object data_node to
|
||||
the cleared state (aka it shall free any resource).
|
||||
It takes as first argument the object to initialize,
|
||||
and since it takes by reference through a pointer,
|
||||
it is compatible with 'API_2' convention for oplist */
|
||||
static void data_node_clear(data_node *obj)
|
||||
{
|
||||
string_clear(obj->type);
|
||||
if (obj->properties)
|
||||
lib_ext_struct_Delete(obj->properties);
|
||||
}
|
||||
|
||||
/* Create a dynamic array of 'data_node' named array_data_node_t
|
||||
and gives the minimum oplist allowing M*LIB to handle
|
||||
properly the object 'data_node' with the API convention
|
||||
to respect for calling the methods.
|
||||
*/
|
||||
ARRAY_DEF(/* the array prefix */ array_data_node,
|
||||
/* the object type */ data_node,
|
||||
/* the object oplist */ (INIT(API_2(data_node_init)),
|
||||
SET(API_6(data_node_set)),
|
||||
INIT_SET(API_6(data_node_init_set)),
|
||||
CLEAR(API_2(data_node_clear))))
|
||||
|
||||
/* Define a global array with the created type */
|
||||
array_data_node_t global_array;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Call the created method */
|
||||
array_data_node_init(global_array);
|
||||
/* Do stuff... */
|
||||
array_data_node_clear(global_array);
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// -- An A* pathfinder inspired by the tutorial at Red Blob Games --
|
||||
// https://www.redblobgames.com/pathfinding/a-star/introduction.html
|
||||
// Code based on:
|
||||
// https://github.com/glouw/ctl/blob/master/examples/astar.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-prioqueue.h"
|
||||
#include "m-dict.h"
|
||||
|
||||
// Create a tuple of point, but don't use its priority field for comparison.
|
||||
TUPLE_DEF2( point, (x, int), (y, int), (priority, int, M_OPEXTEND( M_OPL_int(), CMP(0), HASH(0), EQUAL(0) ) ) )
|
||||
#define M_OPL_point_t() TUPLE_OPLIST(point, M_OPL_int(), M_OPL_int(), M_OPL_int())
|
||||
static inline int point_cmp_prio(const point_t a, const point_t b)
|
||||
{
|
||||
return a->priority < b->priority ? -1 : a->priority > b->priority;
|
||||
}
|
||||
PRIOQUEUE_DEF(prio_point, point_t, M_OPEXTEND(M_OPL_point_t(), CMP(point_cmp_prio) ) )
|
||||
#define M_OPL_prio_point_t() PRIOQUEUE_OPLIST(prio_point, M_OPL_point_t() )
|
||||
ARRAY_DEF(array_point, point_t)
|
||||
#define M_OPL_array_point_t() ARRAY_OPLIST(array_point, M_OPL_point_t() )
|
||||
DICT_DEF2(cost_point, point_t, int)
|
||||
#define M_OPL_cost_point_t() DICT_OPLIST(cost_point, M_OPL_point_t(), M_OPL_int())
|
||||
DICT_DEF2(step_point, point_t, point_t)
|
||||
#define M_OPL_step_point_t() DICT_OPLIST(step_point, M_OPL_point_t(), M_OPL_point_t())
|
||||
|
||||
static inline int point_index(const point_t p, int width)
|
||||
{
|
||||
return p->x + width * p->y;
|
||||
}
|
||||
|
||||
static inline void point_set_from(point_t p, const string_t maze, int width, const char pattern[])
|
||||
{
|
||||
size_t s = string_search_str(maze, pattern);
|
||||
point_emplace(p, s % width, s / width , 0);
|
||||
}
|
||||
|
||||
static void astar(array_point_t path, const string_t maze, int width)
|
||||
{
|
||||
M_LET(front, prio_point_t)
|
||||
M_LET(from, step_point_t)
|
||||
M_LET(costs, cost_point_t)
|
||||
M_LET(start, goal, current, next, point_t)
|
||||
{
|
||||
point_set_from(start, maze, width, "@");
|
||||
point_set_from(goal, maze, width, "!");
|
||||
cost_point_set_at(costs, start, 0);
|
||||
prio_point_push(front, start);
|
||||
while (!prio_point_empty_p(front)) {
|
||||
prio_point_pop(¤t, front);
|
||||
if (point_equal_p(current, goal))
|
||||
break;
|
||||
const struct { int x; int y; } deltas[] = {
|
||||
{ -1, +1 }, { 0, +1 }, { 1, +1 },
|
||||
{ -1, 0 }, /* ~ ~ */ { 1, 0 },
|
||||
{ -1, -1 }, { 0, -1 }, { 1, -1 },
|
||||
};
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
point_emplace(next, current->x + deltas[i].x, current->y + deltas[i].y, 0);
|
||||
if (string_get_char(maze, point_index(next, width)) != '#') {
|
||||
int *new_cost = cost_point_get(costs, current);
|
||||
int *cost = cost_point_get(costs, next);
|
||||
if (cost == NULL || *new_cost < *cost) {
|
||||
cost_point_set_at(costs, next, *new_cost);
|
||||
next->priority = *new_cost + abs(goal->x - next->x) + abs(goal->y - next->y);
|
||||
prio_point_push(front, next);
|
||||
step_point_set_at(from, next, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
point_set(current, goal);
|
||||
while (!point_equal_p(current, start)) {
|
||||
array_point_push_back(path, current);
|
||||
point_set(current, *step_point_get(from, current));
|
||||
}
|
||||
array_point_push_back(path, start);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET( (maze,
|
||||
("#########################################################################\n"
|
||||
"# # # # # # #\n"
|
||||
"# # ######### # ##### ######### ##### ##### ##### # ! #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"######### # ######### ######### ##### # # # ######### #\n"
|
||||
"# # # # # # # # # # #\n"
|
||||
"# # ############# # # ######### ##### # ######### # #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ############# ##### ##### # ##### ######### # ##### #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ##### ##### # ##### # ######### # # # #############\n"
|
||||
"# # # # # # # # # # # #\n"
|
||||
"############# # # # ######### # ##### # ##### ##### #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ##### # ######### ##### # ##### ##### ############# #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# # ######### # ##### ######### # # ############# # #\n"
|
||||
"# # # # # # # # # # #\n"
|
||||
"# ######### # # # ##### ######### ######### # #########\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# @ # ##### ##### ##### ######### ##### # ######### # #\n"
|
||||
"# # # # # # #\n"
|
||||
"#########################################################################\n")), string_t)
|
||||
M_LET(path, array_point_t)
|
||||
{
|
||||
int width = string_search_str(maze, "\n") + 1;
|
||||
astar(path, maze, width);
|
||||
for M_EACH(it, path, array_point_t) {
|
||||
string_set_char(maze, point_index(*it, width), 'x');
|
||||
}
|
||||
printf("%s", string_get_cstr(maze));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "m-bptree.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a map int -> string named map_employee_id
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_id, 5, int, string_t)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
|
||||
// Define a map string -> int named map_employee_name
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_name, 5, string_t, int)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
map_employee_id_t Employees;
|
||||
map_employee_id_init(Employees);
|
||||
|
||||
// Assign the map with some data
|
||||
map_employee_id_set_at(Employees, 17425, STRING_CTE("Mike"));
|
||||
map_employee_id_set_at(Employees, 7147, STRING_CTE("Tango"));
|
||||
map_employee_id_set_at(Employees, 841, STRING_CTE("Charlie"));
|
||||
map_employee_id_set_at(Employees, 11632, STRING_CTE("John Do"));
|
||||
map_employee_id_set_at(Employees, 852, STRING_CTE("Peter"));
|
||||
map_employee_id_set_at(Employees, 530, STRING_CTE("Amanda"));
|
||||
map_employee_id_set_at(Employees, 4258, STRING_CTE("Elisabeth"));
|
||||
|
||||
printf("Number of employees: %zu\n", map_employee_id_size(Employees));
|
||||
|
||||
// Iterate over the employee list
|
||||
printf("\nList of employees (sorted by id):\n");
|
||||
map_employee_id_it_t it;
|
||||
for(map_employee_id_it(it, Employees); !map_employee_id_end_p(it); map_employee_id_next(it)) {
|
||||
// Get a pointer to this employee from the iterator
|
||||
const map_employee_id_itref_t *e = map_employee_id_cref(it);
|
||||
// Print it
|
||||
printf ("%d: %s\n", *(e->key_ptr), string_get_cstr(*(e->value_ptr)));
|
||||
}
|
||||
|
||||
// Now, let's go using some macros!
|
||||
|
||||
// Let's create a reverse map
|
||||
M_LET(Employees_r, map_employee_name_t) {
|
||||
|
||||
// Let's fill in the reverse map with each employee
|
||||
// (using macro M_EACH)
|
||||
for M_EACH(e, Employees, map_employee_id_t) {
|
||||
map_employee_name_set_at(Employees_r, *(e->value_ptr), *(e->key_ptr));
|
||||
}
|
||||
|
||||
// Iterate over the employee list
|
||||
printf("\nList of employees (sorted by name):\n");
|
||||
for M_EACH(e, Employees_r, map_employee_name_t) {
|
||||
printf ("%d: %s\n", *(e->value_ptr), string_get_cstr(*(e->key_ptr)));
|
||||
}
|
||||
|
||||
// Print
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
|
||||
} /* Employees_r is cleared beyond this point */
|
||||
|
||||
map_employee_id_clear(Employees);
|
||||
return 0;
|
||||
}
|
||||
+27
-14
@@ -5,11 +5,13 @@
|
||||
#include "m-mutex.h"
|
||||
|
||||
/* Global variable to stop scheduling */
|
||||
bool continue_threading_g;
|
||||
atomic_bool continue_threading_g;
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Define a random big data structure */
|
||||
/* Define a custom random big data structure
|
||||
with its constructor and its destructor.
|
||||
*/
|
||||
|
||||
#define BIGDATA_SIZE 1000
|
||||
#define BIGDATA_NUM 10
|
||||
@@ -28,6 +30,7 @@ static void bigdata_init(bigdata_t d)
|
||||
{
|
||||
memset(d->bigdata, 0, BIGDATA_SIZE);
|
||||
d->ptr = malloc (BIGDATA_HEIGHT*BIGDATA_WIDTH);
|
||||
if (!d->ptr) abort();
|
||||
d->count = count_g++;
|
||||
printf ("Init image %d\n", d->count);
|
||||
}
|
||||
@@ -38,19 +41,25 @@ static void bigdata_clear(bigdata_t d)
|
||||
free(d->ptr);
|
||||
}
|
||||
|
||||
/* Let's register the oplist of our custom type globally */
|
||||
#define M_OPL_bigdata_t() (INIT(bigdata_init), CLEAR(bigdata_clear))
|
||||
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* Perform some random works on this big data */
|
||||
/* Perform some random works on this custom type */
|
||||
|
||||
static void perform_acquisition(bigdata_t p)
|
||||
{
|
||||
printf ("Acquiring image %d\n", p->count);
|
||||
// Let's say that rand is our acquisition function.
|
||||
for(int i = 0 ; i < BIGDATA_SIZE;i++)
|
||||
p->bigdata[i] = rand();
|
||||
for(int i = 0 ; i < BIGDATA_WIDTH*BIGDATA_HEIGHT;i++)
|
||||
p->ptr[i] = rand();
|
||||
// Let's stop arbitrary after 20 acquisitions
|
||||
if (p->count == 20)
|
||||
continue_threading_g = false;
|
||||
atomic_store(&continue_threading_g, false);
|
||||
}
|
||||
|
||||
static void perform_computation2(bigdata_t p)
|
||||
@@ -69,7 +78,7 @@ static void perform_computation3(bigdata_t p)
|
||||
|
||||
static void perform_computation4(bigdata_t p)
|
||||
{
|
||||
printf ("Computation 4 on image %d\n", p->count);
|
||||
printf ("Reduction on image %d\n", p->count);
|
||||
unsigned long s = 0;
|
||||
for(int i = 0 ; i < BIGDATA_WIDTH*BIGDATA_HEIGHT;i++)
|
||||
s += p->ptr[i];
|
||||
@@ -81,11 +90,12 @@ static void perform_computation4(bigdata_t p)
|
||||
/**************************************************************/
|
||||
|
||||
/* Let's define a shared pointer interface around the bigdata structure */
|
||||
SHARED_PTR_DEF(shared_bigdata, bigdata_t, (INIT(bigdata_init), CLEAR(bigdata_clear)))
|
||||
SHARED_PTR_DEF(shared_bigdata, bigdata_t)
|
||||
|
||||
/* Let's define the communication queue between the thread:
|
||||
* - size of queue is 10,
|
||||
* - it is a queue BUFFER_QUEUE,
|
||||
* - it store shared pointer to our bigdata_t,
|
||||
* - we change the semantics of _push / _pop into buffer as push a new item and pop it as a move (ideal semantics for shared_ptr interface).
|
||||
*/
|
||||
#define MY_QUEUE_SIZE 10
|
||||
@@ -94,11 +104,11 @@ BUFFER_DEF(buffer_bigdata, shared_bigdata_t, MY_QUEUE_SIZE,
|
||||
|
||||
/* Let's build a Thread synchros tree:
|
||||
*
|
||||
* Thread1 perform the simulation acquisition of the data.
|
||||
* Thread2 & Thread3 perform independet computation.
|
||||
* Thread1 perform the simulated acquisition of the data.
|
||||
* Thread2 & Thread3 perform independent computation.
|
||||
* Thread4 finalizes the computation :
|
||||
*
|
||||
* Thread1 ---> Thread 2
|
||||
* Thread1 ---> Thread 2 +
|
||||
* +-> Thread 3 --> Thread 4
|
||||
*/
|
||||
buffer_bigdata_t buf_t1tot2;
|
||||
@@ -123,7 +133,7 @@ static void clearbuf(void)
|
||||
static void thread1 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init_new (ptr);
|
||||
perform_acquisition(*shared_bigdata_ref(ptr));
|
||||
@@ -135,7 +145,7 @@ static void thread1 (void *arg)
|
||||
static void thread2 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot2); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation2(*shared_bigdata_ref(ptr));
|
||||
@@ -145,7 +155,7 @@ static void thread2 (void *arg)
|
||||
static void thread3 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot3); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation3(*shared_bigdata_ref(ptr));
|
||||
@@ -156,7 +166,7 @@ static void thread3 (void *arg)
|
||||
static void thread4 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (continue_threading_g) {
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t3tot4); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation4(*shared_bigdata_ref(ptr));
|
||||
@@ -164,11 +174,12 @@ static void thread4 (void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
initbuf();
|
||||
continue_threading_g = true;
|
||||
atomic_init(&continue_threading_g, true);
|
||||
m_thread_create(t1, thread1, NULL);
|
||||
m_thread_create(t2, thread2, NULL);
|
||||
m_thread_create(t3, thread3, NULL);
|
||||
@@ -184,6 +195,8 @@ static void clear(void)
|
||||
clearbuf();
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "m-core.h"
|
||||
|
||||
// Stubs defined for the example. Real code will use soundio library.
|
||||
struct SoundIo { int x; };
|
||||
struct SoundIoDevice { int x; };
|
||||
struct SoundIoOutStream { int x; };
|
||||
|
||||
static struct SoundIo *soundio_create(void) { return (struct SoundIo *) malloc(sizeof(struct SoundIo)); }
|
||||
static void soundio_destroy(struct SoundIo *s) { free(s); }
|
||||
|
||||
static struct SoundIoDevice *soundio_get_device(struct SoundIo *io, int def) { (void) io; (void) def; return (struct SoundIoDevice *) malloc(sizeof(struct SoundIoDevice)); }
|
||||
static void soundio_device_unref(struct SoundIoDevice *s) { free(s); }
|
||||
|
||||
static struct SoundIoOutStream *soundio_outstream_create(struct SoundIoDevice *device) { (void) device ; return (struct SoundIoOutStream *) malloc(sizeof(struct SoundIoOutStream)); }
|
||||
static void soundio_outstream_destroy(struct SoundIoOutStream *s) { free(s); }
|
||||
|
||||
static bool soundio_wait_events(struct SoundIo *s) { (void) s; return false; }
|
||||
// End of stubs
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err = 1;
|
||||
|
||||
/* Example of using M_LET_IF macro to simplify writing error handling code.
|
||||
The following code creates some object, test if the object creation succeeds, register the destructor, and print an error if something went wrong
|
||||
*/
|
||||
M_LET_IF( struct SoundIo *soundio = soundio_create(), soundio != 0 , soundio_destroy(soundio) , fprintf(stderr, "out of memory for soundio\n") )
|
||||
M_LET_IF(struct SoundIoDevice *device = soundio_get_device(soundio, -1), device != 0, soundio_device_unref(device), fprintf(stderr, "out of memory for device\n"))
|
||||
M_LET_IF(struct SoundIoOutStream *outstream = soundio_outstream_create(device), outstream != 0, soundio_outstream_destroy(outstream), fprintf(stderr, "out of memory for stream\n")) {
|
||||
err = 0;
|
||||
bool cont = true;
|
||||
while (cont)
|
||||
cont = soundio_wait_events(soundio);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a dictionnary of string --> int
|
||||
// named 'str'
|
||||
// named 'dict_str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ int main(void) {
|
||||
char *k = dict_m32_get(h, 10); // No 10 in h, so k == NULL
|
||||
int is_missing = (k != NULL); // true
|
||||
assert (is_missing);
|
||||
dict_m32_remove(h, 5); // h is now empty
|
||||
dict_m32_erase(h, 5); // h is now empty
|
||||
dict_m32_it_t it; // iterate over all dictionnary
|
||||
for (dict_m32_it (it, h) ; !dict_m32_end_p (it); dict_m32_next(it)) {
|
||||
struct dict_m32_pair_s *item = dict_m32_ref(it);
|
||||
@@ -33,7 +33,7 @@ int main(void) {
|
||||
char *k = dict_m32_get(h, 10); // k == NULL
|
||||
int is_missing = (k != NULL); // true
|
||||
assert (is_missing);
|
||||
dict_m32_remove(h, 5); // h is now empty
|
||||
dict_m32_erase(h, 5); // h is now empty
|
||||
for M_EACH(item, h, M32_OPLIST) { // traverse each item
|
||||
item->value = 1; // Set its value to 1
|
||||
}
|
||||
|
||||
+7
-6
@@ -5,8 +5,9 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
DICT_DEF2(dict_map, char, M_DEFAULT_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
|
||||
// Define a dictionary (hashmap) from 'char' to 'int'
|
||||
DICT_DEF2(dict_map, char, int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_map_t mp;
|
||||
@@ -50,11 +51,11 @@ int main(void)
|
||||
printf("Enter the mapped string to be deleted: ");
|
||||
string_fgets (str, stdin, STRING_READ_PURE_LINE);
|
||||
s = atoi(string_get_cstr(str));
|
||||
dict_map_remove(mp, s);
|
||||
dict_map_erase(mp, s);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
printf("Size of Map: %lu\n", (unsigned long) dict_map_size(mp) );
|
||||
printf("Size of Map: %zu\n", dict_map_size(mp) );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
@@ -81,7 +82,7 @@ int main(void)
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
case 6:
|
||||
dict_map_clear(mp);
|
||||
string_clear (str);
|
||||
exit(0);
|
||||
@@ -89,7 +90,7 @@ int main(void)
|
||||
|
||||
default:
|
||||
printf("Wrong Choice\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-5
@@ -5,14 +5,23 @@
|
||||
/* program that reads text from standard-input,
|
||||
and prints the total number of distinct words found in the text.
|
||||
*/
|
||||
DICT_SET_DEF2(dict_str, string_t, STRING_OPLIST)
|
||||
|
||||
/* Definition of a set (hashset) of unique string_t */
|
||||
DICT_SET_DEF(dict_str, string_t, STRING_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define word as a string_t
|
||||
M_LET(word, STRING_OPLIST)
|
||||
M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) {
|
||||
while (string_fget_word(word, " \t\n,.!;:?", stdin))
|
||||
dict_str_set_at(wordcount, word);
|
||||
printf ("Words: %lu\n", dict_str_size(wordcount));
|
||||
// Define wordcount as a set of string_t
|
||||
M_LET(wordcount, DICT_SET_OPLIST(dict_str, STRING_OPLIST)) {
|
||||
// Read a word from the standard input
|
||||
while (string_fget_word(word, " \t\n,.!;:?", stdin)) {
|
||||
// Push this word in the set.
|
||||
// Do nothing if it already exists.
|
||||
dict_str_push(wordcount, word);
|
||||
}
|
||||
// Print the number of words of the standard input.
|
||||
printf ("Words: %zu\n", dict_str_size(wordcount));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include "m-string.h"
|
||||
#include "m-array.h"
|
||||
#include "m-dict.h"
|
||||
|
||||
// Define an array of size_t
|
||||
ARRAY_DEF(array_size, size_t)
|
||||
// Register the oplist of this array globaly
|
||||
#define M_OPL_array_size_t() ARRAY_OPLIST(array_size)
|
||||
|
||||
// Define a dictionary (hashmap) of string_t to array of size_t
|
||||
DICT_DEF2(map_pos, string_t, array_size_t)
|
||||
// Register the oplist of this dictionary (hashmap)
|
||||
#define M_OPL_map_pos_t() DICT_OPLIST(map_pos, STRING_OPLIST, ARRAY_OPLIST(array_size))
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
printf("USAGE: %s filename\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Define word as a string_t
|
||||
M_LET(word, string_t)
|
||||
// Define positions as a map of string_t-->array of size_t
|
||||
M_LET(positions, map_pos_t) {
|
||||
// Open the file
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s.\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// While it reads some word from the file
|
||||
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
|
||||
// Get the reference to the array of this word in the dictionnary (or create it if needed)
|
||||
array_size_t *array = map_pos_safe_get(positions, word);
|
||||
// Push the new offset to this word in the associated array
|
||||
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
|
||||
}
|
||||
|
||||
// Close the file
|
||||
fclose(f);
|
||||
|
||||
// Print the words and where they are:
|
||||
for M_EACH(pair, positions, map_pos_t) {
|
||||
string_fputs(stdout, pair->key);
|
||||
for M_EACH(pos, pair->value, array_size_t) {
|
||||
printf(" %zu", *pos);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
} // All created objects are destroyed beyond this point
|
||||
|
||||
return 0;
|
||||
}
|
||||
+1
-1
@@ -38,7 +38,7 @@ int main(void)
|
||||
list_string_get_str (tmpstr, grow, false);
|
||||
|
||||
// print out
|
||||
printf("Number of elements = %lu\n", (unsigned long) list_string_size(grow));
|
||||
printf("Number of elements = %zu\n", list_string_size(grow));
|
||||
printf("Final string = %s\n", string_get_cstr(tmpstr));
|
||||
|
||||
// Let's iterate over each element of the list
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
/* Based on:
|
||||
* Easy Perfect Minimal Hashing
|
||||
* By Steve Hanov. Released to the public domain.
|
||||
* http://stevehanov.ca/blog/index.php?id=119
|
||||
*
|
||||
* Based on:
|
||||
* Edward A. Fox, Lenwood S. Heath, Qi Fan Chen and Amjad M. Daoud,
|
||||
* "Practical minimal perfect hash functions for large databases", CACM, 35(1):105-121
|
||||
*
|
||||
* also a good reference:
|
||||
* Compress, Hash, and Displace algorithm by Djamal Belazzougui,
|
||||
* Fabiano C. Botelho, and Martin Dietzfelbinger
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Define the needed data structure : */
|
||||
|
||||
// Define a dictionnary of constant string --> integer and register it.
|
||||
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
// Define an array of integer to store the value and register it.
|
||||
ARRAY_DEF(array_value, uint32_t) // Start from 1. 0 is 'None'
|
||||
#define M_OPL_array_value_t() ARRAY_OPLIST(array_value)
|
||||
|
||||
// Define an array of integer to store the seed and register it.
|
||||
ARRAY_DEF(array_seed, int32_t)
|
||||
#define M_OPL_array_seed_t() ARRAY_OPLIST(array_seed)
|
||||
// Define algorithms on array_seed
|
||||
ALGO_DEF(array_seed, array_seed_t)
|
||||
|
||||
// Define an array of constant string that are ordered by their size.
|
||||
ARRAY_DEF(array_cstr, const char *, M_CSTR_OPLIST)
|
||||
// Register it globally but with a custom CMP operator
|
||||
static inline int array_cstr_cmp(const array_cstr_t a, const array_cstr_t b) {
|
||||
// We compare only the size
|
||||
size_t sa = array_cstr_size(a);
|
||||
size_t sb = array_cstr_size(b);
|
||||
return (sa > sb) ? -1 : (sa < sb);
|
||||
}
|
||||
#define M_OPL_array_cstr_t() M_OPEXTEND(ARRAY_OPLIST(array_cstr, M_CSTR_OPLIST), CMP(array_cstr_cmp))
|
||||
|
||||
// Define an array of array of constant string, and some algo over this container
|
||||
ARRAY_DEF(array_bucket, array_cstr_t)
|
||||
#define M_OPL_array_bucket_t() ARRAY_OPLIST(array_bucket, M_OPL_array_cstr_t() )
|
||||
ALGO_DEF(array_bucket, array_bucket_t)
|
||||
|
||||
// Define an array of string to save the input.
|
||||
ARRAY_DEF(array_string, string_t)
|
||||
#define M_OPL_array_string_t() ARRAY_OPLIST(array_string, M_OPL_string_t())
|
||||
|
||||
|
||||
|
||||
|
||||
/* The algorithm may not converge on all inputs if the hash function
|
||||
* doesn't randomly distribute the inputs:
|
||||
* str1 != str2 ==> \exist seed \such_as hash(seed,str1) != hash(seed, str2)
|
||||
* The first hash function below doesn't provide the needed property for
|
||||
* inputs with two words 'a' and 'c'
|
||||
* The second one is more robust but may still have this issue.
|
||||
*/
|
||||
static uint32_t hash(int32_t seed, const char str[])
|
||||
{
|
||||
#if 0
|
||||
if (seed == 0) seed = 0x01000193;
|
||||
while (*str) {
|
||||
seed = ((seed * 0x01000193) ^ *str);
|
||||
str++;
|
||||
}
|
||||
return seed;
|
||||
#else
|
||||
if (seed == 0) seed = 0x811C9DC5;
|
||||
while (*str) {
|
||||
seed = (seed ^ *str) * 16777619;
|
||||
str++;
|
||||
}
|
||||
return seed ^ (seed >> 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Step 1: place all key keys into buckets
|
||||
static void
|
||||
CreateMinimalPerfectHash1(array_seed_t seed, array_value_t value,
|
||||
array_bucket_t bucket,
|
||||
const dict_mph_t dict)
|
||||
{
|
||||
size_t size = dict_mph_size (dict);
|
||||
|
||||
array_value_resize(value, size);
|
||||
array_seed_resize(seed, size);
|
||||
array_bucket_resize(bucket, size);
|
||||
|
||||
for M_EACH(item, dict, dict_mph_t) {
|
||||
size_t i = hash(0, item->key) % size;
|
||||
array_cstr_push_back (*array_bucket_get (bucket, i), item->key);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Sort the buckets and process the ones with the most items first.
|
||||
static void
|
||||
CreateMinimalPerfectHash2(array_seed_t seed, array_value_t value,
|
||||
array_bucket_t bucket,
|
||||
const dict_mph_t dict)
|
||||
{
|
||||
size_t size = dict_mph_size (dict);
|
||||
array_bucket_sort(bucket);
|
||||
M_LET(slots, array_seed_t) {
|
||||
for M_EACH(b, bucket, array_bucket_t) {
|
||||
if (array_cstr_size(*b) <= 1)
|
||||
break;
|
||||
size_t d = 1;
|
||||
/* Repeatedly try different values of d until we find a hash function
|
||||
that places all items in the bucket into free slots.
|
||||
This may loop forever on some inputs if the hash function is not good
|
||||
enought. */
|
||||
for(bool cont = true; cont ; ) {
|
||||
cont = false;
|
||||
array_seed_reset(slots);
|
||||
for M_EACH(it, *b, array_cstr_t) {
|
||||
size_t s = hash(d, *it) % size;
|
||||
if (*array_value_get(value, s) != 0 || array_seed_contain_p(slots, s)){
|
||||
d++;
|
||||
cont = true;
|
||||
break;
|
||||
}
|
||||
array_seed_push_back (slots, s);
|
||||
}
|
||||
}
|
||||
// Fill in the seed & value with the computed value
|
||||
array_seed_set_at(seed, hash(0, *array_cstr_get(*b, 0)) % size, d);
|
||||
d = 0;
|
||||
for M_EACH(it, *b, array_cstr_t) {
|
||||
array_value_set_at(value,
|
||||
*array_seed_get(slots, d),
|
||||
*dict_mph_get(dict, *it));
|
||||
d++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 3:
|
||||
* Only buckets with 1 item remain. Process them more quickly by directly
|
||||
* placing them into a free slot. Use a negative value of d to indicate
|
||||
* this.
|
||||
*/
|
||||
static void
|
||||
CreateMinimalPerfectHash3(array_seed_t seed, array_value_t value,
|
||||
array_bucket_t bucket,
|
||||
const dict_mph_t dict)
|
||||
{
|
||||
size_t size = dict_mph_size (dict);
|
||||
|
||||
M_LET(freelist, array_seed_t) {
|
||||
// Get a list of available slot
|
||||
for(size_t i = 0; i < size; i++)
|
||||
if (*array_value_get(value, i) == 0)
|
||||
array_seed_push_back(freelist, i);
|
||||
for M_EACH(b, bucket, array_bucket_t) {
|
||||
if (array_cstr_size(*b) != 1)
|
||||
continue;
|
||||
int32_t slot;
|
||||
array_seed_pop_back(&slot, freelist);
|
||||
/*We subtract one to ensure it's negative even if the zeroeth slot was
|
||||
used. */
|
||||
array_seed_set_at (seed, hash(0, *array_cstr_get(*b, 0)) % size,
|
||||
-slot-1);
|
||||
array_value_set_at(value, slot, *dict_mph_get(dict, *array_cstr_get(*b, 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CreateMinimalPerfectHash(array_seed_t seed, array_value_t value,
|
||||
const dict_mph_t dict)
|
||||
{
|
||||
M_LET(bucket, array_bucket_t) {
|
||||
CreateMinimalPerfectHash1(seed, value, bucket, dict);
|
||||
CreateMinimalPerfectHash2(seed, value, bucket, dict);
|
||||
CreateMinimalPerfectHash3(seed, value, bucket, dict);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dict_read_from_file(dict_mph_t dict, array_string_t arr, const char filename[])
|
||||
{
|
||||
FILE *f = fopen(filename, "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
uint32_t line = 1;
|
||||
M_LET(str, string_t) {
|
||||
while (!feof(f) && !ferror(f)) {
|
||||
string_fgets(str, f, STRING_READ_PURE_LINE);
|
||||
string_strim(str);
|
||||
if (!string_empty_p(str)) {
|
||||
// Not clean as items of 'dict' points are linked to items of 'arr'
|
||||
// and the containers are not aware of this link.
|
||||
array_string_push_back (arr, str);
|
||||
dict_mph_set_at(dict, string_get_cstr(*array_string_back(arr)), line);
|
||||
line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
perfect_hash_lockup(array_seed_t seed, array_value_t value,
|
||||
const char key[])
|
||||
{
|
||||
int32_t s = *array_seed_get(seed, hash(0, key) % array_seed_size(seed));
|
||||
if (s < 0)
|
||||
return *array_value_get(value, -s-1);
|
||||
else
|
||||
return *array_value_get(value, hash(s, key) % array_value_size(value));
|
||||
}
|
||||
|
||||
static void
|
||||
test(array_seed_t seed, array_value_t value, dict_mph_t dict)
|
||||
{
|
||||
for M_EACH(item, dict, dict_mph_t) {
|
||||
const char *key = item->key;
|
||||
uint32_t v = perfect_hash_lockup(seed, value, key);
|
||||
if (v != item->value) {
|
||||
fprintf(stderr, "ERROR for %s: %u VS %u\n", key, v, item->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
// Create arr as array_string_t, dict as dist_mph_t and seed as array_seed_t
|
||||
M_LET(arr, array_string_t) M_LET(dict, dict_mph_t) M_LET(seed, array_seed_t)
|
||||
// and value as array_value_t
|
||||
M_LET(value, array_value_t) {
|
||||
const char *filename = (argc > 1) ? argv[1] :"/usr/share/dict/words";
|
||||
dict_read_from_file(dict, arr, filename);
|
||||
CreateMinimalPerfectHash(seed, value, dict);
|
||||
test(seed, value, dict);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define an array of integer
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
typedef struct {
|
||||
@@ -25,7 +26,7 @@ static void tape_devance(tape_t tape) { if (tape->pos > 0) tape->pos--; }
|
||||
|
||||
typedef struct {
|
||||
string_t code;
|
||||
array_int_t bracket_map; // Should use map when possible.
|
||||
array_int_t bracket_map;
|
||||
} program_t[1];
|
||||
|
||||
static void program_init(program_t p, string_t text) {
|
||||
@@ -47,8 +48,8 @@ static void program_init(program_t p, string_t text) {
|
||||
int left;
|
||||
array_int_pop_back(&left, leftstack);
|
||||
int right = pc;
|
||||
array_int_set_at2 (p->bracket_map, left, right);
|
||||
array_int_set_at2 (p->bracket_map, right, left);
|
||||
*array_int_safe_get (p->bracket_map, left) = right;
|
||||
*array_int_safe_get (p->bracket_map, right) = left;
|
||||
}
|
||||
|
||||
pc++;
|
||||
@@ -98,7 +99,11 @@ static void program_run(program_t p){
|
||||
|
||||
static void read_file(string_t str, const string_t filename) {
|
||||
FILE *f = fopen(string_get_cstr(filename), "rt");
|
||||
if (!f) abort();
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s\n", string_get_cstr(filename));
|
||||
exit(2);
|
||||
}
|
||||
// Read the full FILE in the string
|
||||
string_fgets (str, f, STRING_READ_FILE);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#if HAVE_GMP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
@@ -50,14 +52,19 @@ int main(void)
|
||||
// Dictionary iterator are pair (key,value)
|
||||
if (my_integer_n_p(p->value)) {
|
||||
printf ("It is a long long, value = %lld\n",
|
||||
*my_integer_get_n(p->value));
|
||||
*my_integer_cget_n(p->value));
|
||||
}
|
||||
if (my_integer_z_p(p->value)) {
|
||||
printf ("It is a mpz_t, value =");
|
||||
mpz_out_str(stdout, 10, *my_integer_get_z(p->value));
|
||||
mpz_out_str(stdout, 10, *my_integer_cget_z(p->value));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* All variables are automatically cleared beyond this point */
|
||||
}
|
||||
|
||||
#else
|
||||
// Nothing to do
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -4,7 +4,7 @@
|
||||
/* Register a dynamic seed to M*LIB hash function.
|
||||
This shall be done before any M*LIB header inclusion. */
|
||||
unsigned long long rand_seed;
|
||||
#define M_HASH_SEED rand_seed
|
||||
#define M_USE_HASH_SEED rand_seed
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-dict.h"
|
||||
@@ -12,7 +12,9 @@ unsigned long long rand_seed;
|
||||
#include "m-variant.h"
|
||||
|
||||
/* This example will show how to create JSON-like files.
|
||||
This is a JSON **like** syntax, not exactly JSON format */
|
||||
This is a JSON **like** syntax, not exactly JSON format.
|
||||
For an example with JSON format, see https://github.com/P-p-H-d/mjsonlib
|
||||
*/
|
||||
|
||||
/* First let's handle the OUT/IN functions of boolean */
|
||||
static inline void boolean_out_str(FILE *f, bool b)
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "m-list.h"
|
||||
#include "m-buffer.h"
|
||||
|
||||
/* This example chains the structure in different ways in
|
||||
order to show/test the good chaining of the structures */
|
||||
|
||||
TUPLE_DEF2(symbol, (type, int), (name, string_t))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
|
||||
ARRAY_DEF(symbol_list, symbol_t)
|
||||
#define M_OPL_symbol_list_t() ARRAY_OPLIST(symbol_list, M_OPL_symbol_t())
|
||||
|
||||
TUPLE_DEF2(record, (fields, symbol_list_t))
|
||||
#define M_OPL_record_t() TUPLE_OPLIST(record, M_OPL_symbol_list_t())
|
||||
|
||||
TUPLE_DEF2(my_tuple, (name, string_t), (value, int))
|
||||
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple)
|
||||
|
||||
ARRAY_DEF(my_list_of_tuple, my_tuple_t)
|
||||
#define M_OPL_my_list_of_tuple_t() ARRAY_OPLIST(my_list_of_tuple)
|
||||
|
||||
TUPLE_DEF2(my_tuple_of_tuple, (name, string_t), (inner_tuple, my_tuple_t))
|
||||
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple)
|
||||
|
||||
LIST_DEF(list_of_tuple_of_tuple, my_tuple_of_tuple_t)
|
||||
#define M_OPL_list_of_tuple_of_tuple_t() LIST_OPLIST(list_of_tuple_of_tuple, M_OPL_my_tuple_of_tuple_t() )
|
||||
|
||||
TUPLE_DEF2(my_triple_tuple, (name, string_t), (inner_tuple, my_tuple_t), (list, list_of_tuple_of_tuple_t) )
|
||||
#define M_OPL_my_triple_tuple_t() TUPLE_OPLIST(my_triple_tuple, STRING_OPLIST, M_OPL_my_tuple_t(), M_OPL_list_of_tuple_of_tuple_t())
|
||||
|
||||
BUFFER_DEF(trbuff, my_triple_tuple_t, 100, BUFFER_QUEUE)
|
||||
#define M_OPL_trbuff_t() BUFFER_OPLIST(trbuff, M_OPL_my_triple_tuple_t())
|
||||
|
||||
TUPLE_DEF2(my_junction, (active, bool), (buffer, trbuff_t))
|
||||
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_DEFAULT_OPLIST, M_OPL_trbuff_t())
|
||||
|
||||
TUPLE_DEF2(mlib_point, (x, int), (y, int))
|
||||
#define M_OPL_mlib_point_t() \
|
||||
TUPLE_OPLIST(mlib_point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
(second_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
(third, mlib_point_t))
|
||||
#define M_OPL_mlib_points_t() \
|
||||
TUPLE_OPLIST(mlib_points, M_PTR_OPLIST, M_PTR_OPLIST, M_OPL_mlib_point_t())
|
||||
|
||||
static void let2(void)
|
||||
{
|
||||
// Initialize p1 as mlib_point_t with (4,4)
|
||||
// and p2 as mlib_point_t with (5,5)
|
||||
// and pair as mlib_point_t with default value
|
||||
M_LET((p1, 4, 4), (p2, 5, 5), mlib_point_t) {
|
||||
M_LET(pair, mlib_points_t) {
|
||||
pair->first_ref = p1;
|
||||
pair->second_ref = p2;
|
||||
pair->third->x = pair->third->y = 6;
|
||||
|
||||
assert(pair->first_ref->x == 4);
|
||||
p1->x = 10;
|
||||
assert(pair->first_ref->x == 10);
|
||||
|
||||
assert(pair->third->x == 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void let(void)
|
||||
{
|
||||
// Let's initialize all the declared types
|
||||
M_LET(s, symbol_t)
|
||||
M_LET(l, symbol_list_t)
|
||||
M_LET(r,record_t)
|
||||
M_LET(tup, my_tuple_t)
|
||||
M_LET(l2, my_list_of_tuple_t)
|
||||
M_LET(tuptup, my_tuple_of_tuple_t)
|
||||
M_LET(ltuptup, list_of_tuple_of_tuple_t)
|
||||
M_LET(tuptuptup, my_triple_tuple_t)
|
||||
M_LET(junc, my_junction_t)
|
||||
{
|
||||
printf("Init ok\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
let();
|
||||
let2();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's create an array of string_t and register it globaly
|
||||
ARRAY_DEF(vector_string, string_t)
|
||||
#define M_OPL_vector_string_t() ARRAY_OPLIST(vector_string, STRING_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's define a new string named str
|
||||
M_LET(str, string_t)
|
||||
// Let's define msg as a vector_array_t
|
||||
M_LET( (msg, STRING_CTE("Hello"), STRING_CTE("C"), STRING_CTE("World!"), STRING_CTE("Let's"), STRING_CTE("discover"), STRING_CTE("M*LIB!")), vector_string_t) {
|
||||
// Iterate over all words of the array msg
|
||||
for M_EACH(word, msg, vector_string_t) {
|
||||
// Cat the current word into the target string
|
||||
string_cat(str, *word);
|
||||
// Also add a space character
|
||||
string_push_back(str, ' ');
|
||||
}
|
||||
// Let's define another string and set it to a formatted value.
|
||||
M_LET( (count, "\nTo display this it uses \"vector\" of %zu strings!", vector_string_size(msg)), string_t) {
|
||||
string_cat(str, count);
|
||||
}
|
||||
// Print the result
|
||||
printf("%s\n", string_get_cstr(str) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+10
-8
@@ -4,6 +4,15 @@
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
// Let's define one utility function.
|
||||
void *xmalloc(size_t n);
|
||||
void *xmalloc(size_t n)
|
||||
{
|
||||
void *p = malloc (n);
|
||||
if (!p) abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
// Let's define a new type.
|
||||
typedef struct {
|
||||
int key;
|
||||
@@ -12,7 +21,7 @@ typedef struct {
|
||||
|
||||
#define SIZE 256
|
||||
|
||||
void *xmalloc(size_t n);
|
||||
// Let's define the prototypes of the methods of this new type.
|
||||
void my_type_init(my_type_t x);
|
||||
void my_type_clear(my_type_t x);
|
||||
void my_type_init_set(my_type_t x, const my_type_t y);
|
||||
@@ -24,13 +33,6 @@ void my_type_out_str(FILE *f, const my_type_t x);
|
||||
bool my_type_in_str(my_type_t x, FILE *f);
|
||||
void my_type_rand(my_type_t x);
|
||||
|
||||
void *xmalloc(size_t n)
|
||||
{
|
||||
void *p = malloc (n);
|
||||
if (!p) abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
// Let's define its constructor
|
||||
void my_type_init(my_type_t x)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "m-string.h"
|
||||
|
||||
#define MAX_COLUMN 80
|
||||
|
||||
static void format(FILE *f)
|
||||
{
|
||||
string_t s;
|
||||
string_init(s);
|
||||
while (string_fgets(s, f, STRING_READ_PURE_LINE) == true)
|
||||
{
|
||||
size_t n = string_size(s);
|
||||
if (n > 0 && string_get_char(s, n-1) == '\\' && n < MAX_COLUMN) {
|
||||
string_left(s, n-1);
|
||||
while (n < MAX_COLUMN-1) {
|
||||
string_push_back(s, ' ');
|
||||
n++;
|
||||
}
|
||||
string_push_back(s, '\\');
|
||||
}
|
||||
if (n >= MAX_COLUMN && string_get_char(s, n-1) == '\\') {
|
||||
n--;
|
||||
string_left(s, n);
|
||||
while (n >= MAX_COLUMN-2 && string_get_char(s, n-1) == ' ') {
|
||||
n--;
|
||||
string_left(s, n);
|
||||
}
|
||||
string_push_back(s, ' ');
|
||||
string_push_back(s, '\\');
|
||||
}
|
||||
printf("%s\n", string_get_cstr(s));
|
||||
}
|
||||
string_clear(s);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Missing argument filename.\nUSAGE: %s filename.h\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open filename '%s' .h\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
format(f);
|
||||
fclose(f);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define an array of string_t. Since the oplist of string_t is registered globaly
|
||||
// there is no need to give it to this definition.
|
||||
ARRAY_DEF(str_array, string_t)
|
||||
|
||||
// First the verbose way and (nearly) macro free:
|
||||
static void main_macrofree(void)
|
||||
{
|
||||
str_array_t tab_name;
|
||||
str_array_init(tab_name);
|
||||
|
||||
// Push some elements in the array (long way)
|
||||
str_array_push_back(tab_name, STRING_CTE("My"));
|
||||
str_array_push_back(tab_name, STRING_CTE("CD"));
|
||||
str_array_push_back(tab_name, STRING_CTE("IS"));
|
||||
str_array_push_back(tab_name, STRING_CTE("OUT"));
|
||||
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Finaly rewrite 1 element of the array
|
||||
string_set_str(*str_array_get(tab_name, 1), "BLU-RAY");
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
string_t format;
|
||||
string_init_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name));
|
||||
string_replace_all_str(format, "capacty", "capacity");
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2)));
|
||||
str_array_push_back(tab_name, format);
|
||||
string_clear(format);
|
||||
|
||||
// Display the content of the array.
|
||||
str_array_it_t it;
|
||||
int i = 0;
|
||||
for (str_array_it(it, tab_name) ; !str_array_end_p(it); str_array_next(it)) {
|
||||
printf("item[%d] = '%s'\n", i, string_get_cstr(*str_array_cref(it)) );
|
||||
i++;
|
||||
}
|
||||
|
||||
// Clear the array
|
||||
str_array_clear(tab_name);
|
||||
}
|
||||
|
||||
// Then the short version with macros.
|
||||
// For this we need to register the oplist of the array of string globally.
|
||||
#define M_OPL_str_array_t() ARRAY_OPLIST(str_array, STRING_OPLIST)
|
||||
|
||||
static void main_macro(void)
|
||||
{
|
||||
// Define and fill an array of string with some elements in it:
|
||||
M_LET( (tab_name, STRING_CTE("My"), STRING_CTE("CD"), STRING_CTE("IS"), STRING_CTE("OUT")), str_array_t) {
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Finaly rewrite 1 element of the array
|
||||
string_set_str(*str_array_get(tab_name, 1), "BLU-RAY");
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
M_LET(format, string_t) {
|
||||
string_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "There is a capacty of %d", str_array_capacity(tab_name));
|
||||
string_replace_all_str(format, "capacty", "capacity");
|
||||
str_array_push_back(tab_name, format);
|
||||
string_printf(format, "The third element is '%s'", string_get_cstr(*str_array_get(tab_name, 2)));
|
||||
str_array_push_back(tab_name, format);
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
// Set format to a formated string
|
||||
// In C11, we can mix string_t and char *.
|
||||
// We can also use M_CSTR to create a printf formated string.
|
||||
string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%zu.txt", str_array_size(tab_name) ));
|
||||
str_array_push_back(tab_name, format);
|
||||
#endif
|
||||
} // beyond this point format is cleared
|
||||
|
||||
// Display the content of the array.
|
||||
int i = 0;
|
||||
for M_EACH(item, tab_name, str_array_t) {
|
||||
printf("item[%d] = '%s'\n", i, string_get_cstr(*item) );
|
||||
i++;
|
||||
}
|
||||
} // beyond this point tab_name is cleared
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("Version macrofree:\n");
|
||||
main_macrofree();
|
||||
printf("Version macro:\n");
|
||||
main_macro();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include "m-string.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Definition of an associative map string_t --> size_t */
|
||||
DICT_DEF2(dict_str, string_t, size_t)
|
||||
#define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Definition of an array of string_t */
|
||||
ARRAY_DEF(vector_str, string_t)
|
||||
#define M_OPL_vector_str_t() ARRAY_OPLIST(vector_str, STRING_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Construct an array of string, performing a convertion of the C const char *
|
||||
// into a proper string_t at real time and push then into a dynamic array
|
||||
// that is declared, initialized and cleared.
|
||||
M_LET( (words, ("This"), ("is"), ("a"), ("useless"), ("sentence"), ("."),
|
||||
("It"), ("is"), ("used"), ("a"), ("bit"), ("to"), ("count"), ("words"), (".") ),
|
||||
vector_str_t) {
|
||||
// Print the arrays.
|
||||
printf("The words are: ");
|
||||
vector_str_out_str(stdout, words);
|
||||
printf("\n");
|
||||
|
||||
// Count the words.
|
||||
M_LET(map, dict_str_t) {
|
||||
// Count the words:
|
||||
for M_EACH(w, words, vector_str_t) {
|
||||
(*dict_str_safe_get(map, *w)) ++;
|
||||
}
|
||||
|
||||
// Print the count:
|
||||
for M_EACH(p, map, dict_str_t) {
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
M_PRINT(p->value, " occurences of ", p->key, "\n");
|
||||
#else
|
||||
printf ("%zu occurences of %s\n", p->value, string_get_cstr(p->key));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Based on https://en.cppreference.com/w/cpp/algorithm/for_each
|
||||
Need to be built in C11 mode */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
/* Define a dynamic array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
/* Define operator increment on int */
|
||||
#define INC(n) (n)++
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET( (nums, 3, 4, 2, 8, 15, 267), vector_int_t) {
|
||||
// Print the array before
|
||||
printf ("before:");
|
||||
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
|
||||
printf ("\n");
|
||||
|
||||
// Increment each element of the array
|
||||
ALGO_FOR_EACH(nums, vector_int_t, INC);
|
||||
|
||||
// Print the array after
|
||||
printf ("after: ");
|
||||
ALGO_FOR_EACH(nums, vector_int_t, M_PRINT, " ");
|
||||
printf ("\n");
|
||||
|
||||
// Sum the elements of the array
|
||||
int sum = 0;
|
||||
ALGO_REDUCE(sum, nums, vector_int_t, add);
|
||||
M_PRINT("sum = ", sum, "\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-funcobj.h"
|
||||
#include "m-serial-json.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define the employee class */
|
||||
TUPLE_DEF2(employee,
|
||||
(name, string_t),
|
||||
(age, int),
|
||||
(idnum, int))
|
||||
/* Register globaly the employee_t oplist */
|
||||
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
/* Define an array of employee, register the oplist and define further algorithms on it */
|
||||
ARRAY_DEF(vector_employee, employee_t)
|
||||
#define M_OPL_vector_employee_t() ARRAY_OPLIST(vector_employee, M_OPL_employee_t())
|
||||
ALGO_DEF(vector_employee, vector_employee_t)
|
||||
|
||||
/* Define the function object to select the sort order.
|
||||
* It is named 'compare_by' and is an instance of the interface
|
||||
* 'vector_employee_cmp_obj' created by ALGO_DEF.
|
||||
*/
|
||||
FUNC_OBJ_INS_DEF(compare_by /* name of the instance */,
|
||||
vector_employee_cmp_obj /* name of the interface */,
|
||||
(a, b) /* name of the input parameters of the function like object. The type are inherited from the interface. */, {
|
||||
/* code of the function object */
|
||||
if (string_equal_str_p(self->sort_field, "name"))
|
||||
return string_cmp(a->name, b->name);
|
||||
else if (string_equal_str_p(self->sort_field, "age"))
|
||||
return a->age < b->age ? -1 : a->age > b->age;
|
||||
else
|
||||
return a->idnum < b->idnum ? -1 : a->idnum > b->idnum;
|
||||
},
|
||||
/* Additional fields stored in the function object */
|
||||
(sort_field, string_t) )
|
||||
#define M_OPL_compare_by_t() FUNC_OBJ_INS_OPLIST(compare_by, STRING_OPLIST)
|
||||
|
||||
// Let's read an array of person from the given JSON file
|
||||
static void read(vector_employee_t base, const char filename[])
|
||||
{
|
||||
m_serial_return_code_t ret;
|
||||
|
||||
// Open the file
|
||||
FILE *f = fopen(filename, "rt");
|
||||
if (!f) {
|
||||
// Handle errors
|
||||
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Initialize the JSON serializer with this file
|
||||
M_LET( (in,f), m_serial_json_read_t)
|
||||
// Read the JSON file and fill in 'base' with it.
|
||||
ret = vector_employee_in_serial(base, in);
|
||||
|
||||
// Let's handle serialization error
|
||||
if (ret != M_SERIAL_OK_DONE) {
|
||||
fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\nParsing stops at:\n", filename);
|
||||
while (!feof(f)) { fputc(fgetc(f), stdout); }
|
||||
fclose(f);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Close the FILE
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(emps, vector_employee_t) {
|
||||
/* Code to populate database from JSON */
|
||||
read(emps, "ex11-algo02.json");
|
||||
|
||||
// Sort the database by employee ID number
|
||||
M_LET( (cmp, STRING_CTE("idnum")), compare_by_t )
|
||||
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
|
||||
M_PRINT("Employees sorted by idnum are: ", (emps, vector_employee_t), "\n" );
|
||||
|
||||
// Sort the database by employee name
|
||||
M_LET( (cmp, STRING_CTE("name")), compare_by_t )
|
||||
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
|
||||
M_PRINT("Employees sorted by name are: ", (emps, vector_employee_t), "\n" );
|
||||
|
||||
// End
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{ "name": "John Doe", "age": 32, "idnum": 14528},
|
||||
{ "name": "Clint Smith", "age": 31, "idnum": 14529},
|
||||
{ "name": "Linda Cameron", "age": 20, "idnum": 14527},
|
||||
{ "name": "Cameron Carrey", "age": 25, "idnum": 14526},
|
||||
{ "name": "Marty Brown", "age": 26, "idnum": 14525},
|
||||
{ "name": "Donald Cow", "age": 45, "idnum": 14520}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "m-serial-json.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
|
||||
// Let's define a 'person' composed of several fields.
|
||||
TUPLE_DEF2(person,
|
||||
(surname, string_t),
|
||||
(age, int),
|
||||
(present, bool)
|
||||
)
|
||||
// Register the oplist of this tuple globaly
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST, M_DEFAULT_OPLIST )
|
||||
|
||||
// Let's define an array of person
|
||||
ARRAY_DEF(base, person_t)
|
||||
// Register the oplist of this array globaly
|
||||
#define M_OPL_base_t() ARRAY_OPLIST(base, M_OPL_person_t())
|
||||
|
||||
// Let's read an array of person from the given JSON file
|
||||
static void read(base_t base, const char filename[])
|
||||
{
|
||||
m_serial_read_t in;
|
||||
m_serial_return_code_t ret;
|
||||
|
||||
// Open the file
|
||||
FILE *f = fopen(filename, "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Initialize the serializer with the file
|
||||
m_serial_json_read_init(in, f);
|
||||
// Read the array
|
||||
ret = base_in_serial(base, in);
|
||||
if (ret != M_SERIAL_OK_DONE) {
|
||||
fprintf(stderr, "ERROR: Cannot read JSON data from file '%s'.\n", filename);
|
||||
exit(2);
|
||||
}
|
||||
// Let's close & clear all
|
||||
m_serial_json_read_clear(in);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's have base as a base_t
|
||||
M_LET(base, base_t) {
|
||||
// Read the JSON file and fill-in base
|
||||
read(base, "ex11-json01.json");
|
||||
// Print the contents of base:
|
||||
printf ("List of presents:\n");
|
||||
for M_EACH(el, base, base_t) {
|
||||
if ((*el)->present) {
|
||||
printf("%s\n", string_get_cstr((*el)->surname));
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{ "surname": "Angel", "age": 1, "present": false},
|
||||
{ "surname": "Snake", "age": 2, "present": true},
|
||||
{ "surname": "BallOfBase", "age": 5, "present": true}
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's define a tuple composed of (offset, value) and register it
|
||||
TUPLE_DEF2(symbol, (offset, long), (value, long))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
// Let's define an array of such tuple and register it
|
||||
ARRAY_DEF(array_symbol, symbol_t)
|
||||
#define M_OPL_array_symbol_t() ARRAY_OPLIST(array_symbol, M_OPL_symbol_t())
|
||||
|
||||
// Let's define a dictionnary associating a string_t to such an array and register it
|
||||
DICT_DEF2(sections, string_t, array_symbol_t)
|
||||
#define M_OPL_sections_t() DICT_OPLIST(sections, STRING_OPLIST, M_OPL_array_symbol_t())
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc < 2) abort();
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s\n", argv[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Create & initialize sc as sections_t
|
||||
M_LET(sc, sections_t) {
|
||||
// Read the section from the FILE
|
||||
sections_in_str(sc, f);
|
||||
// Get the section named .text
|
||||
array_symbol_t *a = sections_get(sc, STRING_CTE(".text"));
|
||||
if (a == NULL) {
|
||||
printf("There is no .text section.");
|
||||
} else {
|
||||
// Print its content
|
||||
printf("Section .text is :");
|
||||
array_symbol_out_str(stdout, *a);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Based on the example of STC https://github.com/tylov/STC */
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-tuple.h"
|
||||
|
||||
// NOTE: After each definition of a container, we register its oplist
|
||||
// It is not mandatory, but it makes the code easier to write and read.
|
||||
|
||||
// Define a basic structure (POD structure) using a tuple to get the default functions
|
||||
TUPLE_DEF2(Point, (x, float), (y, float))
|
||||
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
// NOTE: array, list, deque don't have a native find function.
|
||||
// We'll use the algorithm header to create a find function for such containers.
|
||||
|
||||
// Define a set of int & register its oplist
|
||||
DICT_SET_DEF(cset_i, int)
|
||||
#define M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_DEFAULT_OPLIST)
|
||||
|
||||
// Define an array of Point, register its oplist & include some basic algorithms
|
||||
ARRAY_DEF(cvec_p, Point_t)
|
||||
#define M_OPL_cvec_p_t() ARRAY_OPLIST(cvec_p, M_OPL_Point_t())
|
||||
ALGO_DEF(cvec_p, cvec_p_t)
|
||||
|
||||
// Define a deque of int, including some basic algorithms
|
||||
DEQUE_DEF(cdeq_i, int)
|
||||
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_DEFAULT_OPLIST)
|
||||
ALGO_DEF(cdeq_i, cdeq_i_t)
|
||||
|
||||
// Define a backward list, including some basic algorithms
|
||||
LIST_DEF(clist_i, int)
|
||||
#define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_DEFAULT_OPLIST)
|
||||
ALGO_DEF(clist_i, clist_i_t)
|
||||
|
||||
// Define an unordered map of int to int
|
||||
DICT_DEF2(csmap_i, int, int)
|
||||
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define, init & set the different containers.
|
||||
M_LET( (set, 10, 20, 30), cset_i_t)
|
||||
M_LET( (vec, (10, 1), (20, 2), (30, 3) ), cvec_p_t)
|
||||
M_LET( (deq, 10, 20, 30), cdeq_i_t)
|
||||
M_LET( (lst, 10, 20, 30), clist_i_t)
|
||||
M_LET( (map, (20, 2), (10, 1), (30,3) ), csmap_i_t) {
|
||||
|
||||
// add one more element to each container
|
||||
cset_i_push(set, 40);
|
||||
cvec_p_push_back(vec, (Point_t) {{40, 4}} );
|
||||
cdeq_i_push_front(deq, 5);
|
||||
clist_i_push_back(lst, 5);
|
||||
csmap_i_set_at(map, 40, 4);
|
||||
|
||||
M_PRINT("vec= ", (vec, cvec_p_t));
|
||||
|
||||
// Find an element (either native or through the algo header)
|
||||
int *i1 = cset_i_get(set, 20);
|
||||
cvec_p_it_t i2; cvec_p_find(i2, vec, (Point_t) {{20, 2}});
|
||||
cdeq_i_it_t i3; cdeq_i_find(i3, deq, 20);
|
||||
clist_i_it_t i4; clist_i_find(i4, lst, 20);
|
||||
int *i5 = csmap_i_get(map, 20);
|
||||
printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n",
|
||||
*i1,
|
||||
(*cvec_p_ref(i2))->x, (*cvec_p_ref(i2))->y,
|
||||
*cdeq_i_ref(i3),
|
||||
*clist_i_ref(i4),
|
||||
20, *i5);
|
||||
|
||||
// Erase the elements found (through key or through iterators)
|
||||
cset_i_erase(set, *i1);
|
||||
cvec_p_remove(vec, i2);
|
||||
cdeq_i_remove(deq, i3);
|
||||
clist_i_remove(lst, i4);
|
||||
csmap_i_erase(map, *i5);
|
||||
|
||||
// Display everything in one call by using the registered print functions of the different types.
|
||||
M_PRINT("After erasing elements found:\n",
|
||||
"set: ", (set, cset_i_t), "\n",
|
||||
"vec: ", (vec, cvec_p_t), "\n",
|
||||
"deq: ", (deq, cdeq_i_t), "\n",
|
||||
"map: ", (map, csmap_i_t), "\n");
|
||||
}
|
||||
}
|
||||
+149
-75
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017, Patrick Pelissier
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -22,18 +22,21 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __M_ATOMIC_H
|
||||
#define __M_ATOMIC_H
|
||||
#ifndef MSTARLIB_ATOMIC_H
|
||||
#define MSTARLIB_ATOMIC_H
|
||||
|
||||
/* NOTE: Due to the C++ not having recognized stdatomic.h officialy,
|
||||
it is hard to use this header directly with a C++ compiler like
|
||||
g++ or MSVC.
|
||||
(See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932 ).
|
||||
clang has no issue with this header.
|
||||
GCC 4.9 doesn't have a working implementation of 'atomic'
|
||||
it is hard to use this header directly with a C++ compiler.
|
||||
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932
|
||||
clang++ has no issue with this header but if someone includes
|
||||
atomic from C++, there is incompatibility between atomic & stdatomic.
|
||||
Moreover some compilers lack a working stdatomic header.
|
||||
GCC 4.9 doesn't have a working implementation of 'atomic'.
|
||||
APPLE Clang defines __GNUC__ to be only 4 despite having full support
|
||||
for atomic.
|
||||
*/
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
&& !defined(__clang__) && !(defined(__GNUC__) && __GNUC__ < 5)
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
&& !(defined(__GNUC__) && __GNUC__ < 5 && !defined(__APPLE__))
|
||||
|
||||
/* NOTE: This is what the stdatomic.h header shall do in C++ mode. */
|
||||
#include <atomic>
|
||||
@@ -89,42 +92,91 @@ using std::atomic_flag_test_and_set_explicit;
|
||||
using std::atomic_flag_clear;
|
||||
using std::atomic_flag_clear_explicit;
|
||||
|
||||
using std::memory_order_relaxed;
|
||||
using std::memory_order_consume;
|
||||
using std::memory_order_acquire;
|
||||
using std::memory_order_release;
|
||||
using std::memory_order_acq_rel;
|
||||
using std::memory_order_seq_cst;
|
||||
|
||||
/* CLANG provides a warning on defining _Atomic as it sees it
|
||||
* as a reserved system macro. It is true. However, the goal of this
|
||||
* header is to provide stdatomic semantic, so it needs to define
|
||||
* _Atomic macro.
|
||||
*
|
||||
* So, this warning has to be ignored.
|
||||
*
|
||||
* It cannot use M_BEGIN_PROTECTED_CODE as this header is normally
|
||||
* independent of m-core.h
|
||||
*/
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
|
||||
#endif
|
||||
|
||||
#define _Atomic(T) std::atomic< T >
|
||||
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|
||||
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && __clang_major__ >= 4)
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic pop")
|
||||
#endif
|
||||
|
||||
/* C11 with working stdatomic
|
||||
STDATOMIC doesn't work with C++ except for clang but is incompatible with atomic.
|
||||
GCC < 4.9 doesn't provide a compliant stdatomic.h
|
||||
CLANG 3.5 has issues with GCC's stdatomic.h and doesn't provide its own
|
||||
ICC < 18 doesn't provide a compliant stdatomic.h
|
||||
*/
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) ) \
|
||||
|| (defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 308) \
|
||||
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
|
||||
|
||||
/* CLANG 3.5 has issues with GCC's stdatomic.h
|
||||
and doesn't provide its own stdatomic.h */
|
||||
#include <stdatomic.h>
|
||||
|
||||
#else
|
||||
/* MSYS2 has a conflict between cdefs.h which defines a _Atomic macro (if not C11)
|
||||
not compatible with the used stdatomic.h (from GCC).
|
||||
Provide a configurable mechanism to undef it with auto-detection of msys2 / gcc */
|
||||
#ifndef M_USE_UNDEF_ATOMIC
|
||||
# if defined(__MSYS__) && defined(__GNUC__) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L)
|
||||
# define M_USE_UNDEF_ATOMIC 1
|
||||
# endif
|
||||
#endif
|
||||
#if defined(M_USE_UNDEF_ATOMIC) && M_USE_UNDEF_ATOMIC == 1
|
||||
# undef _Atomic
|
||||
#endif
|
||||
|
||||
/* Non working atomic.h, nor working stdatomic.h found.
|
||||
/* Non working C++ atomic header, nor working stdatomic.h found.
|
||||
Write a compatible layer using mutex as slin as possible.
|
||||
Supports only up to 64-bits atomic (sizeof long long to be more precise).
|
||||
The locks are never properly cleared and remain active until
|
||||
the end of the program.
|
||||
We also assume that the call to the atomic_* interface is "clean".
|
||||
We also assume that the call to the atomic_* interface is "macro clean".
|
||||
*/
|
||||
#include "m-mutex.h"
|
||||
#else
|
||||
|
||||
/* The structure is quite large:
|
||||
__val : value of the atomic type,
|
||||
__zero : zero value of the atomic type (constant),
|
||||
__previous: temporary value used within the mutex lock,
|
||||
__lock : the mutex lock.
|
||||
#include "m-mutex.h"
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* _Atomic qualifier for a type (emulation).
|
||||
The structure is quite large:
|
||||
_val : value of the atomic type,
|
||||
_zero : zero value of the atomic type (constant),
|
||||
_previous: temporary value used within the mutex lock,
|
||||
_lock : the mutex lock.
|
||||
Support up to sizeof (long long) type.
|
||||
*/
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
volatile T __val; \
|
||||
T __zero; \
|
||||
T __previous; \
|
||||
m_mutex_t __lock; \
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
T volatile _val; \
|
||||
T _zero; \
|
||||
T _previous; \
|
||||
m_mutex_t _lock; \
|
||||
}
|
||||
|
||||
/* Even memory order is defined, only the strongest constraint is used */
|
||||
/* Define the supported memory order.
|
||||
Even if memory order is defined, only the strongest constraint is used */
|
||||
typedef enum {
|
||||
memory_order_relaxed,
|
||||
memory_order_consume,
|
||||
@@ -152,7 +204,7 @@ typedef _Atomic(size_t) atomic_size_t;
|
||||
typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
|
||||
/* Define the minimum size supported by the architecture
|
||||
for atomic read or write.
|
||||
for an atomic read or write.
|
||||
This can help a lot since it avoids locking for atomic_load and
|
||||
atomic_store.
|
||||
*/
|
||||
@@ -165,77 +217,97 @@ typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
#endif
|
||||
|
||||
/* Detect if stdint.h was included */
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
defined (_SYS_STDINT_H_)
|
||||
/* Define additional atomic types */
|
||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||
typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||
#endif
|
||||
|
||||
/* Unlock the mutex and return the given value */
|
||||
/* (INTERNAL) Unlock the mutex and return the given value */
|
||||
static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
{
|
||||
m_mutex_unlock (*lock);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* This is the heart of the wrapper:
|
||||
/* (INTERNAL) This is the heart of the wrapper:
|
||||
lock the atomic value, read it and returns the value.
|
||||
In order to avoid any compiler extension, we need to transform the
|
||||
atomic type into 'long long' then convert it back to its value.
|
||||
This is because __previous can't be read after the lock, and we can't
|
||||
This is because _previous can't be read after the lock, and we can't
|
||||
generate temporary variable within a macro.
|
||||
The trick is computing _val - _zero within the lock, then
|
||||
returns retvalue + _zero after the lock.
|
||||
returns retvalue + _zero after the release of the lock.
|
||||
*/
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->__lock), \
|
||||
(ptr)->__previous = (ptr)->__val, \
|
||||
(ptr)->__val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->__lock, (ptr)->__previous-(ptr)->__zero)+(ptr)->__zero)
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
(ptr)->_val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long)((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
/* Perform an atomic add (EMULATION) */
|
||||
#define atomic_fetch_add(ptr, val) atomic_fetch_op(ptr, val, +=)
|
||||
/* Perform an atomic sub (EMULATION) */
|
||||
#define atomic_fetch_sub(ptr, val) atomic_fetch_op(ptr, val, -=)
|
||||
/* Perform an atomic or (EMULATION) */
|
||||
#define atomic_fetch_or(ptr, val) atomic_fetch_op(ptr, val, |=)
|
||||
/* Perform an atomic xor (EMULATION) */
|
||||
#define atomic_fetch_xor(ptr, val) atomic_fetch_op(ptr, val, ^=)
|
||||
/* Perform an atomic and (EMULATION) */
|
||||
#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=)
|
||||
/* Perform an atomic exchange (EMULATION) */
|
||||
#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =)
|
||||
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
/* Initialize an atomic GLOBAL variable */
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
|
||||
#define atomic_init(ptr, val) \
|
||||
(m_mutex_init((ptr)->__lock), (ptr)->__val = val, (ptr)->__zero = 0)
|
||||
/* Initialize an atomic variable */
|
||||
#define atomic_init(ptr, val) \
|
||||
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
|
||||
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->__lock), \
|
||||
(ptr)->__previous = (ptr)->__val, \
|
||||
atomic_fetch_unlock(&(ptr)->__lock, (ptr)->__previous-(ptr)->__zero)+(ptr)->__zero)
|
||||
/* (INTERNAL) Load an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long) ((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->__lock), \
|
||||
(ptr)->__val = (val), \
|
||||
m_mutex_unlock((ptr)->__lock))
|
||||
/* (INTERNAL) Store an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
m_mutex_unlock((ptr)->_lock))
|
||||
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->__val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->__val \
|
||||
/* Atomic load of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct read of the variable (much faster) */
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
: atomic_load_lock(ptr))
|
||||
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->__val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->__val = (val); \
|
||||
} else { \
|
||||
long long _offset = (val) - (ptr)->__zero; \
|
||||
atomic_store_lock(ptr, (ptr)->__zero + _offset); \
|
||||
} \
|
||||
|
||||
/* Atomic store of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct write of the variable (much faster) */
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
} else { \
|
||||
long long _offset = (long long) ((val) - (ptr)->_zero); \
|
||||
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->__lock), \
|
||||
atomic_fetch_unlock(&(ptr)->__lock, \
|
||||
(ptr)->__val == *(exp) \
|
||||
? ((ptr)->__val = (val), true) \
|
||||
: (*(exp) = (ptr)->__val, false)))
|
||||
/* Perform a CAS (Compare and swap) operation (EMULATION) */
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
(ptr)->_val == *(exp) \
|
||||
? ((ptr)->_val = (val), true) \
|
||||
: (*(exp) = (ptr)->_val, false)))
|
||||
|
||||
|
||||
#define atomic_fetch_add_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, +=)
|
||||
@@ -250,11 +322,13 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
#define atomic_thread_fence(mem) (void) 0
|
||||
#define atomic_signal_fence(mem) (void) 0
|
||||
#define atomic_is_lock_free(ptr) false
|
||||
#define atomic_compare_exchange_strong_explicit(ptr, exp, val, mem) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
#define atomic_compare_exchange_strong_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
|
||||
/* TODO: Missing atomic_flag. Problem: it needs to be lock free! */
|
||||
/* TODO: Missing atomic_flag. Problem: it is supposed to be lock free! */
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+465
-260
File diff suppressed because it is too large.
Load diff
+1482
File diff suppressed because it is too large.
Load diff
+1209
-454
File diff suppressed because it is too large.
Load diff
Loaded 100 of 171 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user