Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46759b5f2c | ||
|
|
8c8a1e2822 | ||
|
|
ad646f5e04 | ||
|
|
9ecc031fd7 | ||
|
|
ea3c2c5019 | ||
|
|
a9dc2eef12 | ||
|
|
39a0a4f672 | ||
|
|
4ffa4a15ac | ||
|
|
2d5c9e71ae | ||
|
|
e802e22b7b | ||
|
|
3fbe8ec0b6 | ||
|
|
34085aa637 | ||
|
|
77033e2020 | ||
|
|
5c57ad1f51 | ||
|
|
27621db95d | ||
|
|
eab3f701a8 | ||
|
|
cbc5f17cf0 | ||
|
|
02a39fce3f | ||
|
|
7c4f94a674 | ||
|
|
8c70a1f96c | ||
|
|
25dcdeed69 | ||
|
|
7e8cb07a6c | ||
|
|
2296f203fd | ||
|
|
790ae33334 | ||
|
|
d795476157 | ||
|
|
6a2bdc49fb | ||
|
|
725f42852e | ||
|
|
bfcc4134d6 | ||
|
|
de6ccc293e | ||
|
|
d9953daf59 | ||
|
|
1a62f5a4ed | ||
|
|
3721129da1 | ||
|
|
f585167fa8 | ||
|
|
6d5d34fb72 | ||
|
|
196db1cf62 | ||
|
|
174c62015b | ||
|
|
fb3140e645 | ||
|
|
431e3a1228 | ||
|
|
3ddf9438da | ||
|
|
6e8aa58bd6 | ||
|
|
df37a5d8f1 | ||
|
|
2ad8d42401 | ||
|
|
8f47fb35ae | ||
|
|
a1a5ae749d | ||
|
|
147bc0a363 | ||
|
|
33aa102b7c | ||
|
|
bd9485a3fe | ||
|
|
0de3c622e3 | ||
|
|
93a1be616d | ||
|
|
692c0487af | ||
|
|
22ccae74c3 | ||
|
|
586d0ae13a | ||
|
|
c7bad98a7e | ||
|
|
8e3a06b852 | ||
|
|
d548117538 | ||
|
|
3a39ce5a4a | ||
|
|
fa41f3affd | ||
|
|
0d0747dea9 | ||
|
|
ab75397e21 | ||
|
|
cc97aa887f | ||
|
|
b275859a37 | ||
|
|
256ff916a2 | ||
|
|
77195fb1d0 | ||
|
|
c2cfb2f0a0 | ||
|
|
03cceafd73 | ||
|
|
505e2c4a62 | ||
|
|
daadf693f7 | ||
|
|
98b3bbd7a1 | ||
|
|
decec8f7ae | ||
|
|
ce3f674ba8 | ||
|
|
01f5228a36 | ||
|
|
a7294abe0c | ||
|
|
77e5666802 | ||
|
|
689527c2dc | ||
|
|
5d1ebdf5bb | ||
|
|
10d918bbc9 | ||
|
|
8069fae3d5 | ||
|
|
94dd0a5571 | ||
|
|
32a3d95104 | ||
|
|
d08aeb32fe | ||
|
|
26fc2bcffe | ||
|
|
7617048073 | ||
|
|
57e7510ae7 | ||
|
|
324ba5d256 | ||
|
|
8939b4d046 | ||
|
|
1cf7c4fa4d | ||
|
|
839e7c2957 | ||
|
|
06e3046268 | ||
|
|
e959c001aa | ||
|
|
bcc9f2c894 | ||
|
|
6e828eabaf | ||
|
|
7677b13d8a | ||
|
|
e16c6987e4 | ||
|
|
aa4cbfebdb | ||
|
|
66f376ea80 | ||
|
|
6de8eab5c3 | ||
|
|
9e63289a38 | ||
|
|
bf617ab6ab | ||
|
|
3f8c30e592 | ||
|
|
37b2f4d2ac | ||
|
|
50e8d1f469 | ||
|
|
d40a6e5bc3 | ||
|
|
b4c29d5423 | ||
|
|
9f4f9d1d5d | ||
|
|
1e196fe22a | ||
|
|
450d2c9000 | ||
|
|
93112a5a7c | ||
|
|
1f2584ccea | ||
|
|
5b4c9cd618 | ||
|
|
f4e3d9cd4c | ||
|
|
4988661b7d | ||
|
|
7033a922c7 | ||
|
|
dd607252eb | ||
|
|
73da9a4316 | ||
|
|
b3a0d70147 | ||
|
|
c55bb6b9ad | ||
|
|
68fdc2dde1 | ||
|
|
8877af10b0 | ||
|
|
782963dec5 | ||
|
|
36d11bc2bd | ||
|
|
6d621703eb | ||
|
|
76b40d247d | ||
|
|
033deac9f5 | ||
|
|
b60553165d | ||
|
|
e1a4d359a2 | ||
|
|
4ab2615a1c | ||
|
|
9136a4a972 | ||
|
|
55dcf0e438 | ||
|
|
fb604f02b7 | ||
|
|
1db417e30e | ||
|
|
5b77fe7207 | ||
|
|
dd509f2b7e | ||
|
|
50d4e15297 | ||
|
|
f6d1b16338 | ||
|
|
64a035559d | ||
|
|
c4bc37560c | ||
|
|
e7309b7d3a | ||
|
|
c461b4eca4 | ||
|
|
f21d427de1 | ||
|
|
0f9edaa7ee | ||
|
|
64888127c4 | ||
|
|
d5b4ec249b | ||
|
|
0bcd78a8f5 | ||
|
|
27b0850af4 | ||
|
|
ae55ccfc40 | ||
|
|
5bf644ccf0 | ||
|
|
3f09adc507 | ||
|
|
4e851142c2 | ||
|
|
fec6b42260 | ||
|
|
9dbc48aa5d | ||
|
|
b92bae34eb | ||
|
|
8faf7f79c4 | ||
|
|
c3e29a16df | ||
|
|
1bc33a10fc | ||
|
|
b7074d1c69 | ||
|
|
26d541fe06 | ||
|
|
2991c7cc5a | ||
|
|
4e7cbae766 | ||
|
|
d5e0620e4c | ||
|
|
32cfbd23bc | ||
|
|
0e09681a6a | ||
|
|
bc8098b337 | ||
|
|
c5692e7e9f | ||
|
|
f43db93791 | ||
|
|
14c954c6ce | ||
|
|
60280087c7 | ||
|
|
1e57d9c6d6 | ||
|
|
eeaf74d24f | ||
|
|
a318d36c35 | ||
|
|
edcf8ee37a | ||
|
|
8a1f30eeff | ||
|
|
2995b119b7 | ||
|
|
08bd5a888b | ||
|
|
2f1b17f805 | ||
|
|
0379f5f1c6 | ||
|
|
45b11fb49b | ||
|
|
82ea4341de | ||
|
|
341d145b4d | ||
|
|
847f52fa5e | ||
|
|
02828a0109 | ||
|
|
0f7d5bf366 | ||
|
|
1277c75ea3 | ||
|
|
47a51ee5c4 | ||
|
|
3f102c2270 | ||
|
|
4ba55dc3ca | ||
|
|
2c0db40158 | ||
|
|
8987288a10 | ||
|
|
cf8c2afddd | ||
|
|
0a8e336037 | ||
|
|
e7e29d913e | ||
|
|
f3ebc8c7eb | ||
|
|
2d4fc9dc97 | ||
|
|
afedb06dee | ||
|
|
3fd2146bbe | ||
|
|
8e70b6175a | ||
|
|
67e9c8ff06 | ||
|
|
bf59c53921 | ||
|
|
5589105f5c | ||
|
|
66d2aa26d3 | ||
|
|
1ae904dff2 | ||
|
|
4549f4ab91 | ||
|
|
75d5627378 | ||
|
|
8cbd27e629 | ||
|
|
333cc2ccf8 | ||
|
|
000dba1da5 | ||
|
|
11946f155d | ||
|
|
99713e873c | ||
|
|
ea5c993ff0 | ||
|
|
22d62f94bb | ||
|
|
8fd79f07d5 | ||
|
|
29fe80a6af | ||
|
|
e787b64978 | ||
|
|
4f9db5eba6 | ||
|
|
db5990de03 | ||
|
|
d4383ef854 | ||
|
|
d10c8c1b41 | ||
|
|
3c669548a2 | ||
|
|
ec11230b5e | ||
|
|
567473869b | ||
|
|
0b6733fdcb | ||
|
|
8e330862e1 | ||
|
|
b2adc77d76 | ||
|
|
82cbe9e282 | ||
|
|
93429c8bf3 | ||
|
|
150bef4d4d | ||
|
|
562fd875e9 | ||
|
|
5513a9df1b | ||
|
|
6fd2610eec | ||
|
|
11bf5e4691 | ||
|
|
cf0d82a706 | ||
|
|
b0cc17ea86 | ||
|
|
04d4bf6866 | ||
|
|
738123d4a7 | ||
|
|
a3ece09e66 | ||
|
|
8109c094db | ||
|
|
2c81582419 | ||
|
|
f8c79d9259 | ||
|
|
c7a894b34e | ||
|
|
5c36e045ff | ||
|
|
0f883d2ecf | ||
|
|
9dfcf41b64 | ||
|
|
1416f4e225 | ||
|
|
16c6a13fb1 | ||
|
|
9382cdc0f7 | ||
|
|
ced2719760 | ||
|
|
1798530284 | ||
|
|
68f890a015 | ||
|
|
5805038943 | ||
|
|
2395ceb3d2 | ||
|
|
2b455c5c6b | ||
|
|
d466e76702 | ||
|
|
9d33c85e13 | ||
|
|
4e24e7a533 | ||
|
|
0914c26b8d | ||
|
|
c245285123 | ||
|
|
be4ff6f94d | ||
|
|
aa055d0b00 | ||
|
|
e7d6e0d6ac | ||
|
|
8f97a194ae | ||
|
|
b191baec8b | ||
|
|
e4a85cdc61 | ||
|
|
12ee3213b0 | ||
|
|
6cba7ad8ba | ||
|
|
955c8bfb81 | ||
|
|
8602a259fd | ||
|
|
7404e63b53 | ||
|
|
c539eb57b7 | ||
|
|
3c4943015b | ||
|
|
c9fef6d80a | ||
|
|
5174781a7a | ||
|
|
7bf9f6a377 | ||
|
|
7575681e27 | ||
|
|
cfab3cf0cf | ||
|
|
a523a97a0e | ||
|
|
6f75bb938b | ||
|
|
a22046bc2a | ||
|
|
84ee15b2e7 | ||
|
|
fd6a8f1361 | ||
|
|
d22e75d7a0 | ||
|
|
ca25dfb537 | ||
|
|
e2159109b3 | ||
|
|
cc6bdbf06c | ||
|
|
cd37efc69d | ||
|
|
db08e62f1a | ||
|
|
3be653d55a | ||
|
|
e351730ad0 | ||
|
|
d7a232364f | ||
|
|
f7580e7ce9 | ||
|
|
26cec1591a | ||
|
|
52b58c5a51 | ||
|
|
8902a752f5 | ||
|
|
3445da13f3 | ||
|
|
127530abaa | ||
|
|
ed0f538fb7 | ||
|
|
76ef061dec | ||
|
|
c98786a3b3 | ||
|
|
422f3c2c04 | ||
|
|
5ceb34d980 | ||
|
|
73e3d1d1bd | ||
|
|
044a085fb6 | ||
|
|
5344423ad9 | ||
|
|
76ea989865 | ||
|
|
29c4ba3dcc | ||
|
|
42184f69db | ||
|
|
fb8bf65233 | ||
|
|
1d86e51f4a | ||
|
|
53c35a22d7 | ||
|
|
722737d60c | ||
|
|
f951a947ec | ||
|
|
d9401371a6 | ||
|
|
690fd72c8b | ||
|
|
d318493c6c | ||
|
|
fecece19cb | ||
|
|
ea640482a7 | ||
|
|
3e558af559 | ||
|
|
91a602f774 | ||
|
|
6a5c136c72 | ||
|
|
e50fdc82ef | ||
|
|
ec0a082701 | ||
|
|
7bf3ea3a87 | ||
|
|
15492394ad | ||
|
|
09f40b5695 | ||
|
|
eabfcd1d49 | ||
|
|
00aeafc616 | ||
|
|
f512051807 | ||
|
|
4e8b929da9 | ||
|
|
5841f936e6 | ||
|
|
2ee40339b0 | ||
|
|
0c8eca893d | ||
|
|
b16048a55b | ||
|
|
9dc582c6bc | ||
|
|
1df8bf84fb | ||
|
|
e017a90e5c | ||
|
|
58b317b759 | ||
|
|
3a057fc319 | ||
|
|
703ab6ff9c | ||
|
|
f7f5db61d3 | ||
|
|
32b00eb433 | ||
|
|
796f2619e5 | ||
|
|
268192138a | ||
|
|
0671a2ea41 | ||
|
|
07dce84e51 | ||
|
|
5f4303624f | ||
|
|
19e61467d5 | ||
|
|
1454bcebe4 | ||
|
|
d48f2ff84d | ||
|
|
269636b4d8 | ||
|
|
bf68340106 | ||
|
|
5dba526e29 | ||
|
|
469239adcd | ||
|
|
589abda0c2 | ||
|
|
8f141896ba | ||
|
|
a0cbec4329 | ||
|
|
df66db562d | ||
|
|
1829a70601 | ||
|
|
e9b25f2414 | ||
|
|
c9bb739f24 | ||
|
|
e049b83a9e | ||
|
|
31ac3999a1 | ||
|
|
a0818419ab | ||
|
|
496f885a84 | ||
|
|
d5d9a4bd5c | ||
|
|
ca9571a110 | ||
|
|
4497214b9c | ||
|
|
ccb1658afd | ||
|
|
eaf2783f1a | ||
|
|
5705819814 | ||
|
|
91f5f513c4 | ||
|
|
3dec4e2cbe | ||
|
|
e70766beaa | ||
|
|
d7639f0ae0 | ||
|
|
c63ce84e45 | ||
|
|
a043c379c0 | ||
|
|
92bb380117 | ||
|
|
6bb7a184db | ||
|
|
fa9163be9d | ||
|
|
0bade1563c | ||
|
|
1278d2f8a0 | ||
|
|
53af2aae68 | ||
|
|
17ded6fcc8 | ||
|
|
19ce371533 | ||
|
|
0bd1bcb68e | ||
|
|
b50813713a | ||
|
|
2628536d20 | ||
|
|
ecfa4a9152 | ||
|
|
dafe4bcec5 | ||
|
|
8544a7f289 | ||
|
|
aa18915d61 | ||
|
|
df4bc0a56c | ||
|
|
b6046e5e23 | ||
|
|
b487bfe5ad | ||
|
|
408272c810 | ||
|
|
6a9ee17eca | ||
|
|
05c5a94634 | ||
|
|
b1b0927e9f | ||
|
|
37770365a1 | ||
|
|
82bdcc685a | ||
|
|
26fa733f70 | ||
|
|
cd2fc05573 | ||
|
|
33430d4359 | ||
|
|
dc95b49f05 | ||
|
|
3ec24cfa40 | ||
|
|
12b099dcf8 | ||
|
|
b885d6136c | ||
|
|
b51c4bea2b | ||
|
|
302c5eb300 | ||
|
|
6d2900a2bd | ||
|
|
573e09c56e | ||
|
|
0a39a17d36 | ||
|
|
a913d0947c | ||
|
|
abbd8ad6ce | ||
|
|
a09c9fe1c3 | ||
|
|
219c62ff5d | ||
|
|
272a326375 | ||
|
|
eca79f2c80 | ||
|
|
2feda4059f | ||
|
|
de0ef67cf2 | ||
|
|
95762a058c | ||
|
|
acd8671017 | ||
|
|
a6c1688f23 | ||
|
|
f6ed549ce5 | ||
|
|
8639fdbd98 | ||
|
|
693b09387f | ||
|
|
4052d3794b | ||
|
|
044e9c3bf7 | ||
|
|
45a2a1afb2 | ||
|
|
b44e4e09dd | ||
|
|
5158059ec4 | ||
|
|
7279011f0a | ||
|
|
79369e9b05 | ||
|
|
58a7a7c214 | ||
|
|
e3e94ca238 | ||
|
|
ae81271b2a | ||
|
|
d9c3724cff | ||
|
|
1ff9848384 | ||
|
|
83e7f2a641 | ||
|
|
6580601969 | ||
|
|
ad023bb09d | ||
|
|
b5df21f9c5 | ||
|
|
d2dccbf514 | ||
|
|
a8075cbb05 | ||
|
|
1322afc4c9 | ||
|
|
0f885fb158 | ||
|
|
25a2eb0875 | ||
|
|
6bcd51f10f | ||
|
|
9c1cb9c835 | ||
|
|
19cb329ae6 | ||
|
|
8099e6a94f | ||
|
|
ce6cc080d6 | ||
|
|
a27b0b4014 | ||
|
|
e74f80cc59 | ||
|
|
bafd307247 | ||
|
|
6bed3ac697 | ||
|
|
b8a9073fc9 | ||
|
|
da3e71c676 | ||
|
|
4ea83e129e | ||
|
|
fc34fa80b5 | ||
|
|
4f608ec266 | ||
|
|
ccaa54d2a5 | ||
|
|
095bf7070d | ||
|
|
676b12d5d2 | ||
|
|
f858aa2cb5 | ||
|
|
9d77448a25 | ||
|
|
8babc33b91 | ||
|
|
352d7cf725 | ||
|
|
a6993ab758 | ||
|
|
48260ac2a6 | ||
|
|
e4afb024b9 | ||
|
|
63008af30f | ||
|
|
1828aca65e | ||
|
|
9354e9717d | ||
|
|
100c0f22fe | ||
|
|
ff778528f8 | ||
|
|
8f1a1df617 | ||
|
|
28faf815d7 | ||
|
|
fe3b703d0a | ||
|
|
0aa6a9f0cf | ||
|
|
67832ac918 | ||
|
|
669a3297c7 | ||
|
|
25d4829d7b | ||
|
|
ebab05a789 | ||
|
|
727df5b7bf | ||
|
|
aebe1308fc | ||
|
|
1d163a396e | ||
|
|
7534aa0d61 | ||
|
|
6976d4e23d | ||
|
|
6b7954e141 | ||
|
|
c27d76a83b | ||
|
|
0e3081bfc6 | ||
|
|
d754e9a15f | ||
|
|
4e4e21793c | ||
|
|
c515da9f37 | ||
|
|
961b93bd4c | ||
|
|
39a719c3f0 | ||
|
|
8b643b4878 | ||
|
|
876c394fba | ||
|
|
81439c9437 | ||
|
|
191ef7d09e | ||
|
|
bd4131dd8f | ||
|
|
cfe8293c64 | ||
|
|
ea2715aa75 | ||
|
|
f69cec6820 | ||
|
|
085f371693 | ||
|
|
16a0a5c1a3 | ||
|
|
3953f81884 | ||
|
|
8365888e6e | ||
|
|
c3f6e3c5f0 | ||
|
|
4cafe4dce1 | ||
|
|
9f8b97ae46 | ||
|
|
030bea9c11 | ||
|
|
e33894f1b3 | ||
|
|
66f5e6c67d | ||
|
|
78c6dce068 | ||
|
|
0798480ad5 | ||
|
|
e8322215fd | ||
|
|
42d3042c15 | ||
|
|
b7214ad11d | ||
|
|
08b4bc9052 | ||
|
|
d813171e8a | ||
|
|
d1094999f5 | ||
|
|
c8354aa6ed | ||
|
|
ab3aa33fac | ||
|
|
01f2f376e2 | ||
|
|
535e00366a | ||
|
|
42111ec22a | ||
|
|
ef0e849616 | ||
|
|
9c516c2055 | ||
|
|
db48b985c3 | ||
|
|
888796ca06 | ||
|
|
144ae9c5ed | ||
|
|
6223c93b53 | ||
|
|
30f7656822 | ||
|
|
8209a0c32a | ||
|
|
92e6957320 | ||
|
|
b3c9f6ee47 | ||
|
|
ab8bbad3f4 | ||
|
|
9047376b7f | ||
|
|
dfed8dbc50 | ||
|
|
2d3c25cd85 | ||
|
|
bfa948dc7a | ||
|
|
94b6d1b9fd | ||
|
|
0ddd5ddc6d | ||
|
|
cba93d5bb4 | ||
|
|
d02de75487 | ||
|
|
2f57766249 | ||
|
|
3ff01e37eb | ||
|
|
5683df0f22 | ||
|
|
11dc7afc06 | ||
|
|
9e2ae3f101 | ||
|
|
c35aa9c891 | ||
|
|
2fc31d8c12 | ||
|
|
4f8d0a7156 | ||
|
|
aaf5bbd6a0 | ||
|
|
2f76652f2b | ||
|
|
942cf32519 | ||
|
|
c1c9cb9cd3 | ||
|
|
76bfb48685 | ||
|
|
afff412f7a | ||
|
|
e48dcdeecc | ||
|
|
12fae5c36c | ||
|
|
3f9129c7ed | ||
|
|
b918f61f4f | ||
|
|
93b69d0f8b | ||
|
|
b3440a2edd | ||
|
|
4140df5bfc | ||
|
|
fbab093d52 | ||
|
|
f57a0e0bf8 | ||
|
|
925c06beb8 | ||
|
|
8e2f67b794 | ||
|
|
f176d01e49 | ||
|
|
2b99bbe956 | ||
|
|
700bfc5341 | ||
|
|
4062525821 | ||
|
|
800a1e5c36 | ||
|
|
1838f675a7 | ||
|
|
bf6c1341b3 | ||
|
|
55b745b916 | ||
|
|
5cb0d9214b | ||
|
|
8f99b8e617 | ||
|
|
d2ce71a90a | ||
|
|
8562986eea | ||
|
|
ee89858bf0 | ||
|
|
085d7157c0 | ||
|
|
91f3174a36 | ||
|
|
56f51c59af | ||
|
|
df0c95ca46 | ||
|
|
482ec38e62 | ||
|
|
82743ca72c | ||
|
|
312821454c | ||
|
|
c953e87660 | ||
|
|
8846707c8b | ||
|
|
bf7d4eee55 | ||
|
|
d4dc85f89a | ||
|
|
130c32e7d4 | ||
|
|
2bcaba3bc0 | ||
|
|
443c805c22 | ||
|
|
414c87bb69 | ||
|
|
e9ca506d93 | ||
|
|
8e58f7d637 | ||
|
|
254beaf3c7 | ||
|
|
27735eb224 | ||
|
|
0afc81bd54 | ||
|
|
39e67eebdc | ||
|
|
840226c7fd | ||
|
|
e421851525 | ||
|
|
f70b52c9e4 | ||
|
|
40249ce5bc | ||
|
|
97ff413f01 | ||
|
|
8e4ac99a35 | ||
|
|
4366e8eeab | ||
|
|
4e5e498bb2 | ||
|
|
870a6f4b57 | ||
|
|
a2ae209992 | ||
|
|
43fdd10e77 | ||
|
|
b1183de0f8 | ||
|
|
3a3ef7454c | ||
|
|
5f946b728b | ||
|
|
9cc03ff81b | ||
|
|
89d4db174e | ||
|
|
f5bbc0a7fb | ||
|
|
9da0d1d94b | ||
|
|
fafaaafdbf | ||
|
|
38f4107b19 | ||
|
|
cbefdab4bb | ||
|
|
bcd0c46e8b | ||
|
|
f25bb73e58 | ||
|
|
ea3584e048 | ||
|
|
85473610a4 | ||
|
|
f9f0b307fc | ||
|
|
d17fa4530b | ||
|
|
3806495e2d | ||
|
|
15f58d5738 | ||
|
|
4de7da1c05 | ||
|
|
93229c61f2 | ||
|
|
3f0e8956b8 | ||
|
|
b82670b643 | ||
|
|
64800dbd3f | ||
|
|
2d9d9fbd9f | ||
|
|
f0ba5d17f4 | ||
|
|
e51c988222 | ||
|
|
0be3900beb | ||
|
|
f60ce0320a | ||
|
|
77008b8622 | ||
|
|
a7617002c5 | ||
|
|
bc73616bde | ||
|
|
d6b9b054c2 | ||
|
|
9eed4be97c | ||
|
|
2519927178 | ||
|
|
0fec33b38e | ||
|
|
dc2b6d2b2d | ||
|
|
bc63edc595 | ||
|
|
6241a3093c | ||
|
|
fb53a464d7 | ||
|
|
aba26b75a2 | ||
|
|
775ec6f91b | ||
|
|
95bc7063a0 | ||
|
|
731d3ecf1a | ||
|
|
0d1817e7ca | ||
|
|
1a5b428bfb | ||
|
|
bd49e31f3b | ||
|
|
2dba83e3c5 | ||
|
|
75e9766da9 | ||
|
|
d2f8aa1c0d | ||
|
|
4aa4b7693f | ||
|
|
d50b450927 | ||
|
|
5674cdbfc5 | ||
|
|
3641829198 | ||
|
|
10a759b09e | ||
|
|
b5a3b36c1b | ||
|
|
b0c3839f2b | ||
|
|
3aa3e95e4c | ||
|
|
87f1e53e13 | ||
|
|
d7b45cc220 | ||
|
|
d8142a9764 | ||
|
|
8780f58739 | ||
|
|
e352104df8 | ||
|
|
cbb2b452bb | ||
|
|
6e947c6262 | ||
|
|
18f04da4ec | ||
|
|
3dad6ef65c | ||
|
|
41c4f5fe5c | ||
|
|
cfeedf19f8 | ||
|
|
2ab410bd6a | ||
|
|
aefbc5b2f5 | ||
|
|
abec9c37fa | ||
|
|
442b0e7cea | ||
|
|
0b853c6d52 | ||
|
|
cc7fc66899 | ||
|
|
6b994c2928 | ||
|
|
e6fe36d3cd | ||
|
|
f45ededf8b | ||
|
|
ed27bedcb4 | ||
|
|
eb1a7a0435 | ||
|
|
de00fdc5f7 | ||
|
|
8febe12c5c | ||
|
|
1368b201eb | ||
|
|
4ca166b0b9 | ||
|
|
c13533cf21 | ||
|
|
9fdf0f76e7 | ||
|
|
308f513edc | ||
|
|
900bcc3819 | ||
|
|
b6e0994dfc | ||
|
|
121339d948 | ||
|
|
c5bb84013a | ||
|
|
65b49268d3 | ||
|
|
ecebd62f86 | ||
|
|
6a8c9a703d | ||
|
|
ad05ae9aa5 | ||
|
|
abffe201e5 | ||
|
|
ee2bc27bda | ||
|
|
14b94865b7 | ||
|
|
6e1ceafcc2 | ||
|
|
58746560e9 | ||
|
|
082adca3e6 | ||
|
|
ee1dc2a8e8 | ||
|
|
92e2d835bd | ||
|
|
22aba04b47 | ||
|
|
399c615915 | ||
|
|
cbdba0941a | ||
|
|
90c54a48d0 | ||
|
|
22b18830f7 | ||
|
|
dab085e3a7 | ||
|
|
66fac10a98 | ||
|
|
e5fb5ddde1 | ||
|
|
dcf20fbbd6 | ||
|
|
5d659877fe | ||
|
|
a30dd69aaa | ||
|
|
b1f698bb7b | ||
|
|
2323420a87 | ||
|
|
7e120a3615 | ||
|
|
804db294ca | ||
|
|
d12aa6c263 | ||
|
|
d59e87d2bf | ||
|
|
8f3c0af548 | ||
|
|
1f3013c445 | ||
|
|
f13e99ab1a | ||
|
|
fb8ad84675 | ||
|
|
12608afe10 | ||
|
|
f97e92b4cb | ||
|
|
a74e26e3de | ||
|
|
a30b783692 | ||
|
|
e64a6a22e7 | ||
|
|
76892afa13 | ||
|
|
dcb1eb0d94 | ||
|
|
950ea224ff | ||
|
|
b22a844007 | ||
|
|
502756c731 | ||
|
|
e38dc19ea1 | ||
|
|
2bebb2b4a1 | ||
|
|
5b7be93c1a | ||
|
|
d04270ae3f | ||
|
|
1bef7c1977 | ||
|
|
ae037ff7af | ||
|
|
a4267d60df | ||
|
|
47e32ab2b3 | ||
|
|
5ac08e42d8 | ||
|
|
9c59684b61 | ||
|
|
f26e1e5a12 | ||
|
|
1cde4633e6 | ||
|
|
1393f8e9aa | ||
|
|
bfffa1d245 | ||
|
|
3a6b568ccc | ||
|
|
453a920af8 | ||
|
|
1fd86ffc2e | ||
|
|
96a0639a8a | ||
|
|
c12d0a3f23 | ||
|
|
cac8790405 | ||
|
|
ccd9726e01 | ||
|
|
5516b50b3a | ||
|
|
b5a3e010d8 | ||
|
|
2d7d267252 | ||
|
|
bd5d7aaada | ||
|
|
18b6be8e00 | ||
|
|
958abfef93 | ||
|
|
198be1062b | ||
|
|
0cfee02641 | ||
|
|
48dc38508a | ||
|
|
e763204bf7 | ||
|
|
370baf56ab | ||
|
|
4fd6bcbf99 | ||
|
|
59d1e23dea | ||
|
|
cb173f2f81 | ||
|
|
d047174c2f | ||
|
|
df25159d03 | ||
|
|
99618a687e | ||
|
|
a1b226e185 | ||
|
|
e93df4332a | ||
|
|
5a1f768b03 | ||
|
|
e854bc8fc9 | ||
|
|
9ab958708d | ||
|
|
85ea92d83b | ||
|
|
22a406ac51 | ||
|
|
58eed79413 | ||
|
|
e83dea8212 | ||
|
|
c829827f48 | ||
|
|
b47cf05a59 | ||
|
|
22a93514ff | ||
|
|
154865f0f1 | ||
|
|
71151770fd | ||
|
|
72623ce13e | ||
|
|
94f20d56e9 | ||
|
|
9e8ad9bfd9 | ||
|
|
e51a5be776 | ||
|
|
7d647340c6 | ||
|
|
c6ea3c0616 | ||
|
|
9ab90be6d4 | ||
|
|
10440320d1 | ||
|
|
fc7e93403a | ||
|
|
b0c4418584 | ||
|
|
5f73eb7788 | ||
|
|
a554312573 | ||
|
|
8a1fd391d1 | ||
|
|
95b104ee48 | ||
|
|
c3df69d011 | ||
|
|
73468a3e24 | ||
|
|
f254f98e42 | ||
|
|
d37076dd37 | ||
|
|
5ef9376148 | ||
|
|
d8abda7583 | ||
|
|
892c755389 | ||
|
|
aba2f90c9d | ||
|
|
dc487c7e64 | ||
|
|
18b1bd9518 | ||
|
|
845ab1fef0 | ||
|
|
94bfac3f75 | ||
|
|
bd5c9ce2a7 | ||
|
|
f5934a6274 | ||
|
|
c6f71fddc7 | ||
|
|
74764e2d6f | ||
|
|
9b00a8c54e | ||
|
|
66735e99c3 | ||
|
|
80acbb4343 | ||
|
|
2fb912d43d | ||
|
|
8c8dc6de7c | ||
|
|
677acdd14e | ||
|
|
6caeea98b9 | ||
|
|
c5d37ce028 | ||
|
|
112b405df6 | ||
|
|
47385d58e5 | ||
|
|
c8275c8f63 | ||
|
|
0c1e888a78 | ||
|
|
6a1ff3e080 | ||
|
|
6d41eba5ed | ||
|
|
c0abcc6d60 | ||
|
|
da71c81195 | ||
|
|
8e0d17e85c | ||
|
|
6d98c273c1 | ||
|
|
85f6ff34aa | ||
|
|
759c24be63 | ||
|
|
d85955ef60 | ||
|
|
3a53044198 | ||
|
|
4d5cd9c635 | ||
|
|
57b88160ae | ||
|
|
33ba602aef | ||
|
|
3632388315 | ||
|
|
6ee82e885b | ||
|
|
2f92cee416 | ||
|
|
9269473e10 | ||
|
|
c8611ce708 | ||
|
|
d8fd43e9e9 | ||
|
|
a2e471620d | ||
|
|
ffa3821acf | ||
|
|
5c98d47d8c | ||
|
|
0875eaac03 | ||
|
|
60734bdb2b | ||
|
|
e71b19424b | ||
|
|
daac0169d5 | ||
|
|
baacc0df52 | ||
|
|
c6921536f7 | ||
|
|
4abf0ad2b2 | ||
|
|
379d555d35 | ||
|
|
8c01acb8d2 | ||
|
|
2c2c3c21ba | ||
|
|
50fd27e07b | ||
|
|
3309035814 | ||
|
|
b691758fa9 | ||
|
|
7c9afcec8b | ||
|
|
06ac05526a | ||
|
|
69cef8249a | ||
|
|
473df16a5a | ||
|
|
e1abf0528c | ||
|
|
ef0b335f67 | ||
|
|
1a866a3dc4 | ||
|
|
ed437b9e05 | ||
|
|
eea85872fd | ||
|
|
9d33e4cd5a | ||
|
|
530cc8d2a2 | ||
|
|
9baca84825 | ||
|
|
58538e4822 | ||
|
|
e31a8dc407 | ||
|
|
7875263092 | ||
|
|
de3b8509bf | ||
|
|
a19e1acfff | ||
|
|
e613b5c624 | ||
|
|
ccfddb0685 | ||
|
|
b8cd679679 | ||
|
|
fc26e472ab | ||
|
|
fc8c7349d6 | ||
|
|
a4d9b8df17 | ||
|
|
f26da68aa4 | ||
|
|
144182b540 | ||
|
|
a834ca4921 | ||
|
|
d1fc216836 | ||
|
|
5e57338928 | ||
|
|
f3376b6f0e | ||
|
|
5e001fdd9d | ||
|
|
9fda06276c | ||
|
|
df79c306d9 | ||
|
|
e4955e6851 | ||
|
|
0fec9e7ac4 | ||
|
|
5be8bb435b | ||
|
|
35b915ab10 | ||
|
|
80c57e996d | ||
|
|
511293d580 | ||
|
|
fe2b816447 | ||
|
|
093b7dc1e8 | ||
|
|
811fa57cbc | ||
|
|
359ad20a6a | ||
|
|
ac9989e4ff | ||
|
|
7268551737 | ||
|
|
823b1974bb | ||
|
|
382f636206 | ||
|
|
9a1b4abcf9 | ||
|
|
a0fc57687b | ||
|
|
02897f982f | ||
|
|
07a5d0ed0a | ||
|
|
017995ade6 | ||
|
|
9711b2280c | ||
|
|
619331916f | ||
|
|
d7909f7312 | ||
|
|
22674f2b46 | ||
|
|
845736c489 | ||
|
|
501f9db465 | ||
|
|
8dd440a582 | ||
|
|
dd7f090b4b | ||
|
|
dc14a2677b | ||
|
|
8b1ed7f0ae | ||
|
|
19b01b404d | ||
|
|
ec780d2d4d | ||
|
|
07790f6711 | ||
|
|
f72d2b6c67 | ||
|
|
e35d631012 | ||
|
|
3499a08207 | ||
|
|
0ac23e512e | ||
|
|
1852fabcd2 | ||
|
|
7b6bfac7cb | ||
|
|
e72aa5fb79 | ||
|
|
f4b02b92cc | ||
|
|
39edcc560f | ||
|
|
50669a320c | ||
|
|
d22c0b05ef | ||
|
|
689be30803 | ||
|
|
b393a83d38 | ||
|
|
1a1339da6b | ||
|
|
9926b51da0 | ||
|
|
761447dea3 | ||
|
|
829c20ba8a | ||
|
|
9ac734e191 | ||
|
|
5420fc6c51 | ||
|
|
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 |
No files matched your search
@@ -0,0 +1,223 @@
|
||||
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@v4
|
||||
- name: CPU Information
|
||||
run: lscpu || sysctl -a|grep cpu || echo "CPU information not available"
|
||||
- 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@v4
|
||||
- name: update package list
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
run: sudo apt-get install gcc-multilib g++-multilib
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- 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@v4
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- 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 -j4 || make CC="/tmp/tcc/bin/tcc -std=c99" check -j2 || make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_linux_sanitize:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make sanitize
|
||||
working-directory: ./tests
|
||||
run: make sanitize -j 2
|
||||
|
||||
build_windows_mingw:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- 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@v4
|
||||
- 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@v4
|
||||
- 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@v4
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat clang-cl
|
||||
|
||||
# The host should always be linux
|
||||
build_freebsd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
usesh: true
|
||||
run: |
|
||||
freebsd-version
|
||||
cd tests
|
||||
make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror" && make clean && make check -j 2 CC="cc -std=c11 -Wno-unknown-warning-option -Werror" LDFLAGS="-lstdthreads" && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_aarch64:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on aarch64
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: aarch64
|
||||
distro: bullseye
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apt-get update -q -y
|
||||
apt-get install -q -y build-essential git gcc
|
||||
lscpu
|
||||
cd tests && make check -j 2 && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_armv6:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on armv6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on armv6
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: armv6
|
||||
distro: alpine_latest
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apk update
|
||||
apk add build-base gcc make
|
||||
cd tests && make check -j 2 && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_riscv64:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on riscv64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on riscv64
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: riscv64
|
||||
distro: ubuntu22.04
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apt-get update -q -y
|
||||
apt-get install -q -y build-essential git gcc
|
||||
lscpu
|
||||
cd tests && make check -j 2 && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_ppc64le:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on ppc64le
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Run commands on ppc64le
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
arch: ppc64le
|
||||
distro: ubuntu22.04
|
||||
# Not required, but speeds up builds
|
||||
githubToken: ${{ github.token }}
|
||||
shell: /bin/sh
|
||||
run: |
|
||||
apt-get update -q -y
|
||||
apt-get install -q -y build-essential git gcc
|
||||
lscpu
|
||||
cd tests && make check -j 2 && make clean
|
||||
@@ -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@v3
|
||||
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@v2
|
||||
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@v2
|
||||
@@ -36,3 +36,15 @@ depend
|
||||
|
||||
# Others
|
||||
other/
|
||||
a*.dat
|
||||
config
|
||||
config.*
|
||||
*.log
|
||||
.vscode
|
||||
.vs
|
||||
tmp-serial.*
|
||||
*~
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
*.synt
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2018, Patrick Pelissier
|
||||
Copyright (c) 2017-2025, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,8 +1,49 @@
|
||||
PREFIX=/usr/local
|
||||
# Copyright (c) 2017-2025, 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
|
||||
|
||||
.PHONY: all test check doc clean distclean depend depend.png install
|
||||
# Installation directory
|
||||
PREFIX=/usr/local
|
||||
DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.8.1
|
||||
|
||||
# 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-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-list.h m-thread.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h m-queue.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 doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh
|
||||
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/ex11-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 example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c example/ex-bptree02.c example/ex-i-list.c example/ex11-generic02.c example/ex11-small-name.c example/ex11-variant01.c example/ex11-use-pool.c
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.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-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.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-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/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 tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp tests/test-mtry.c tests/tgen-mmap.c tests/tgen-try.c tests/tgen-tuple.c tests/test-mgeneric.c tests/test-mbstring.c tests/except-array.c tests/except-bitset.c tests/except-deque.c tests/except-list.c tests/except-string.c tests/test-mshared-ptr.c tests/test-mshared-ptr.h tests/test-obj-except.h tests/test-mqueue.c
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
all:
|
||||
@echo "Nothing to be done."
|
||||
@@ -13,25 +54,64 @@ 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 depend.dot
|
||||
$(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
|
||||
|
||||
depend.png:
|
||||
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 depend.png
|
||||
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
|
||||
@@ -1,324 +0,0 @@
|
||||
CC=cc -std=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
CPPFLAGS=-I..
|
||||
N=4
|
||||
BENCH_DEF=
|
||||
|
||||
.PHONY: all 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-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
|
||||
|
||||
all: container queue mempool string plain
|
||||
|
||||
#########################################################################
|
||||
|
||||
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
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
mempool: bench-mempool
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
string: bench-string
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
plain: bench-plain
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
|
||||
bench-mlib:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -pthread bench-mlib.c -o bench-mlib.exe
|
||||
@./bench-mlib.exe 10
|
||||
@./bench-mlib.exe 20
|
||||
@./bench-mlib.exe 30
|
||||
@./bench-mlib.exe 40
|
||||
@./bench-mlib.exe 41
|
||||
@./bench-mlib.exe 42
|
||||
@./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
|
||||
@./bench-mlib-mempool.exe 10
|
||||
@./bench-mlib-mempool.exe 20
|
||||
@./bench-mlib-mempool.exe 30
|
||||
@./bench-mlib-mempool.exe 40
|
||||
@./bench-mlib-mempool.exe 41
|
||||
@./bench-mlib-mempool.exe 42
|
||||
@./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
|
||||
@./bench-mlib-thread.exe 60
|
||||
@./bench-mlib-thread.exe 61
|
||||
|
||||
bench-stl:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) bench-stl.cpp -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 43
|
||||
@./bench-stl.exe 50
|
||||
@./bench-stl.exe 51
|
||||
|
||||
# QT shall point to the the directory containing the file .pc are stored
|
||||
bench-qt:
|
||||
@if test -n "$${QT}" ; then $(MAKE) bench-qt0 ; else echo "Nothing to be done for QT." ; fi
|
||||
bench-qt0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp -o bench-qt.exe
|
||||
@./bench-qt.exe 10
|
||||
@./bench-qt.exe 20
|
||||
@./bench-qt.exe 30
|
||||
@./bench-qt.exe 40
|
||||
@./bench-qt.exe 41
|
||||
@./bench-qt.exe 42
|
||||
@./bench-qt.exe 50
|
||||
|
||||
# GLIB shall point to the the directory containing the file .pc are stored
|
||||
bench-glib:
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-glib0 ; else echo "Nothing to be done for GLIB." ; fi
|
||||
bench-glib0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-glib.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
|
||||
@./bench-glib.exe 40
|
||||
@./bench-glib.exe 41
|
||||
@./bench-glib.exe 50
|
||||
|
||||
# KLIB shall point to the directory where the headers are
|
||||
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
|
||||
@./bench-klib.exe 10
|
||||
@./bench-klib.exe 20
|
||||
@./bench-klib.exe 30
|
||||
@./bench-klib.exe 40
|
||||
@./bench-klib.exe 41
|
||||
@./bench-klib.exe 50
|
||||
|
||||
# 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
|
||||
@./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
|
||||
@./bench-sparsepp.exe 41
|
||||
@./bench-sparsepp.exe 42
|
||||
@./bench-sparsepp.exe 43
|
||||
|
||||
# DENSEHASHMAP shall point to the directory where the src are
|
||||
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
|
||||
@./bench-densehashmap.exe 41
|
||||
@./bench-densehashmap.exe 42
|
||||
@./bench-densehashmap.exe 43
|
||||
|
||||
# COLLECTIONC shall point to the directory where the 'src' directory is.
|
||||
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
|
||||
@./bench-collectionc.exe 10
|
||||
@./bench-collectionc.exe 20
|
||||
@./bench-collectionc.exe 30
|
||||
@./bench-collectionc.exe 40
|
||||
@./bench-collectionc.exe 41
|
||||
@./bench-collectionc.exe 50
|
||||
|
||||
# TOMMYDS shall point to the source directory.
|
||||
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
|
||||
@./bench-tommyds.exe 10
|
||||
@./bench-tommyds.exe 20
|
||||
@./bench-tommyds.exe 30
|
||||
@./bench-tommyds.exe 40
|
||||
@./bench-tommyds.exe 41
|
||||
|
||||
# FLATHASHMAP shall point to the directory where the headers are
|
||||
bench-flathashmap:
|
||||
@if test -n "$${FLATHASHMAP}" ; then $(MAKE) bench-flathashmap0 ; else echo "Nothing to be done for FLATHASHMAP." ; fi
|
||||
|
||||
bench-flathashmap0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(CPPFLAGS) -I "$${FLATHASHMAP}" bench-flathashmap.cpp -o bench-flathashmap.exe
|
||||
@./bench-flathashmap.exe 41
|
||||
@./bench-flathashmap.exe 42
|
||||
@./bench-flathashmap.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
|
||||
@./bench-hopscotchmap.exe 41
|
||||
@./bench-hopscotchmap.exe 42
|
||||
@./bench-hopscotchmap.exe 43
|
||||
|
||||
# UTHASH shall point to the directory where the source are
|
||||
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
|
||||
@./bench-uthash.exe 10
|
||||
@./bench-uthash.exe 20
|
||||
@./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.
|
||||
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
|
||||
@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
|
||||
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
|
||||
@./bench-libsrt.exe 20
|
||||
@./bench-libsrt.exe 41
|
||||
@./bench-libsrt.exe 42
|
||||
@./bench-libsrt.exe 43
|
||||
@./bench-libsrt.exe 50
|
||||
|
||||
|
||||
# LIBLFDS shall point to the directory where the bin/build/inc/obj/src directories are
|
||||
# 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
|
||||
@LD_LIBRARY_PATH="$${LIBLFDS}/bin:$${LD_LIBRARY_PATH}" ./bench-liblfds.exe 60
|
||||
|
||||
|
||||
# CONCURRENTQUEUE shall point to the directory where the bin/build/inc/obj/src directories are
|
||||
# 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
|
||||
@./bench-concurrentqueue.exe 60
|
||||
|
||||
|
||||
# XXHASH shall point to the source directory of xxhash
|
||||
bench-xxhash:
|
||||
@if test -n "$${XXHASH}" ; then $(MAKE) bench-xxhash0 ; else echo "Nothing to be done for XXHASH." ; fi
|
||||
bench-xxhash0:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I "$${XXHASH}/" bench-xxhash.c "$${XXHASH}/libxxhash.a" -o bench-xxhash.exe
|
||||
@./bench-xxhash.exe 70
|
||||
|
||||
# BOOST shall point to the header location.
|
||||
bench-boost:
|
||||
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
|
||||
bench-boost0:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp -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) $(CPPFLAGS) -I "$${NEDTRIES}" bench-nedtries.c -o bench-nedtries.exe
|
||||
@./bench-nedtries.exe 40
|
||||
@./bench-nedtries.exe 45
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-plain:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) bench-plain-c.c -o bench-plain-c.exe
|
||||
@./bench-plain-c.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mempool:
|
||||
@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) $(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
|
||||
@./bench-max-dict.exe
|
||||
|
||||
############################################################################
|
||||
|
||||
# BSTRLIB shall point to the BSTRLIB sources
|
||||
# LIBSRT shall point to the LIBSRT sources
|
||||
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
|
||||
|
||||
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-exe:
|
||||
$(CXX) $(CFLAGS) $(CPPFLAGS) -I "$${BSTRLIB}" -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string.cpp -o bench-string.exe $(BENCH_DEF)
|
||||
@./bench-string.exe
|
||||
|
||||
|
||||
############################################################################
|
||||
|
||||
clean:
|
||||
rm -f *.o bench-*.exe bench-*.s *~ massif.out.*
|
||||
cd nucleotide && $(MAKE) clean
|
||||
|
||||
############################################################################
|
||||
|
||||
massif-do: all
|
||||
@valgrind --tool=massif ./bench-mlib.exe $(N)
|
||||
@valgrind --tool=massif ./bench-mlib-mempool.exe $(N)
|
||||
@valgrind --tool=massif ./bench-stl.exe $(N)
|
||||
@valgrind --tool=massif ./bench-qt.exe $(N)
|
||||
@valgrind --tool=massif ./bench-glib.exe $(N)
|
||||
@test -f ./bench-klib.exe && valgrind --tool=massif ./bench-klib.exe $(N)
|
||||
@test -f ./bench-libdynamic.exe && valgrind --tool=massif ./bench-libdynamic.exe $(N)
|
||||
|
||||
massif-visu:
|
||||
test -f massif.out.* || $(MAKE) massif-do
|
||||
for i in massif.out.* ; do ms_print $$i|head -30 ; done
|
||||
@@ -1,98 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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;
|
||||
|
||||
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++) {
|
||||
while (!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++) {
|
||||
while (!g_buff.pop(j));
|
||||
s += j;
|
||||
}
|
||||
while (!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++) {
|
||||
while (!g_buff.push(r));
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "array.h"
|
||||
#include "slist.h"
|
||||
#include "treetable.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
Array *a1, *a2;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = array_new(&a1);
|
||||
if (stat != CC_OK) abort();
|
||||
stat = array_new(&a2);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
stat = array_add(a1, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
stat = array_add(a2, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
void *e, *f;
|
||||
stat = array_get_at(a1, i, &e);
|
||||
if (stat != CC_OK) abort();
|
||||
stat = array_get_at(a2, i, &f);
|
||||
if (stat != CC_OK) abort();
|
||||
s += ((unsigned int)(uintptr_t) e) * ((unsigned int)(uintptr_t) f);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
array_destroy(a1);
|
||||
array_destroy(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
SList *a1, *a2;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = slist_new(&a1);
|
||||
if (stat != CC_OK) abort();
|
||||
stat = slist_new(&a2);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
stat = slist_add(a1, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
stat = slist_add(a2, (void*) (uintptr_t)rand_get() );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
SListIter iter1, iter2;
|
||||
void *e, *f;
|
||||
slist_iter_init(&iter1, a1);
|
||||
slist_iter_init(&iter2, a2);
|
||||
while (slist_iter_next(&iter1, &e) == CC_OK && slist_iter_next(&iter2, &f) == CC_OK) {
|
||||
s += ((unsigned int)(uintptr_t) e) * ((unsigned int)(uintptr_t) f);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
slist_destroy(a1);
|
||||
slist_destroy(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int compare(const void *a, const void *b)
|
||||
{
|
||||
const uintptr_t pa = (uintptr_t) a;
|
||||
const uintptr_t pb = (uintptr_t) b;
|
||||
return (pa < pb) ? -1 : (pa > pb);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
TreeTable *tree;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = treetable_new(compare, &tree);
|
||||
if (stat != CC_OK) abort();
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *key = (void*)(uintptr_t) i;
|
||||
stat = treetable_add(tree, key, key);
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *e;
|
||||
void *key = (void*) (uintptr_t) rand_get();
|
||||
stat = treetable_get(tree, key, &e);
|
||||
if (stat == CC_OK)
|
||||
s += (uintptr_t)e;
|
||||
}
|
||||
g_result = s;
|
||||
treetable_destroy(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static size_t hash_func (const void *key, int l, uint32_t seed)
|
||||
{
|
||||
const unsigned long pa = (uintptr_t) key;
|
||||
(void)l;
|
||||
return pa ^ seed;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
{
|
||||
HashTable *dict;
|
||||
enum cc_stat stat;
|
||||
HashTableConf htc;
|
||||
hashtable_conf_init(&htc);
|
||||
htc.hash = hash_func;
|
||||
htc.key_compare = equal_func;
|
||||
stat = hashtable_new_conf(&htc, &dict);
|
||||
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();
|
||||
stat = hashtable_add(dict, key, value );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
void *key = (void*)(uintptr_t) rand_get();
|
||||
void *r;
|
||||
stat = hashtable_get(dict, key, &r);
|
||||
if (stat == CC_OK)
|
||||
s += (uintptr_t) r;
|
||||
}
|
||||
g_result = s;
|
||||
hashtable_destroy(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static size_t char_hash(const void *a, int l, uint32_t seed)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char *s = *pa;
|
||||
(void)l ;
|
||||
size_t hash = seed;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
HashTable *dict;
|
||||
enum cc_stat stat;
|
||||
HashTableConf htc;
|
||||
hashtable_conf_init(&htc);
|
||||
htc.hash = char_hash;
|
||||
htc.key_compare = char_equal;
|
||||
stat = hashtable_new_conf(&htc, &dict);
|
||||
if (stat != CC_OK) abort();
|
||||
|
||||
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));
|
||||
sprintf(*key, "%u", rand_get());
|
||||
sprintf(*value, "%u", rand_get());
|
||||
stat = hashtable_add(dict, key, value );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
void *r;
|
||||
sprintf(s1, "%u", rand_get());
|
||||
stat = hashtable_get(dict, s1, &r);
|
||||
if (stat == CC_OK)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
hashtable_destroy(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int cmp_float(const void * a, const void *b)
|
||||
{
|
||||
const float *const*pa = a, *const*pb = b;
|
||||
return (**pa < **pb) ? -1 : (**pa > **pb);
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
Array *a1;
|
||||
enum cc_stat stat;
|
||||
|
||||
stat = array_new(&a1);
|
||||
if (stat != CC_OK) abort();
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
float *v = malloc(sizeof(float));
|
||||
*v = rand_get();
|
||||
stat = array_add(a1, v );
|
||||
if (stat != CC_OK) abort();
|
||||
}
|
||||
array_sort(a1, cmp_float);
|
||||
void *e;
|
||||
stat = array_get_at(a1, 0, &e);
|
||||
if (stat != CC_OK) abort();
|
||||
g_result = *(float*)e;
|
||||
array_destroy(a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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;
|
||||
|
||||
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++) {
|
||||
while (!g_final.try_dequeue(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++) {
|
||||
while (!g_buff.try_dequeue(j));
|
||||
s += j;
|
||||
}
|
||||
while (!g_final.try_enqueue(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++) {
|
||||
while (!g_buff.try_enqueue(r));
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
#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 <google/dense_hash_map>
|
||||
|
||||
using google::dense_hash_map;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
{
|
||||
dense_hash_map<unsigned long, unsigned long> dict;
|
||||
dict.set_empty_key(-1);
|
||||
dict.set_deleted_key(-2);
|
||||
|
||||
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++) {
|
||||
dense_hash_map<unsigned long, unsigned long>::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;
|
||||
};
|
||||
};
|
||||
namespace tr1 {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(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(unsigned long n)
|
||||
{
|
||||
dense_hash_map<char_array_s, char_array_s> dict;
|
||||
struct char_array_s empty, del;
|
||||
memset(&empty, 0, sizeof empty); empty.a[1] = 255;
|
||||
memset(&del, 0, sizeof del); del.a[1] = 255;
|
||||
dict.set_empty_key(empty);
|
||||
dict.set_deleted_key(del);
|
||||
|
||||
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());
|
||||
dense_hash_map<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
{
|
||||
dense_hash_map<string, string> dict;
|
||||
string empty, del;
|
||||
empty = "";
|
||||
del = "DEL";
|
||||
dict.set_empty_key(empty);
|
||||
dict.set_deleted_key(del);
|
||||
|
||||
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();
|
||||
dense_hash_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
// Need recent gcc
|
||||
#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 "flat_hash_map.hpp"
|
||||
|
||||
using namespace ska;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
{
|
||||
flat_hash_map<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++) {
|
||||
flat_hash_map<unsigned long, unsigned long>::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;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
flat_hash_map<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());
|
||||
flat_hash_map<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
{
|
||||
flat_hash_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();
|
||||
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();
|
||||
flat_hash_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
GArray *a1, *a2;
|
||||
a1 = g_array_new (FALSE, FALSE, sizeof (unsigned int));
|
||||
a2 = g_array_new (FALSE, FALSE, sizeof (unsigned int));
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
g_array_append_val(a1, v );
|
||||
v = rand_get();
|
||||
g_array_append_val(a2, v );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += g_array_index(a1, unsigned int, i ) * g_array_index(a2, unsigned int, i );
|
||||
}
|
||||
g_result = s;
|
||||
g_array_free(a1, FALSE);
|
||||
g_array_free(a2, FALSE);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
GSList *a1 = NULL, *a2 = NULL;
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1 = g_slist_prepend (a1, GINT_TO_POINTER (rand_get() ));
|
||||
a2 = g_slist_prepend (a2, GINT_TO_POINTER (rand_get() ));
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(GSList *it1 = a1, *it2 = a2 ; it1 != NULL; it1 = g_slist_next(it1), it2 = g_slist_next(it2) ) {
|
||||
s += GPOINTER_TO_INT(it1->data) * GPOINTER_TO_INT(it2->data);
|
||||
n--;
|
||||
}
|
||||
g_result = s;
|
||||
g_slist_free(a1);
|
||||
g_slist_free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int compare(gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
(void) user_data;
|
||||
return (*pa < *pb) ? -1 : (*pa > *pb);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
GTree *tree = g_tree_new_full(compare, NULL, free, NULL);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
// NOTE: unsigned long are not designed to work with GPOINTER_TO_INT according to documentation.
|
||||
unsigned long *p = malloc(sizeof(unsigned long));
|
||||
*p = rand_get();
|
||||
g_tree_insert(tree, p, p);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long *p = g_tree_lookup(tree, &key);
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
g_tree_destroy(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static guint hash_func (gconstpointer a)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
return *pa;
|
||||
}
|
||||
|
||||
static gboolean equal_func(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
return *pa == *pb;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
{
|
||||
GHashTable *dict = g_hash_table_new_full(hash_func, equal_func, free, free);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *key = malloc(sizeof(unsigned long));
|
||||
unsigned long *value = malloc(sizeof(unsigned long));
|
||||
*key = rand_get();
|
||||
*value = rand_get();
|
||||
g_hash_table_insert(dict, key, value );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
unsigned long *p = g_hash_table_lookup(dict, &key);
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
g_hash_table_destroy(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
static gboolean char_equal (gconstpointer a, gconstpointer 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;
|
||||
}
|
||||
|
||||
static guint char_hash(gconstpointer a)
|
||||
{
|
||||
const char_array_t *pa = (const char_array_t *)a;
|
||||
const char *s = *pa;
|
||||
guint hash = 0;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
GHashTable *dict = g_hash_table_new_full(char_hash, char_equal, free, free);
|
||||
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));
|
||||
sprintf(*key, "%u", rand_get());
|
||||
sprintf(*value, "%u", rand_get());
|
||||
g_hash_table_insert(dict, key, value );
|
||||
}
|
||||
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 = g_hash_table_lookup(dict, &s1);
|
||||
if (p)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
g_hash_table_destroy(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static gint cmp_float(gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const float *pa = a, *pb = b;
|
||||
return (*pa < *pb) ? -1 : (*pa > *pb);
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
GArray *a1 = g_array_new (FALSE, FALSE, sizeof (float));
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
float v = rand_get();
|
||||
g_array_append_val(a1, v );
|
||||
}
|
||||
g_array_sort(a1, cmp_float);
|
||||
g_result = g_array_index (a1, float, 0);
|
||||
g_array_free(a1, FALSE);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
#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 "src/hopscotch_map.h"
|
||||
|
||||
using namespace tsl;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
{
|
||||
tsl::hopscotch_map<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++) {
|
||||
hopscotch_map<unsigned long, unsigned long>::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;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
hopscotch_map<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());
|
||||
hopscotch_map<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
{
|
||||
hopscotch_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();
|
||||
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();
|
||||
hopscotch_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "kvec.h"
|
||||
#include "klist.h"
|
||||
#include "kbtree.h"
|
||||
#include "khash.h"
|
||||
#include "ksort.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
kvec_t(unsigned int) a1, a2;
|
||||
|
||||
kv_init(a1);
|
||||
kv_init(a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
kv_push(unsigned int, a1, rand_get() );
|
||||
kv_push(unsigned int, a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += kv_A(a1, i ) * kv_A(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kv_destroy(a1);
|
||||
kv_destroy(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define uint_free(x)
|
||||
KLIST_INIT(list_uint, unsigned int, uint_free)
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
klist_t(list_uint) *a1, *a2;
|
||||
a1 = kl_init(list_uint);
|
||||
a2 = kl_init(list_uint);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
*kl_pushp (list_uint, a1) = rand_get();
|
||||
*kl_pushp (list_uint, a2) = rand_get();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
kliter_t(list_uint) *it1, *it2;
|
||||
for(it1 = kl_begin(a1), it2 = kl_begin(a2);
|
||||
it1 != kl_end(a1);
|
||||
it1 = kl_next(it1), it2 = kl_next(it2)) {
|
||||
s += kl_val(it1) * kl_val(it2);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kl_destroy(list_uint, a1);
|
||||
kl_destroy(list_uint, a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define my_cmp(a,b) ( (a) < (b) ? -1 : (a) > (b) )
|
||||
|
||||
KBTREE_INIT(kTree, unsigned long, my_cmp)
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
kbtree_t(kTree) *tree;
|
||||
tree = kb_init(kTree, KB_DEFAULT_SIZE/2);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
kb_putp(kTree, tree, &j);
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = 0;
|
||||
if (kb_getp(kTree, tree, &j) != 0)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
kb_destroy(kTree, tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define hash_eq(a, b) ((a) == (b))
|
||||
#define hash_func(a) kh_int64_hash_func(a)
|
||||
|
||||
KHASH_INIT(iun, unsigned long, unsigned long, 1, hash_func, hash_eq)
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
{
|
||||
khash_t(iun) *dict = kh_init(iun);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
int ret;
|
||||
khiter_t k = kh_put(iun, dict, rand_get(), &ret);
|
||||
kh_value(dict, k) = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
khiter_t k = kh_get(iun, dict, rand_get());
|
||||
if (kh_exist(dict, k))
|
||||
s += kh_value(dict, k);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kh_destroy(iun, dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
static inline void char_init (char_array_t *a) { a->a[0] = 0; }
|
||||
static inline void char_set (char_array_t *a, const char_array_t b) { strcpy(a->a, b.a); }
|
||||
static inline bool char_equal_p (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.a)==0; }
|
||||
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;
|
||||
}
|
||||
|
||||
KHASH_INIT(iub, char_array_t, char_array_t, 1, char_hash, char_equal_p)
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
khash_t(iub) *dict = kh_init(iub);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
int ret;
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
khiter_t k = kh_put(iub, dict, s1, &ret);
|
||||
char_set(&kh_value(dict, k), 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());
|
||||
khiter_t k = kh_get(iub, dict, s1);
|
||||
if (kh_exist(dict, k))
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
kh_destroy(iub, dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
// NOTE: Needed for compiling
|
||||
double drand48(void) { return rand_get(); }
|
||||
|
||||
KSORT_INIT_GENERIC(float)
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
kvec_t(float) a1;
|
||||
|
||||
kv_init(a1);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
kv_push(float, a1, rand_get() );
|
||||
}
|
||||
// NOTE: Is-it the right way to do? Seems very low level!
|
||||
ks_introsort_float(n, & kv_A(a1, 0));
|
||||
g_result = kv_A(a1, 0);
|
||||
kv_destroy(a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dynamic.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vector a1, a2;
|
||||
|
||||
vector_construct(&a1, sizeof(unsigned int));
|
||||
vector_construct(&a2, sizeof(unsigned int));
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
vector_push_back(&a1, &v);
|
||||
v = rand_get();
|
||||
vector_push_back(&a2, &v);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned int*) vector_at(&a1, i) * *(unsigned int*) vector_at(&a2, i);
|
||||
}
|
||||
g_result = s;
|
||||
vector_destruct(&a1, NULL);
|
||||
vector_destruct(&a2, NULL);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static size_t hash_func (void *a)
|
||||
{
|
||||
return hash_data(a, sizeof (unsigned long));
|
||||
}
|
||||
|
||||
static int equal_func(void *a, void *b)
|
||||
{
|
||||
const unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
return *pa == *pb;
|
||||
}
|
||||
|
||||
static void set_func(void *a, void *b)
|
||||
{
|
||||
unsigned long *pa = a;
|
||||
const unsigned long *pb = b;
|
||||
*pa = *pb;
|
||||
}
|
||||
|
||||
typedef struct map_element map_element;
|
||||
struct map_element
|
||||
{
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
{
|
||||
map dict;
|
||||
map_construct(&dict, sizeof(map_element), (map_element[]) {{.key = -1}}, 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);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
map_element *p = map_at(&dict, (map_element[]){{.key = rand_get()}}, hash_func, equal_func);
|
||||
if (p)
|
||||
s += p->value;
|
||||
}
|
||||
g_result = s;
|
||||
map_destruct(&dict, NULL, NULL);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
static int char_equal (void *a, 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;
|
||||
}
|
||||
|
||||
static size_t char_hash(void *a)
|
||||
{
|
||||
char_array_t *pa = (char_array_t *)a;
|
||||
return hash_string(*pa);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
typedef struct big_map_element big_map_element;
|
||||
struct big_map_element
|
||||
{
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
map dict;
|
||||
big_map_element empty;
|
||||
strcpy(empty.key, "");
|
||||
strcpy(empty.value, "");
|
||||
map_construct(&dict, sizeof(big_map_element), &empty, 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);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
big_map_element el;
|
||||
sprintf(el.key, "%u", rand_get());
|
||||
big_map_element *p = map_at(&dict, &el, char_hash, char_equal);
|
||||
if (p)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
map_destruct(&dict, NULL, NULL);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "liblfds711.h"
|
||||
|
||||
#include "m-mutex.h"
|
||||
#define MULTI_THREAD_MEASURE
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct lfds711_queue_bmm_state g_buff;
|
||||
struct lfds711_queue_bmm_state g_final;
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
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);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
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);
|
||||
s += j;
|
||||
}
|
||||
int rv;
|
||||
do {
|
||||
rv = lfds711_queue_bmm_enqueue(&g_final, (void*)(uintptr_t)s, NULL);
|
||||
} while (rv == 0);
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = arg;
|
||||
size_t n = *p_n;
|
||||
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);
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(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();
|
||||
// Init
|
||||
const size_t size = m_core_roundpow2(64*cpu_count);
|
||||
struct lfds711_queue_bmm_element g_buff_elements[size];
|
||||
struct lfds711_queue_bmm_element g_final_elements[size];
|
||||
lfds711_queue_bmm_init_valid_on_current_logical_core(&g_buff, g_buff_elements,
|
||||
size, NULL);
|
||||
lfds711_queue_bmm_init_valid_on_current_logical_core(&g_final, g_final_elements,
|
||||
size, NULL);
|
||||
|
||||
// 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);
|
||||
|
||||
// Clear & quit
|
||||
lfds711_queue_bmm_cleanup(&g_final, NULL);
|
||||
lfds711_queue_bmm_cleanup(&g_buff, NULL);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "svector.h"
|
||||
#include "smap.h"
|
||||
#include "smset.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
sv_push(&a1, &value );
|
||||
value = rand_get();
|
||||
sv_push(&a2, &value );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned int*)sv_at(a1, i ) * *(unsigned int *)sv_at(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
sv_free(&a1);
|
||||
sv_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
/* There is no 'unsigned long' key in smset */
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int cmp_float (const void *a, const void *b)
|
||||
{
|
||||
const float *pa=a;
|
||||
const float *pb = b;
|
||||
return (*pa < *pb) ? -1 : *pa > *pb;
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
sv_t *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 );
|
||||
}
|
||||
sv_sort(a1);
|
||||
g_result = *(float*)sv_at(a1, 0);
|
||||
sv_free(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,520 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.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 "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(array_uint, unsigned int)
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
M_LET(a1, a2, ARRAY_OPLIST(array_uint)) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
array_uint_push_back(a1, rand_get() );
|
||||
array_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *array_uint_cget(a1, i ) * *array_uint_cget(a2, i );
|
||||
}
|
||||
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)))
|
||||
#else
|
||||
LIST_DEF(list_uint, unsigned int)
|
||||
#endif
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
list_uint_mempool_init(list_mpool);
|
||||
#endif
|
||||
M_LET(a1, a2, LIST_OPLIST(list_uint)) {
|
||||
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;
|
||||
list_uint_it_t it1, it2;
|
||||
for(list_uint_it(it1, a1), list_uint_it(it2,a2); !list_uint_end_p(it1); list_uint_next(it1), list_uint_next(it2)) {
|
||||
s += *list_uint_cref(it1) * *list_uint_cref(it2);
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
#ifdef USE_MEMPOOL
|
||||
list_uint_mempool_clear(list_mpool);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
RBTREE_DEF(rbtree_ulong, unsigned long, (MEMPOOL( rbtree_mpool), MEMPOOL_LINKAGE(static)))
|
||||
#else
|
||||
RBTREE_DEF(rbtree_ulong, unsigned long)
|
||||
#endif
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
rbtree_ulong_mempool_init(rbtree_mpool);
|
||||
#endif
|
||||
M_LET(tree, RBTREE_OPLIST(rbtree_ulong)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
rbtree_ulong_push(tree, rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *p = rbtree_ulong_get(tree, rand_get());
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
#ifdef USE_MEMPOOL
|
||||
rbtree_ulong_mempool_clear(rbtree_mpool);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#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
|
||||
DICT_DEF2(dict_ulong, unsigned long, M_DEFAULT_OPLIST, unsigned long, M_DEFAULT_OPLIST)
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_dict(unsigned long 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 key = rand_get();
|
||||
dict_ulong_set_at(dict, key, rand_get() );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *p = dict_ulong_get(dict, rand_get());
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_ulong_list_pair_mempool_clear(dict_mpool);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static inline bool oor_equal_p(unsigned long k, unsigned char n)
|
||||
{
|
||||
return k == (unsigned long)n;
|
||||
}
|
||||
|
||||
static inline void oor_set(unsigned long *k, unsigned char n)
|
||||
{
|
||||
*k = (unsigned long)n;
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_oa_ulong,
|
||||
unsigned long, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
unsigned long, M_DEFAULT_OPLIST)
|
||||
|
||||
static void
|
||||
test_dict_oa(unsigned long n)
|
||||
{
|
||||
M_LET(dict, DICT_OPLIST(dict_oa_ulong)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict_oa_ulong_set_at(dict, rand_get(), rand_get() );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *p = dict_oa_ulong_get(dict, rand_get());
|
||||
if (p)
|
||||
s += *p;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
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))
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
DICT_STOREHASH_DEF2(dict_char, char_array_t, M_OPEXTEND(CHAR_OPLIST,MEMPOOL(dict_mpool2), MEMPOOL_LINKAGE(static)), char_array_t, CHAR_OPLIST)
|
||||
#else
|
||||
DICT_STOREHASH_DEF2(dict_char, char_array_t, CHAR_OPLIST, char_array_t, CHAR_OPLIST)
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_char_list_pair_mempool_init(dict_mpool2);
|
||||
#endif
|
||||
M_LET(dict, DICT_OPLIST(dict_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_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_char_get(dict, s1);
|
||||
if (p)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_char_list_pair_mempool_clear(dict_mpool2);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#ifdef USE_MEMPOOL
|
||||
DICT_DEF2(dict_str, string_t, M_OPEXTEND(STRING_OPLIST, MEMPOOL(dict_mpool3), MEMPOOL_LINKAGE(static)), string_t, STRING_OPLIST)
|
||||
#else
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
{
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_str_list_pair_mempool_init(dict_mpool3);
|
||||
#endif
|
||||
M_LET(s1, s2, STRING_OPLIST)
|
||||
M_LET(dict, DICT_OPLIST(dict_str)) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string_printf(s1, "%u", rand_get());
|
||||
string_printf(s2, "%u", rand_get());
|
||||
dict_str_set_at(dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string_printf(s1, "%u", rand_get());
|
||||
string_t *p = dict_str_get(dict, s1);
|
||||
if (p)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
#ifdef USE_MEMPOOL
|
||||
dict_str_list_pair_mempool_clear(dict_mpool3);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(array_float, float)
|
||||
ALGO_DEF(array_float, ARRAY_OPLIST(array_float))
|
||||
|
||||
static void test_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_sort(a1);
|
||||
g_result = *array_float_get(a1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
BUFFER_DEF(buffer_uint, unsigned int, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
|
||||
buffer_uint_t g_buff;
|
||||
|
||||
BUFFER_DEF(buffer_ull, unsigned long long, 0, BUFFER_QUEUE|BUFFER_BLOCKING)
|
||||
buffer_ull_t g_final;
|
||||
|
||||
static void final(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);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(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);
|
||||
s += j;
|
||||
}
|
||||
buffer_ull_push(g_final, s);
|
||||
}
|
||||
|
||||
static void prod(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 );
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_buffer(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;
|
||||
}
|
||||
// Init
|
||||
buffer_uint_init(g_buff, 64*cpu_count);
|
||||
buffer_ull_init (g_final, 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);
|
||||
}
|
||||
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);
|
||||
|
||||
// Clear & quit
|
||||
buffer_ull_clear(g_final);
|
||||
buffer_uint_clear(g_buff);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE)
|
||||
queue_uint_t g_buff2;
|
||||
|
||||
QUEUE_MPMC_DEF(queue_ull, unsigned long long, BUFFER_QUEUE)
|
||||
queue_ull_t g_final2;
|
||||
|
||||
static void final2(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));
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso2(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));
|
||||
s += j;
|
||||
}
|
||||
while (!queue_ull_push(g_final2, s));
|
||||
}
|
||||
|
||||
static void prod2(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 ));
|
||||
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 Queue performance.\n");
|
||||
return;
|
||||
}
|
||||
// Init
|
||||
queue_uint_init(g_buff2, 64*cpu_count);
|
||||
queue_ull_init (g_final2, 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);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso2, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final2, &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_ull_clear(g_final2);
|
||||
queue_uint_clear(g_buff2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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)
|
||||
{
|
||||
M_HASH_DECL(hash);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
M_HASH_UP(hash, g_p[i]);
|
||||
g_result = M_HASH_FINAL(hash);
|
||||
}
|
||||
|
||||
static void test_core_hash(size_t n)
|
||||
{
|
||||
g_result = m_core_hash(g_p, n*sizeof(unsigned long));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
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 == 51)
|
||||
test_function("Stable Sort time", 10000000, test_stable_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();
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#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(unsigned long 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(unsigned long 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);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 40)
|
||||
test_function("Dict time", 1000000, test_dict);
|
||||
if (n == 45)
|
||||
test_function("Dict No Alloc time", 1000000, test_dict_noalloc);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
// Inspired by: http://stackoverflow.com/questions/3664272/is-stdvector-so-much-slower-than-plain-arrays/3664349#3664349
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-mempool.h"
|
||||
#include "m-string.h"
|
||||
|
||||
unsigned long g_result;
|
||||
|
||||
static unsigned long long
|
||||
cputime (void)
|
||||
{
|
||||
struct rusage rus;
|
||||
getrusage (0, &rus);
|
||||
return rus.ru_utime.tv_sec * 1000000ULL + rus.ru_utime.tv_usec;
|
||||
}
|
||||
|
||||
struct Pixel
|
||||
{
|
||||
unsigned char r, g, b;
|
||||
};
|
||||
|
||||
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT)) )
|
||||
|
||||
void UseMlib(void)
|
||||
{
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
for(int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int dimension = 999;
|
||||
|
||||
array_pixel_t pixels;
|
||||
array_pixel_init(pixels);
|
||||
array_pixel_reserve(pixels, dimension * dimension);
|
||||
|
||||
for(int i = 0; i < dimension * dimension; ++i)
|
||||
{
|
||||
const struct Pixel p = { 255, 0, 0};
|
||||
array_pixel_push_back (pixels, p);
|
||||
}
|
||||
|
||||
array_pixel_clear(pixels);
|
||||
}
|
||||
unsigned long long t2 = cputime();
|
||||
printf ("M*Lib Array: %Lu us\n", (t2-t1)/1000);
|
||||
}
|
||||
|
||||
void UseNative(void)
|
||||
{
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
for(int i = 0; i < 1000; ++i)
|
||||
{
|
||||
int dimension = 999;
|
||||
|
||||
struct Pixel * pixels = malloc(sizeof(struct Pixel) * dimension * dimension);
|
||||
|
||||
for(int i = 0 ; i < dimension * dimension; ++i)
|
||||
{
|
||||
pixels[i].r = 255;
|
||||
pixels[i].g = 0;
|
||||
pixels[i].b = 0;
|
||||
}
|
||||
|
||||
free(pixels);
|
||||
}
|
||||
unsigned long long t2 = cputime();
|
||||
printf ("Native Array: %Lu us\n", (t2-t1)/1000);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UseNative();
|
||||
UseMlib();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "qlibc/qlibc.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
qvector_t *a1 = qvector(16, sizeof(unsigned int), QVECTOR_RESIZE_DOUBLE);
|
||||
if (!a1) abort();
|
||||
qvector_t *a2 = qvector(16, sizeof(unsigned int), QVECTOR_RESIZE_DOUBLE);
|
||||
if (!a2) abort();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
bool success = a1->addlast(a1, &v);
|
||||
if (!success) abort();
|
||||
v = rand_get();
|
||||
success = a2->addlast(a2, &v);
|
||||
if (!success) abort();
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned int*)a1->getat(a1, i, false) * *(unsigned int *) a2->getat(a2, i, false);
|
||||
}
|
||||
g_result = s;
|
||||
a1->free(a1);
|
||||
a2->free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
qlist_t *a1 = qlist(0);
|
||||
qlist_t *a2 = qlist(0);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int u = rand_get(), v = rand_get();
|
||||
a1->addlast(a1, &u, sizeof(unsigned int));
|
||||
a2->addlast(a2, &v, sizeof(unsigned int));
|
||||
}
|
||||
unsigned int s = 0;
|
||||
qlist_obj_t it1, it2;
|
||||
memset(&it1, 0, sizeof (it1));
|
||||
memset(&it2, 0, sizeof (it2));
|
||||
while (a1->getnext(a1, &it1, false) == true
|
||||
&& a2->getnext(a2, &it2, false) == true) {
|
||||
s += *(unsigned int*)it1.data * *(unsigned int*)it2.data;
|
||||
}
|
||||
g_result = s;
|
||||
a1->free(a1);
|
||||
a2->free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static int compare(const void *key1, size_t size1,
|
||||
const void *key2, size_t size2)
|
||||
{
|
||||
assert(size1 == sizeof(unsigned long));
|
||||
assert(size2 == sizeof(unsigned long));
|
||||
const unsigned long *pa = key1;
|
||||
const unsigned long *pb = key2;
|
||||
return (*pa < *pb) ? -1 : (*pa > *pb);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
qtreetbl_t *tree = qtreetbl(0);
|
||||
tree->set_compare(tree, compare);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long v = rand_get();
|
||||
tree->put_by_obj(tree,
|
||||
&v, sizeof(unsigned long), /* key */
|
||||
&v, sizeof(unsigned long) /* value */ );
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long v = rand_get();
|
||||
void *obj = tree->get_by_obj(tree, (const char*)&v, sizeof(unsigned long), NULL, 0);
|
||||
if (obj)
|
||||
s += *(unsigned long*)obj;
|
||||
}
|
||||
g_result = s;
|
||||
tree->free(tree);
|
||||
}
|
||||
|
||||
/* qlibc hash functions only accept a string as the key */
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <QLinkedList>
|
||||
#include <QVector>
|
||||
#include <QSet>
|
||||
#include <QMap>
|
||||
#include <QHash>
|
||||
#include <QtAlgorithms>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
QLinkedList<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 (QLinkedList<unsigned int>::const_iterator ci1 = a1.begin(), ci2 = a2.begin (); ci1 != a1.end(); ++ci1, ++ci2) {
|
||||
s += *ci1 * *ci2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
QVector<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(unsigned long i = 0; i < n; i++) {
|
||||
s += a1[i] * a2[i];
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
/* NOTE: QSet doesn't perform full ordering. I can't find any container
|
||||
which is a set with total ordering within Qt. So we have to fake it. */
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
QMap<unsigned long, QHashDummyValue> tree;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
tree[rand_get()] = QHashDummyValue();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
QMap<unsigned long, QHashDummyValue>::iterator it = tree.find(rand_get());
|
||||
if (it != tree.end())
|
||||
s += it.key();
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict1(unsigned long n)
|
||||
{
|
||||
QMap<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++) {
|
||||
QMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it.value();
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
{
|
||||
QHash<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++) {
|
||||
QHash<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it.value();
|
||||
}
|
||||
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; }
|
||||
};
|
||||
|
||||
uint qHash(const char_array_s &k)
|
||||
{
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
QHash<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());
|
||||
QHash<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
QVector<float> a1;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
}
|
||||
qSort(a1.begin(), a1.end());
|
||||
g_result = a1[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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
#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 <sparsepp/spp.h>
|
||||
|
||||
using spp::sparse_hash_map;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
{
|
||||
sparse_hash_map<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++) {
|
||||
sparse_hash_map<unsigned long, unsigned long>::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;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
sparse_hash_map<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());
|
||||
sparse_hash_map<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long n)
|
||||
{
|
||||
sparse_hash_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();
|
||||
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();
|
||||
sparse_hash_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
#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>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
list<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 (list<unsigned int>::const_iterator ci1 = a1.begin(), ci2 = a2.begin (); ci1 != a1.end(); ++ci1, ++ci2) {
|
||||
s += *ci1 * *ci2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vector<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(unsigned long i = 0; i < n; i++) {
|
||||
s += a1[i] * a2[i];
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set<unsigned long> tree;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
tree.insert(rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set<unsigned long>::iterator it = tree.find(rand_get());
|
||||
if (it != tree.end())
|
||||
s += *it;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict1(unsigned long n)
|
||||
{
|
||||
map<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++) {
|
||||
map<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(unsigned long n)
|
||||
{
|
||||
unordered_map<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++) {
|
||||
unordered_map<unsigned long, unsigned long>::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;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
unordered_map<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());
|
||||
unordered_map<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(unsigned long 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();
|
||||
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();
|
||||
unordered_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_str2(unsigned long 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();
|
||||
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();
|
||||
map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vector<float> a1;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
}
|
||||
sort(a1.begin(), a1.end());
|
||||
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];
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
if (n == 51)
|
||||
test_function("Stable Sort time", 10000000, test_stable_sort);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,602 +0,0 @@
|
||||
/*
|
||||
* This source file is part of the bstring string library as cppbench.cpp
|
||||
* The bstring string library is written by Paul Hsieh in 2002-2015,
|
||||
* and is covered by the BSD open source license. See :
|
||||
* * https://github.com/websnarf/bstrlib
|
||||
* * http://bstring.sourceforge.net/
|
||||
* * http://prdownloads.sourceforge.net/bstring/examples-09282006.zip?download
|
||||
|
||||
Copyright (c) 2014, Paul Hsieh
|
||||
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.
|
||||
|
||||
* Neither the name of bstrlib nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Update of integrating M*LIB done by Patrick Pelissier */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
#define NDEBUG
|
||||
#include "m-string.h"
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
#include "bstrlib.h"
|
||||
#include "bstrwrap.h"
|
||||
#include "bstraux.h"
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_LIBSRT
|
||||
#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.
|
||||
*/
|
||||
#if defined (BENCH_CAN_USE_STL)
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#define TEST_SECONDS (5)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#define TESTSTRING1 ("<sometag name=\"John Doe\" position=\"Executive VP Marketing\"/>")
|
||||
|
||||
#if defined (BENCH_CAN_USE_STL)
|
||||
int testSTL_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
std::string b;
|
||||
c += b.length () ^ i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSTL_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
std::string b (TESTSTRING1);
|
||||
c += b.length () ^ i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSTL_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
std::string b;
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
b = TESTSTRING1;
|
||||
c += b.length () ^ i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSTL_extraction (int count) {
|
||||
int i, c = 0;
|
||||
std::string b (TESTSTRING1);
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
c += b[(i & 7)];
|
||||
c += b[(i & 7) ^ 8];
|
||||
c += b.c_str()[(i & 7) ^ 4] ^ i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSTL_scan (int count) {
|
||||
int i, c = 0;
|
||||
std::string b ("Dot. 123. Some more data.");
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
c += b.find ('.');
|
||||
c += b.find ("123");
|
||||
c += b.find_first_of ("sm") ^i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSTL_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
std::string a (TESTSTRING1);
|
||||
std::string accum;
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
accum = "";
|
||||
for (i=0; i < 250; i++) {
|
||||
accum += a;
|
||||
accum += "!!";
|
||||
c += accum.length() ^i;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSTL_replace (int count) {
|
||||
int j, c = 0;
|
||||
std::string a (TESTSTRING1);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
a.replace (11, 4, "XXXXXX");
|
||||
a.replace (23, 2, "XXXXXX");
|
||||
a.replace ( 4, 8, "XX");
|
||||
c += a.length () ^ j;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
int testCBS_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
CBString b;
|
||||
c += b.length ()^i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testCBS_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (i=0; i < count; i++) {
|
||||
CBString b (TESTSTRING1);
|
||||
c += b.length () ^i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testCBS_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
CBString b;
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
b = TESTSTRING1;
|
||||
c += b.length () ^i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testCBS_extraction (int count) {
|
||||
int i, c = 0;
|
||||
CBString b (TESTSTRING1);
|
||||
|
||||
for (i=0; i < count; i++) {
|
||||
c += b[(i & 7)];
|
||||
c += b[(i & 7) ^ 8];
|
||||
c += ((const char *)b)[(i & 7) ^ 4] ^i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testCBS_scan (int count) {
|
||||
int i, c = 0;
|
||||
CBString b ("Dot. 123. Some more data.");
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += b.find ('.');
|
||||
c += b.find ("123");
|
||||
c += b.findchr ("sm") ^i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testCBS_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
CBString a (TESTSTRING1);
|
||||
CBString accum;
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
accum = "";
|
||||
for (i=0; i < 250; i++) {
|
||||
accum += a;
|
||||
accum += "!!";
|
||||
c+= accum.length() ^i;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testCBS_replace (int count) {
|
||||
int j, c = 0;
|
||||
CBString a (TESTSTRING1);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
a.replace (11, 4, "XXXXXX");
|
||||
a.replace (23, 2, "XXXXXX");
|
||||
a.replace ( 4, 8, "XX");
|
||||
c += a.length () ^j;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_LIBSRT
|
||||
int testSRT_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
ss_t *b = ss_alloc(0);
|
||||
c += ss_size(b) ^i;
|
||||
ss_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSRT_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
ss_t *b = ss_dup_c(TESTSTRING1);
|
||||
c += ss_size(b) ^i;
|
||||
ss_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSRT_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
ss_t *b = ss_alloc(0);
|
||||
for (c=i=0; i < count; i++) {
|
||||
ss_cpy_cn(&b, TESTSTRING1, strlen(TESTSTRING1));
|
||||
c += ss_size(b) ^i;
|
||||
}
|
||||
ss_free(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSRT_extraction (int count) {
|
||||
int i, c = 0;
|
||||
ss_t *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;
|
||||
}
|
||||
ss_free(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testSRT_scan (int count) {
|
||||
int i, c = 0;
|
||||
ss_t *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;
|
||||
}
|
||||
ss_free(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int testSRT_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
ss_t *a = ss_dup_c(TESTSTRING1);
|
||||
ss_t *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);
|
||||
c += ss_size(accum) ^i;
|
||||
}
|
||||
}
|
||||
ss_free(&a);
|
||||
ss_free(&accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
int testMLIB_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init(b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_set_str(b, TESTSTRING1);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init(b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_set_str(b, TESTSTRING1);
|
||||
c += string_size(b) ^i;
|
||||
}
|
||||
string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
string_t b;
|
||||
string_init_set_str(b, TESTSTRING1);
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_get_char(b, (i & 7));
|
||||
c += string_get_char(b, (i & 7) ^ 8);
|
||||
c += string_get_char(b, (i & 7) ^ 4) ^i;
|
||||
}
|
||||
string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_scan (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init_set_str(b, "Dot. 123. Some more data.");
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_search_char (b, '.');
|
||||
c += string_search_str (b, "123");
|
||||
c += string_search_pbrk (b, "sm") ^i;
|
||||
}
|
||||
string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int testMLIB_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
string_t a, accum;
|
||||
string_init_set_str(a, TESTSTRING1);
|
||||
string_init (accum);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
string_set_str(accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
string_cat(accum, a);
|
||||
string_cat_str(accum, "!!");
|
||||
c += string_size(accum) ^i;
|
||||
}
|
||||
}
|
||||
string_clear(a);
|
||||
string_clear(accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_replace (int count) {
|
||||
int j, c = 0;
|
||||
string_t a;
|
||||
string_init_set_str(a, TESTSTRING1);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
string_replace_at(a, 11, 4, "XXXXXX");
|
||||
string_replace_at(a, 23, 2, "XXXXXX");
|
||||
string_replace_at(a, 4, 8, "XX");
|
||||
c += string_size(a) ^j;
|
||||
}
|
||||
|
||||
string_clear(a);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NTESTS 7
|
||||
struct flags {
|
||||
int runtest[NTESTS];
|
||||
};
|
||||
|
||||
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);
|
||||
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_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);
|
||||
}
|
||||
#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);
|
||||
}
|
||||
#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);
|
||||
}
|
||||
#endif
|
||||
return c;
|
||||
}
|
||||
|
||||
int main (int argc, char * argv[]) {
|
||||
struct flags runflags;
|
||||
int i, j;
|
||||
|
||||
for (i=0; i < NTESTS; i++) runflags.runtest[i] = argc < 2;
|
||||
for (i=1; i < argc; i++) {
|
||||
if (1 == sscanf (argv[i], "%d", &j)) {
|
||||
if (j >= 1 && j <= NTESTS) runflags.runtest[j-1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
benchTest (&runflags);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tommyds/tommy.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
tommy_array a1, a2;
|
||||
|
||||
tommy_array_init(&a1);
|
||||
tommy_array_init(&a2);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v = rand_get();
|
||||
tommy_array_insert(&a1, (void*)(uintptr_t) v);
|
||||
v = rand_get();
|
||||
tommy_array_insert(&a2, (void*)(uintptr_t) v);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += (uintptr_t) *tommy_array_ref(&a1, i) * (uintptr_t) *tommy_array_ref(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
tommy_array_done(&a1);
|
||||
tommy_array_done(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct list_node_s {
|
||||
unsigned int value;
|
||||
tommy_node node;
|
||||
};
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
tommy_list a1, a2;
|
||||
|
||||
tommy_list_init(&a1);
|
||||
tommy_list_init(&a2);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
struct list_node_s *obj;
|
||||
obj = malloc(sizeof(struct list_node_s));
|
||||
if (obj == NULL) abort();
|
||||
obj->value = rand_get();
|
||||
tommy_list_insert_tail(&a1, &obj->node, obj);
|
||||
obj = malloc(sizeof(struct list_node_s));
|
||||
if (obj == NULL) abort();
|
||||
obj->value = rand_get();
|
||||
tommy_list_insert_tail(&a2, &obj->node, obj);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(tommy_node *it1 = tommy_list_head(&a1), *it2 = tommy_list_head(&a2)
|
||||
; it1 != NULL; it1 = it1->next, it2 = it2->next ) {
|
||||
struct list_node_s *obj1 = it1->data, *obj2 = it2->data;
|
||||
s += obj1->value * obj2->value;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_list_foreach(&a1, free);
|
||||
tommy_list_foreach(&a2, free);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct tree_node_s {
|
||||
unsigned long value;
|
||||
tommy_tree_node node;
|
||||
} ;
|
||||
|
||||
static int compare(const void *a, const void *b)
|
||||
{
|
||||
const struct tree_node_s *pa = a;
|
||||
const struct tree_node_s *pb = b;
|
||||
return (pa->value < pb->value) ? -1 : (pa->value > pb->value);
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
tommy_tree tree;
|
||||
tommy_tree_init(&tree, compare);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct tree_node_s *obj = malloc(sizeof(struct tree_node_s));
|
||||
if (obj == NULL) abort();
|
||||
obj->value = rand_get();
|
||||
tommy_tree_insert(&tree, &obj->node, obj);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct tree_node_s key = { .value = rand_get() };
|
||||
struct tree_node_s *obj = tommy_tree_search (&tree, &key);
|
||||
if (obj)
|
||||
s += obj->value;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_tree_foreach(&tree, free);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct hash_i_node_s {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
tommy_node node;
|
||||
};
|
||||
|
||||
static inline size_t hash_func (const unsigned long key)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
static int equal_func(const void* arg, const void *obj_p)
|
||||
{
|
||||
const struct hash_i_node_s *obj = obj_p;
|
||||
const unsigned long *key = arg;
|
||||
return *key != obj->key;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
{
|
||||
tommy_hashlin dict;
|
||||
tommy_hashlin_init(&dict);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct hash_i_node_s *obj = malloc(sizeof (struct hash_i_node_s));
|
||||
if(!obj) abort();
|
||||
obj->key = rand_get();
|
||||
obj->value = rand_get();
|
||||
tommy_hashlin_insert(&dict, &obj->node, obj, hash_func(obj->key));
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
struct hash_i_node_s *obj = tommy_hashlin_search(&dict, &equal_func,
|
||||
&key,
|
||||
hash_func(key));
|
||||
if (obj)
|
||||
s += obj->value;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_hashlin_done(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef char char_array_t[256];
|
||||
|
||||
struct hash_b_node_s {
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
tommy_node node;
|
||||
};
|
||||
|
||||
static int char_equal (const void *arg, const void *obj_p)
|
||||
{
|
||||
const struct hash_b_node_s *obj = obj_p;
|
||||
const char_array_t *key = (const char_array_t *)arg;
|
||||
return strcmp(*key, (obj->key));
|
||||
}
|
||||
|
||||
static size_t char_hash(const char *s)
|
||||
{
|
||||
size_t hash = 0;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
tommy_hashlin dict;
|
||||
tommy_hashlin_init(&dict);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
struct hash_b_node_s *obj = malloc(sizeof (struct hash_b_node_s));
|
||||
if(!obj) abort();
|
||||
sprintf(obj->key, "%u", rand_get());
|
||||
sprintf(obj->value, "%u", rand_get());
|
||||
/* NOTE: this is not an insert_or_replace func...
|
||||
It will always insert a new node, even if the key already exists...
|
||||
Maybe searching then inserting will be a better representative?
|
||||
*/
|
||||
tommy_hashlin_insert(&dict, &obj->node, obj, char_hash(obj->key));
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1, "%u", rand_get());
|
||||
struct hash_b_node_s *obj = tommy_hashlin_search(&dict, &char_equal,
|
||||
&s1,
|
||||
char_hash(s1));
|
||||
if (obj)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
tommy_hashlin_done(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/uthash.h"
|
||||
#include "include/utarray.h"
|
||||
#include "include/utlist.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static const UT_icd int_icd = {
|
||||
.sz = sizeof (unsigned int),
|
||||
.init = NULL,
|
||||
.dtor = NULL,
|
||||
.copy = NULL
|
||||
};
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
UT_array a1, a2;
|
||||
|
||||
utarray_init(&a1, &int_icd);
|
||||
utarray_init(&a2, &int_icd);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int v1 = rand_get(), v2 = rand_get();
|
||||
utarray_push_back(&a1, &v1);
|
||||
utarray_push_back(&a2, &v2);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *(unsigned long *) utarray_eltptr(&a1, i ) * *(unsigned long *)utarray_eltptr(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
utarray_done(&a1);
|
||||
utarray_done(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct list_node_s {
|
||||
unsigned int value;
|
||||
struct list_node_s *next;
|
||||
};
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
struct list_node_s *a1 = NULL, *a2 = NULL;
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
struct list_node_s *p = malloc(sizeof(struct list_node_s));
|
||||
if (!p) abort();
|
||||
p->value = rand_get();
|
||||
LL_PREPEND(a1, p);
|
||||
p = malloc(sizeof(struct list_node_s));
|
||||
if (!p) abort();
|
||||
p->value = rand_get();
|
||||
LL_PREPEND(a2, p);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(struct list_node_s *it1 = a1, *it2 = a2
|
||||
; it1 != NULL
|
||||
; it1 = it1->next, it2 = it2->next) {
|
||||
s += it1->value * it2->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
struct list_node_s *el;
|
||||
LL_FOREACH(a1, el) free(el);
|
||||
LL_FOREACH(a2, el) free(el);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
struct hash_i_node_s {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict(unsigned long n)
|
||||
{
|
||||
struct hash_i_node_s *dict = NULL;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long k = rand_get();
|
||||
struct hash_i_node_s *s;
|
||||
HASH_FIND(hh, dict, &k, sizeof (unsigned long), s);
|
||||
if (s == NULL) {
|
||||
s = malloc(sizeof(struct hash_i_node_s));
|
||||
if (!s) abort();
|
||||
s->key = k;
|
||||
s->value = rand_get();
|
||||
HASH_ADD(hh, dict, key, sizeof(unsigned long), s);
|
||||
}
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long k = rand_get();
|
||||
struct hash_i_node_s *sp;
|
||||
HASH_FIND(hh, dict, &k, sizeof (unsigned long), sp);
|
||||
if (sp != NULL)
|
||||
s += sp->value;
|
||||
}
|
||||
g_result = s;
|
||||
struct hash_i_node_s *current, *tmp;
|
||||
HASH_ITER(hh, dict, current, tmp) {
|
||||
HASH_DEL(dict,current); /* delete it (users advances to next) */
|
||||
free(current); /* free it */
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
|
||||
struct hash_b_node_s {
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
static void
|
||||
test_dict_big(unsigned long n)
|
||||
{
|
||||
struct hash_b_node_s *dict = NULL;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t k;
|
||||
sprintf(k.a, "%u", rand_get());
|
||||
struct hash_b_node_s *s;
|
||||
HASH_FIND(hh, dict, &k, sizeof (char_array_t), s);
|
||||
if (s == NULL) {
|
||||
s = malloc(sizeof(struct hash_b_node_s));
|
||||
if (!s) abort();
|
||||
memcpy(s->key.a, k.a, sizeof(s->key));
|
||||
sprintf(s->value.a, "%u", rand_get());
|
||||
HASH_ADD(hh, dict, key, sizeof(char_array_t), s);
|
||||
}
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t k;
|
||||
sprintf(k.a, "%u", rand_get());
|
||||
struct hash_b_node_s *sp;
|
||||
HASH_FIND(hh, dict, &k, sizeof (char_array_t), sp);
|
||||
if (sp != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
struct hash_b_node_s *current, *tmp;
|
||||
HASH_ITER(hh, dict, current, tmp) {
|
||||
HASH_DEL(dict,current); /* delete it (users advances to next) */
|
||||
free(current); /* free it */
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static const UT_icd float_icd = {
|
||||
.sz = sizeof (float),
|
||||
.init = NULL,
|
||||
.dtor = NULL,
|
||||
.copy = NULL
|
||||
};
|
||||
|
||||
static int cmp(const void *a1, const void *a2)
|
||||
{
|
||||
const float *f1 = a1;
|
||||
const float *f2 = a2;
|
||||
return (*f1 < *f2) ? -1 : (*f1 > *f2);
|
||||
}
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
UT_array a1;
|
||||
|
||||
utarray_init(&a1, &float_icd);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
float v1 = rand_get();
|
||||
utarray_push_back(&a1, &v1);
|
||||
}
|
||||
utarray_sort(&a1, cmp);
|
||||
g_result = *(float *)utarray_eltptr(&a1, 0);
|
||||
utarray_done(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
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);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 70) {
|
||||
n = (argc > 2) ? atoi(argv[2]) : 100000000;
|
||||
test_hash_prepare(n);
|
||||
test_function("XXHASH64 time", n, test_hash);
|
||||
test_hash_final();
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2018, 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.
|
||||
*/
|
||||
#ifndef __COMMON_BENCH__H
|
||||
#define __COMMON_BENCH__H
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* WINDOWS variant */
|
||||
#include <windows.h>
|
||||
|
||||
static unsigned long long
|
||||
cputime (void)
|
||||
{
|
||||
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
|
||||
cputime (void)
|
||||
{
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
// Multi thread
|
||||
struct timeval tv;
|
||||
gettimeofday (&tv, NULL);
|
||||
return tv.tv_sec * 1000000ULL + tv.tv_usec;
|
||||
#else
|
||||
// Single thread
|
||||
struct rusage rus;
|
||||
getrusage (0, &rus);
|
||||
return rus.ru_utime.tv_sec * 1000000ULL + rus.ru_utime.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned long g_result;
|
||||
unsigned int randValue = 0;
|
||||
|
||||
static void rand_init(void)
|
||||
{
|
||||
randValue = 0;
|
||||
}
|
||||
static 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))
|
||||
{
|
||||
unsigned long long start, end;
|
||||
rand_init();
|
||||
start = cputime();
|
||||
(*func)(n);
|
||||
end = cputime();
|
||||
end = (end - start) / 1000U;
|
||||
printf ("%s %lu ms for n = %lu [r=%lu]\n", str, (unsigned long) end, (unsigned long) n, g_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>
|
||||
#endif
|
||||
|
||||
/* Return the number of CPU of the system */
|
||||
static inline int get_cpu_count(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
return sysinfo.dwNumberOfProcessors;
|
||||
#elif defined(USE_SYSCTL)
|
||||
int nm[2];
|
||||
int count = 0;
|
||||
size_t len = sizeof (count);
|
||||
nm[0] = CTL_HW;
|
||||
nm[1] = HW_NCPU;
|
||||
sysctl(nm, 2, &count, &len, NULL, 0);
|
||||
return MAX(1, count);
|
||||
#elif defined (_SC_NPROCESSORS_ONLN)
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,344 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
// The Computer Language Benchmarks Game
|
||||
// http://benchmarksgame.alioth.debian.org/
|
||||
//
|
||||
// Original version Contributed by Jeremy Zerfas
|
||||
// M*LIB port contributed by Patrick Pélissier
|
||||
// gcc -O2 -march=native nucleotide.c -I../.. -std=c11 -lpthread -DNDEBUG
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "m-worker.h"
|
||||
#include "m-dict.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
|
||||
|
||||
// Define Open Addressing dictionnary. Need to define how to handle out of bound data.
|
||||
static inline bool oor_equal_p(uint64_t k, unsigned char n)
|
||||
{
|
||||
return k == ~(uint64_t) n;
|
||||
}
|
||||
static inline void oor_set(uint64_t *k, unsigned char n)
|
||||
{
|
||||
*k = ~(uint64_t)n;
|
||||
}
|
||||
// Custom hash function.
|
||||
static inline size_t my_hash(uint64_t key)
|
||||
{
|
||||
return ((key) ^ (key)>>7);
|
||||
}
|
||||
// Define a dictionnary of uint64_t --> uint32_t
|
||||
DICT_OA_DEF2(dict_oligonucleotide,
|
||||
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
uint32_t, M_DEFAULT_OPLIST)
|
||||
// Define oplist of dictionary
|
||||
#define OLIGONUCLEOTIDE_OPLIST DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(oor_hash), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), M_DEFAULT_OPLIST)
|
||||
|
||||
typedef struct {
|
||||
uint64_t key;
|
||||
uint32_t value;
|
||||
} element;
|
||||
|
||||
// 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])
|
||||
|
||||
|
||||
// Function to use when sorting elements with qsort() later. Elements with
|
||||
// larger values will come first and in cases of identical values then elements
|
||||
// with smaller keys will come first.
|
||||
static int element_Compare(const void *a, const void *b)
|
||||
{
|
||||
const element * const left_Element = a;
|
||||
const element * const right_Element = b;
|
||||
// Sort based on element values.
|
||||
if(left_Element->value < right_Element->value) return 1;
|
||||
if(left_Element->value > right_Element->value) return -1;
|
||||
|
||||
// If we got here then both items have the same value so then sort based on
|
||||
// key.
|
||||
return left_Element->key > right_Element->key ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
// Generate frequencies for all oligonucleotides in polynucleotide that are of
|
||||
// desired_Length_For_Oligonucleotides and then save it to output.
|
||||
static void
|
||||
generate_Frequencies_For_Desired_Length_Oligonucleotides(const char polynucleotide[],
|
||||
const int polynucleotide_Length,
|
||||
const int desired_Length_For_Oligonucleotides,
|
||||
char * const output)
|
||||
{
|
||||
assert (2*desired_Length_For_Oligonucleotides <= 64);
|
||||
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
dict_oligonucleotide_init(hash_Table);
|
||||
|
||||
uint64_t key=0;
|
||||
const uint64_t mask=(1ULL<<(2*desired_Length_For_Oligonucleotides))-1;
|
||||
|
||||
// For the first several nucleotides we only need to append them to key in
|
||||
// preparation for the insertion of complete oligonucleotides to hash_Table.
|
||||
for(int i=0; i<desired_Length_For_Oligonucleotides-1; i++)
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
// Add all the complete oligonucleotides of
|
||||
// desired_Length_For_Oligonucleotides to hash_Table and update the count
|
||||
// for each oligonucleotide.
|
||||
for(int i=desired_Length_For_Oligonucleotides-1
|
||||
; i<polynucleotide_Length; i++){
|
||||
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
|
||||
if (p != NULL)
|
||||
(*p) ++;
|
||||
else {
|
||||
dict_oligonucleotide_set_at(hash_Table, key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an array of elements from hash_Table.
|
||||
int elements_Array_Size=dict_oligonucleotide_size(hash_Table), i=0;
|
||||
element * elements_Array=malloc(elements_Array_Size*sizeof(element));
|
||||
if (!elements_Array) abort();
|
||||
for M_EACH(item, hash_Table, OLIGONUCLEOTIDE_OPLIST) {
|
||||
elements_Array[i++]=((element){item->key, item->value});
|
||||
}
|
||||
// Clear the hash table
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
|
||||
// Sort elements_Array.
|
||||
qsort(elements_Array, elements_Array_Size, sizeof(element), element_Compare);
|
||||
|
||||
// Print the frequencies for each oligonucleotide.
|
||||
for(int output_Position=0, i=0; i<elements_Array_Size; i++) {
|
||||
|
||||
// Convert the key for the oligonucleotide to a string.
|
||||
char oligonucleotide[desired_Length_For_Oligonucleotides+1];
|
||||
for(int j=desired_Length_For_Oligonucleotides-1; j>-1; j--){
|
||||
oligonucleotide[j]=NUCLEOTIDE_FOR_CODE(elements_Array[i].key);
|
||||
elements_Array[i].key>>=2;
|
||||
}
|
||||
oligonucleotide[desired_Length_For_Oligonucleotides]='\0';
|
||||
|
||||
// Output the frequency for oligonucleotide to output.
|
||||
output_Position+=snprintf(output+output_Position
|
||||
, MAXIMUM_OUTPUT_LENGTH-output_Position, "%s %.3f\n", oligonucleotide
|
||||
, 100.0f*elements_Array[i].value
|
||||
/(polynucleotide_Length-desired_Length_For_Oligonucleotides+1));
|
||||
}
|
||||
|
||||
free(elements_Array);
|
||||
}
|
||||
|
||||
|
||||
// Generate a count for the number of times oligonucleotide appears in
|
||||
// polynucleotide and then save it to output.
|
||||
static void
|
||||
generate_Count_For_Oligonucleotide(const char * const polynucleotide,
|
||||
const int polynucleotide_Length,
|
||||
const char * const oligonucleotide,
|
||||
char * const output)
|
||||
{
|
||||
const int oligonucleotide_Length=strlen(oligonucleotide);
|
||||
assert (2*oligonucleotide_Length <= 64);
|
||||
|
||||
dict_oligonucleotide_t hash_Table;
|
||||
dict_oligonucleotide_init(hash_Table);
|
||||
|
||||
uint64_t key = 0;
|
||||
const uint64_t mask=(1ULL<<(2*oligonucleotide_Length))-1;
|
||||
|
||||
// For the first several nucleotides we only need to append them to key in
|
||||
// preparation for the insertion of complete oligonucleotides to hash_Table.
|
||||
for(int i=0; i<oligonucleotide_Length-1; i++)
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
// Add all the complete oligonucleotides of oligonucleotide_Length to
|
||||
// hash_Table and update the count for each oligonucleotide.
|
||||
for(int i=oligonucleotide_Length-1; i<polynucleotide_Length; i++){
|
||||
key=(key<<2 & mask) | polynucleotide[i];
|
||||
|
||||
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
|
||||
if (p != NULL)
|
||||
(*p) ++;
|
||||
else {
|
||||
dict_oligonucleotide_set_at(hash_Table, key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the key for oligonucleotide.
|
||||
key=0;
|
||||
for(int i=0; i<oligonucleotide_Length; i++)
|
||||
key=(key<<2) | CODE_FOR_NUCLEOTIDE(oligonucleotide[i]);
|
||||
|
||||
// Output the count for oligonucleotide to output.
|
||||
uint32_t *p = dict_oligonucleotide_get(hash_Table, key);
|
||||
uintmax_t count= p== NULL ? 0 : *p;
|
||||
snprintf(output, MAXIMUM_OUTPUT_LENGTH, "%ju\t%s", count, oligonucleotide);
|
||||
|
||||
dict_oligonucleotide_clear(hash_Table);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
char buffer[MAXIMUM_OUTPUT_LENGTH];
|
||||
worker_t worker;
|
||||
|
||||
// Initialize the different worker threads by auto-detecting the number of cores of the system
|
||||
worker_init(worker, 0, 1, NULL);
|
||||
|
||||
// Find the start of the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stdin) && memcmp(">THREE", buffer
|
||||
, sizeof(">THREE")-1));
|
||||
|
||||
// Start with 1 MB of storage for reading in the polynucleotide and grow
|
||||
// geometrically.
|
||||
int polynucleotide_Capacity=1048576;
|
||||
int polynucleotide_Length=0;
|
||||
char * polynucleotide=malloc(polynucleotide_Capacity);
|
||||
if (!polynucleotide) abort();
|
||||
|
||||
// Start reading and encoding the third polynucleotide.
|
||||
while(fgets(buffer, sizeof(buffer), stdin) && buffer[0]!='>'){
|
||||
for(int i=0; buffer[i]!='\0'; i++)
|
||||
if(buffer[i]!='\n')
|
||||
polynucleotide[polynucleotide_Length++]
|
||||
=CODE_FOR_NUCLEOTIDE(buffer[i]);
|
||||
|
||||
// Make sure we still have enough memory allocated for any potential
|
||||
// nucleotides in the next line.
|
||||
if(polynucleotide_Capacity-polynucleotide_Length<sizeof(buffer)) {
|
||||
polynucleotide=realloc(polynucleotide, polynucleotide_Capacity*=2);
|
||||
if (!polynucleotide) abort();
|
||||
}
|
||||
}
|
||||
|
||||
char output_Buffer[7][MAXIMUM_OUTPUT_LENGTH];
|
||||
char (*output)[MAXIMUM_OUTPUT_LENGTH] = output_Buffer;
|
||||
|
||||
// Do the following functions in parallel.
|
||||
// Define a synchronization block
|
||||
worker_sync_t block;
|
||||
worker_start(block);
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTATTTTAATTTATAGT", output[6]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTATTTTAATT", output[5]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTATT", output[4]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGTA", output[3]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Count_For_Oligonucleotide(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
"GGT", output[2]);
|
||||
}, (/*no output*/));
|
||||
|
||||
WORKER_SPAWN(worker, block, (polynucleotide, polynucleotide_Length, output), {
|
||||
generate_Frequencies_For_Desired_Length_Oligonucleotides(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
2,
|
||||
output[1]);
|
||||
}, (/*no output*/));
|
||||
|
||||
generate_Frequencies_For_Desired_Length_Oligonucleotides(polynucleotide,
|
||||
polynucleotide_Length,
|
||||
1,
|
||||
output[0]);
|
||||
worker_sync(block);
|
||||
|
||||
// Output the results to stdout.
|
||||
for(int i=0; i<7; i++)
|
||||
printf("%s\n", output_Buffer[i]);
|
||||
|
||||
free(polynucleotide);
|
||||
worker_clear(worker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,940 +0,0 @@
|
||||
/**
|
||||
* Memory pool benchmark.
|
||||
*
|
||||
* Results (the better values for each measure from at least 3 runs)for
|
||||
* Intel Core i7-4650U CPU 1.70GHz, 8GB RAM:
|
||||
*
|
||||
* small object size: 24
|
||||
* big object size: 240
|
||||
* huge object size: 8305
|
||||
*
|
||||
* boost::pool (Small): 258ms
|
||||
* boost::pool w/ free (Small): 165ms
|
||||
* boost::pool (Big): 174ms
|
||||
* boost::pool w/ free (Big): 154ms
|
||||
* boost::pool cr. & destr.: 133ms
|
||||
*
|
||||
* ngx_pool (Small): 305ms
|
||||
* ngx_pool (Big): 132ms
|
||||
* ngx_pool w/ free (Mix): 542ms
|
||||
* ngx_pool cr. & destr.: 98ms
|
||||
*
|
||||
* tfw_pool (Small): 279ms
|
||||
* tfw_pool w/ free (Small): 101ms
|
||||
* tfw_pool (Big): 106ms
|
||||
* tfw_pool w/ free (Big): 50ms
|
||||
* tfw_pool w/ free (Mix): 107ms
|
||||
* tfw_pool cr. & destr.: 53ms
|
||||
*
|
||||
* Copyright (C) 2015 Alexander Krizhanovsky (ak@natsys-lab.com).
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* See http://www.gnu.org/licenses/lgpl.html .
|
||||
*
|
||||
* From https://github.com/natsys/blog/tree/master/mempool
|
||||
*/
|
||||
#define NDEBUG
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#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;
|
||||
|
||||
// sizeof(TfwStr)
|
||||
struct Small {
|
||||
long l[3];
|
||||
|
||||
std::string
|
||||
operator+(const char *str)
|
||||
{ return std::string(str) + " (Small)"; }
|
||||
};
|
||||
|
||||
// size of common HTTP headers table
|
||||
struct Big {
|
||||
Small s[10];
|
||||
|
||||
std::string
|
||||
operator+(const char *str)
|
||||
{ return std::string(str) + " (Big)"; }
|
||||
};
|
||||
|
||||
// very big allocation
|
||||
struct Huge {
|
||||
char c[PAGE_SIZE * 2 + 113];
|
||||
|
||||
std::string
|
||||
operator+(const char *str)
|
||||
{ return std::string(str) + " (Huge)"; }
|
||||
};
|
||||
|
||||
static const size_t N = 20 * 1000 * 1000;
|
||||
|
||||
void
|
||||
benchmark(std::string &&desc, std::function<void ()> cb)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
// steady_clock has the same resolution as high_resolution_clock
|
||||
auto t(steady_clock::now());
|
||||
|
||||
cb();
|
||||
|
||||
auto dt = steady_clock::now() - t;
|
||||
std::cout << std::setw(30) << std::right << desc << ": "
|
||||
<< duration_cast<milliseconds>(dt).count()
|
||||
<< "ms" << std::endl;
|
||||
}
|
||||
|
||||
#define touch_obj(o) \
|
||||
if (__builtin_expect(!o, 0)) { \
|
||||
std::cerr << "failed alloc" << std::endl; \
|
||||
break; \
|
||||
} else { \
|
||||
*(long *)o = 1; \
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Boost::pool
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_BOOST
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_boost_pool()
|
||||
{
|
||||
boost::object_pool<T> p;
|
||||
|
||||
benchmark(std::move(T() + "boost::pool"), [&]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = p.malloc();
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_boost_pool_free()
|
||||
{
|
||||
boost::object_pool<T> p;
|
||||
|
||||
benchmark(std::move(T() + "boost::pool w/ free"), [&]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = p.malloc();
|
||||
touch_obj(o);
|
||||
if (__builtin_expect(!(i & 3), 0))
|
||||
p.free(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_boost_pool_create_and_destroy()
|
||||
{
|
||||
benchmark(std::move(std::string("boost::pool cr. & destr.")), []() {
|
||||
for (size_t i = 0; i < N / 100; ++i) {
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
boost::object_pool<Big> p;
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
Big *o = p.malloc();
|
||||
touch_obj(o);
|
||||
}
|
||||
} else {
|
||||
boost::object_pool<Small> p;
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
Small *o = p.malloc();
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* malloc/free
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
template<class T>
|
||||
void
|
||||
benchmark_mallocfree()
|
||||
{
|
||||
benchmark(std::move(T() + "mallocfree"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)malloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
free(ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_mallocfree_free()
|
||||
{
|
||||
benchmark(std::move(T() + "mallocfree w/ free"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)malloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
free(o);
|
||||
ptrs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
free(ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* GLib slices
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef USE_GLIB
|
||||
template<class T>
|
||||
void
|
||||
benchmark_glib_slices()
|
||||
{
|
||||
benchmark(std::move(T() + "GLib slices"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)g_slice_alloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
g_slice_free1(sizeof(T), ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_glib_slices_free()
|
||||
{
|
||||
benchmark(std::move(T() + "GLib slices w/ free"), [&]() {
|
||||
static __thread T *ptrs[N * sizeof(Small) / sizeof(T)];
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T*)g_slice_alloc(sizeof(T));
|
||||
ptrs[i] = o;
|
||||
touch_obj(o);
|
||||
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
g_slice_free1(sizeof(T), o);
|
||||
ptrs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
g_slice_free1(sizeof(T), ptrs[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Nginx pool
|
||||
* Simplified version of src/core/ngx_palloc.c from nginx-1.9.5 with
|
||||
* some code adjustments to be built in this benchmark.
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
struct ngx_pool_t;
|
||||
typedef uintptr_t ngx_uint_t;
|
||||
|
||||
#define NGX_POOL_ALIGNMENT 16
|
||||
#define NGX_ALIGNMENT sizeof(unsigned long)
|
||||
#define ngx_align_ptr(p, a) \
|
||||
(u_char *)(((uintptr_t)(p) + ((uintptr_t)a - 1)) & ~((uintptr_t)a - 1))
|
||||
#define NGX_MAX_ALLOC_FROM_POOL ((size_t)PAGE_SIZE - 1)
|
||||
|
||||
struct ngx_pool_data_t {
|
||||
unsigned char *last;
|
||||
unsigned char *end;
|
||||
ngx_pool_t *next;
|
||||
unsigned int failed;
|
||||
};
|
||||
|
||||
struct ngx_pool_large_t {
|
||||
ngx_pool_large_t *next;
|
||||
void *alloc;
|
||||
};
|
||||
|
||||
struct ngx_pool_t {
|
||||
ngx_pool_data_t d;
|
||||
size_t max;
|
||||
ngx_pool_t *current;
|
||||
ngx_pool_large_t *large;
|
||||
};
|
||||
|
||||
ngx_pool_t *
|
||||
ngx_create_pool(size_t size)
|
||||
{
|
||||
ngx_pool_t *p;
|
||||
|
||||
if (posix_memalign((void **)&p, NGX_POOL_ALIGNMENT, size))
|
||||
return NULL;
|
||||
|
||||
p->d.last = (unsigned char *)p + sizeof(ngx_pool_t);
|
||||
p->d.end = (unsigned char *)p + size;
|
||||
p->d.next = NULL;
|
||||
p->d.failed = 0;
|
||||
|
||||
size = size - sizeof(ngx_pool_t);
|
||||
p->max = (size < NGX_MAX_ALLOC_FROM_POOL)
|
||||
? size : NGX_MAX_ALLOC_FROM_POOL;
|
||||
|
||||
p->current = p;
|
||||
p->large = NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
ngx_destroy_pool(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *p, *n;
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (l->alloc)
|
||||
free(l->alloc);
|
||||
}
|
||||
|
||||
for (p = pool, n = pool->d.next; ; p = n, n = n->d.next) {
|
||||
free(p);
|
||||
if (n == NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
ngx_palloc_block(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
unsigned char *m;
|
||||
size_t psize = (size_t)(pool->d.end - (unsigned char *)pool);
|
||||
ngx_pool_t *p, *p_new;
|
||||
|
||||
if (posix_memalign((void **)&m, NGX_POOL_ALIGNMENT, psize))
|
||||
return NULL;
|
||||
p_new = (ngx_pool_t *)m;
|
||||
|
||||
p_new->d.end = m + psize;
|
||||
p_new->d.next = NULL;
|
||||
p_new->d.failed = 0;
|
||||
|
||||
m += sizeof(ngx_pool_data_t);
|
||||
m = ngx_align_ptr(m, NGX_ALIGNMENT);
|
||||
p_new->d.last = m + size;
|
||||
|
||||
for (p = pool->current; p->d.next; p = p->d.next) {
|
||||
if (p->d.failed++ > 4)
|
||||
pool->current = p->d.next;
|
||||
}
|
||||
p->d.next = p_new;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void *ngx_palloc(ngx_pool_t *pool, size_t size);
|
||||
|
||||
static void *
|
||||
ngx_palloc_large(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
void *p;
|
||||
unsigned int n = 0;
|
||||
ngx_pool_large_t *large;
|
||||
|
||||
p = malloc(size);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
for (large = pool->large; large; large = large->next) {
|
||||
if (large->alloc == NULL) {
|
||||
large->alloc = p;
|
||||
return p;
|
||||
}
|
||||
if (n++ > 3)
|
||||
break;
|
||||
}
|
||||
|
||||
large = (ngx_pool_large_t *)ngx_palloc(pool, sizeof(ngx_pool_large_t));
|
||||
if (large == NULL) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
large->alloc = p;
|
||||
large->next = pool->large;
|
||||
pool->large = large;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
ngx_palloc(ngx_pool_t *pool, size_t size)
|
||||
{
|
||||
unsigned char *m;
|
||||
ngx_pool_t *p;
|
||||
|
||||
if (size <= pool->max) {
|
||||
p = pool->current;
|
||||
do {
|
||||
m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
|
||||
if ((size_t)(p->d.end - m) >= size) {
|
||||
p->d.last = m + size;
|
||||
return m;
|
||||
}
|
||||
p = p->d.next;
|
||||
} while (p);
|
||||
|
||||
return ngx_palloc_block(pool, size);
|
||||
}
|
||||
|
||||
return ngx_palloc_large(pool, size);
|
||||
}
|
||||
|
||||
void
|
||||
ngx_pfree(ngx_pool_t *pool, void *p)
|
||||
{
|
||||
ngx_pool_large_t *l;
|
||||
|
||||
for (l = pool->large; l; l = l->next) {
|
||||
if (p == l->alloc) {
|
||||
free(l->alloc);
|
||||
l->alloc = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_ngx_pool()
|
||||
{
|
||||
ngx_pool_t *p = ngx_create_pool(PAGE_SIZE);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(T() + "ngx_pool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T *)ngx_palloc(p, sizeof(T));
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
|
||||
ngx_destroy_pool(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_ngx_pool_mix_free()
|
||||
{
|
||||
ngx_pool_t *p = ngx_create_pool(PAGE_SIZE);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(std::string("ngx_pool w/ free (Mix)")), [=]() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (__builtin_expect(!(i & 0xfff), 0)) {
|
||||
Huge *o;
|
||||
o = (Huge *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
ngx_pfree(p, o);
|
||||
}
|
||||
else if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o = (Big *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
ngx_pfree(p, o);
|
||||
}
|
||||
else {
|
||||
Small *o = (Small *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
ngx_pfree(p, o);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ngx_destroy_pool(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_ngx_pool_create_and_destroy()
|
||||
{
|
||||
benchmark(std::move(std::string("ngx_pool cr. & destr.")), []() {
|
||||
for (size_t i = 0; i < N / 100; ++i) {
|
||||
ngx_pool_t *p = ngx_create_pool(PAGE_SIZE);
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o;
|
||||
o = (Big *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
} else {
|
||||
Small *o;
|
||||
o = (Small *)ngx_palloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
ngx_destroy_pool(p);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Tempesta FW pool
|
||||
* Simplified and ported to user-space from
|
||||
* https://github.com/natsys/tempesta/blob/master/tempesta_fw/pool.c
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
/**
|
||||
* Emulation of Linux buddy allocator.
|
||||
*/
|
||||
#define GFP_ATOMIC 0
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
#define likely(x) __builtin_expect(x, 1)
|
||||
#define unlikely(x) __builtin_expect(x, 0)
|
||||
#define free_pages(p, o) free((void *)(p))
|
||||
#define get_order(n) (assert((n) < PAGE_SIZE * 128), \
|
||||
(n) < PAGE_SIZE ? 0 \
|
||||
: (n) < PAGE_SIZE * 2 ? 1 \
|
||||
: (n) < PAGE_SIZE * 4 ? 2 \
|
||||
: (n) < PAGE_SIZE * 8 ? 3 \
|
||||
: (n) < PAGE_SIZE * 16 ? 4 \
|
||||
: (n) < PAGE_SIZE * 32 ? 5 \
|
||||
: (n) < PAGE_SIZE * 64 ? 6 \
|
||||
: 7)
|
||||
|
||||
static inline unsigned long
|
||||
__get_free_pages(int flags __attribute__((unused)), int order)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (posix_memalign((void **)&p, PAGE_SIZE, PAGE_SIZE << order))
|
||||
return 0;
|
||||
|
||||
return (unsigned long)p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory pool chunk descriptor.
|
||||
*
|
||||
* @next - pointer to next memory chunk;
|
||||
* @order - order of number of pages in the chunk;
|
||||
* @off - current chunk offset;
|
||||
*/
|
||||
struct TfwPoolChunk {
|
||||
TfwPoolChunk *next;
|
||||
unsigned int order;
|
||||
unsigned int off;
|
||||
};
|
||||
|
||||
/**
|
||||
* Memory pool descriptor.
|
||||
*
|
||||
* @curr - current chunk to allocate memory from;
|
||||
* @order,@off - cached members of @curr;
|
||||
*/
|
||||
typedef struct {
|
||||
TfwPoolChunk *curr;
|
||||
unsigned int order;
|
||||
unsigned int off;
|
||||
} TfwPool;
|
||||
|
||||
#define TFW_POOL_CHUNK_SZ(p) (PAGE_SIZE << (p)->order)
|
||||
#define TFW_POOL_CHUNK_BASE(c) ((unsigned long)(c) & PAGE_MASK)
|
||||
#define TFW_POOL_CHUNK_END(p) (TFW_POOL_CHUNK_BASE((p)->curr) + (p)->off)
|
||||
#define TFW_POOL_ALIGN_SZ(n) (((n) + 7) & ~7UL)
|
||||
#define TFW_POOL_HEAD_OFF (TFW_POOL_ALIGN_SZ(sizeof(TfwPool)) \
|
||||
+ TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)))
|
||||
#define TFW_POOL_PGCACHE_SZ 256
|
||||
|
||||
static unsigned int pg_next;
|
||||
static unsigned long pg_cache[TFW_POOL_PGCACHE_SZ];
|
||||
|
||||
static unsigned long
|
||||
tfw_pool_alloc_pages(unsigned int order)
|
||||
{
|
||||
if (likely(pg_next && !order))
|
||||
return pg_cache[--pg_next];
|
||||
return __get_free_pages(GFP_ATOMIC, order);
|
||||
}
|
||||
|
||||
static void
|
||||
tfw_pool_free_pages(unsigned long addr, unsigned int order)
|
||||
{
|
||||
if (likely(pg_next < TFW_POOL_PGCACHE_SZ && !order)) {
|
||||
pg_cache[pg_next++] = addr;
|
||||
} else {
|
||||
free_pages(addr, order);
|
||||
}
|
||||
}
|
||||
|
||||
TfwPool *
|
||||
__tfw_pool_new(size_t n)
|
||||
{
|
||||
TfwPool *p;
|
||||
TfwPoolChunk *c;
|
||||
unsigned int order;
|
||||
|
||||
order = get_order(TFW_POOL_ALIGN_SZ(n) + TFW_POOL_HEAD_OFF);
|
||||
|
||||
c = (TfwPoolChunk *)tfw_pool_alloc_pages(order);
|
||||
if (unlikely(!c))
|
||||
return NULL;
|
||||
|
||||
p = (TfwPool *)((char *)c + TFW_POOL_ALIGN_SZ(sizeof(*c)));
|
||||
c->next = NULL;
|
||||
|
||||
p->order = order;
|
||||
p->off = TFW_POOL_HEAD_OFF;
|
||||
p->curr = c;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
tfw_pool_alloc(TfwPool *p, size_t n)
|
||||
{
|
||||
void *a;
|
||||
|
||||
n = TFW_POOL_ALIGN_SZ(n);
|
||||
|
||||
if (unlikely(p->off + n > TFW_POOL_CHUNK_SZ(p))) {
|
||||
TfwPoolChunk *c, *curr = p->curr;
|
||||
unsigned int off = TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)) + n;
|
||||
unsigned int order = get_order(off);
|
||||
|
||||
c = (TfwPoolChunk *)tfw_pool_alloc_pages(order);
|
||||
if (!c)
|
||||
return NULL;
|
||||
c->next = curr;
|
||||
|
||||
curr->order = p->order;
|
||||
curr->off = p->off;
|
||||
|
||||
p->order = order;
|
||||
p->off = off;
|
||||
p->curr = c;
|
||||
|
||||
return (void *)TFW_POOL_ALIGN_SZ((unsigned long)(c + 1));
|
||||
}
|
||||
|
||||
a = (char *)TFW_POOL_CHUNK_END(p);
|
||||
p->off += n;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
tfw_pool_free(TfwPool *p, void *ptr, size_t n)
|
||||
{
|
||||
n = TFW_POOL_ALIGN_SZ(n);
|
||||
|
||||
/* Stack-like usage is expected. */
|
||||
if (unlikely((char *)ptr + n != (char *)TFW_POOL_CHUNK_END(p)))
|
||||
return;
|
||||
|
||||
p->off -= n;
|
||||
|
||||
/* Free empty chunk which doesn't contain the pool header. */
|
||||
if (unlikely(p->off == TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)))) {
|
||||
TfwPoolChunk *next = p->curr->next;
|
||||
tfw_pool_free_pages(TFW_POOL_CHUNK_BASE(p->curr), p->order);
|
||||
p->curr = next;
|
||||
p->order = next->order;
|
||||
p->off = next->off;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tfw_pool_destroy(TfwPool *p)
|
||||
{
|
||||
TfwPoolChunk *c, *next;
|
||||
|
||||
for (c = p->curr; c; c = next) {
|
||||
next = c->next;
|
||||
tfw_pool_free_pages(TFW_POOL_CHUNK_BASE(c), c->order);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_tfw_pool()
|
||||
{
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(T() + "tfw_pool"), [=]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T *)tfw_pool_alloc(p, sizeof(T));
|
||||
touch_obj(o);
|
||||
}
|
||||
});
|
||||
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
benchmark_tfw_pool_free()
|
||||
{
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(T() + "tfw_pool w/ free"), [&]() {
|
||||
for (size_t i = 0; i < N * sizeof(Small) / sizeof(T); ++i) {
|
||||
T *o = (T *)tfw_pool_alloc(p, sizeof(T));
|
||||
touch_obj(o);
|
||||
if (__builtin_expect(!(i & 3), 0))
|
||||
tfw_pool_free(p, o, sizeof(T));
|
||||
}
|
||||
});
|
||||
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_tfw_pool_mix_free()
|
||||
{
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
assert(p);
|
||||
|
||||
benchmark(std::move(std::string("tfw_pool w/ free (Mix)")), [=]() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if (__builtin_expect(!(i & 0xfff), 0)) {
|
||||
Huge *o;
|
||||
o = (Huge *)tfw_pool_alloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
tfw_pool_free(p, o, sizeof(*o));
|
||||
}
|
||||
else if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o = (Big *)tfw_pool_alloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
tfw_pool_free(p, o, sizeof(*o));
|
||||
}
|
||||
else {
|
||||
Small *o;
|
||||
o = (Small *)tfw_pool_alloc(p, sizeof(*o));
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_tfw_pool_create_and_destroy()
|
||||
{
|
||||
benchmark(std::move(std::string("tfw_pool cr. & destr.")), []() {
|
||||
for (size_t i = 0; i < N / 100; ++i) {
|
||||
TfwPool *p = __tfw_pool_new(0);
|
||||
for (size_t j = 0; j < 100; ++j) {
|
||||
if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o;
|
||||
o = (Big *)tfw_pool_alloc(p,
|
||||
sizeof(*o));
|
||||
touch_obj(o);
|
||||
} else {
|
||||
Small *o;
|
||||
o = (Small *)tfw_pool_alloc(p,
|
||||
sizeof(*o));
|
||||
touch_obj(o);
|
||||
}
|
||||
}
|
||||
tfw_pool_destroy(p);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* Adding M*LIB mempool */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "m-mempool.h"
|
||||
|
||||
MEMPOOL_DEF(mempool_small, Small)
|
||||
MEMPOOL_DEF(mempool_big, Big)
|
||||
MEMPOOL_DEF(mempool_huge, Huge)
|
||||
|
||||
void
|
||||
benchmark_mempool_small()
|
||||
{
|
||||
mempool_small_t p;
|
||||
mempool_small_init (p);
|
||||
mempool_small_t *ptr = &p; // C++ lambda !
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
mempool_small_clear(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_mempool_big()
|
||||
{
|
||||
mempool_big_t p;
|
||||
mempool_big_init (p);
|
||||
mempool_big_t *ptr = &p; // C++ lambda !
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
mempool_big_clear(p);
|
||||
}
|
||||
|
||||
void
|
||||
benchmark_mempool_mix_free()
|
||||
{
|
||||
mempool_small_t s, *ptr_s = &s;
|
||||
mempool_big_t b, *ptr_b = &b;
|
||||
mempool_huge_t h, *ptr_h = &h;
|
||||
|
||||
mempool_small_init (s);
|
||||
mempool_big_init (b);
|
||||
mempool_huge_init (h);
|
||||
|
||||
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);
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
mempool_huge_free (*ptr_h, o);
|
||||
}
|
||||
else if (__builtin_expect(!(i & 3), 0)) {
|
||||
Big *o = mempool_big_alloc(*ptr_b);
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
mempool_big_free (*ptr_b, o);
|
||||
}
|
||||
else {
|
||||
Small *o = mempool_small_alloc (*ptr_s);
|
||||
touch_obj(o);
|
||||
if (!(i & 1))
|
||||
mempool_small_free (*ptr_s, o);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mempool_small_clear (s);
|
||||
mempool_big_clear (b);
|
||||
mempool_huge_clear (h);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------------------
|
||||
* Main part of the benchmark
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
main()
|
||||
{
|
||||
std::cout << std::setw(35) << std::right << "small object size: "
|
||||
<< sizeof(Small) << std::endl;
|
||||
std::cout << std::setw(35) << std::right << "big object size: "
|
||||
<< sizeof(Big) << std::endl;
|
||||
std::cout << std::setw(35) << std::right << "huge object size: "
|
||||
<< sizeof(Huge) << "\n" << std::endl;
|
||||
|
||||
// Warm up malloc().
|
||||
static const size_t n = N * sizeof(Big);
|
||||
void *p = malloc(n);
|
||||
assert(p);
|
||||
memset(p, 0, n);
|
||||
free(p);
|
||||
|
||||
benchmark_mallocfree<Small>();
|
||||
benchmark_mallocfree_free<Small>();
|
||||
benchmark_mallocfree<Big>();
|
||||
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();
|
||||
benchmark_ngx_pool_create_and_destroy();
|
||||
std::cout << std::endl;
|
||||
|
||||
benchmark_mempool_small();
|
||||
benchmark_mempool_big();
|
||||
benchmark_mempool_mix_free();
|
||||
std::cout << std::endl;
|
||||
|
||||
benchmark_tfw_pool<Small>();
|
||||
benchmark_tfw_pool_free<Small>();
|
||||
benchmark_tfw_pool<Big>();
|
||||
benchmark_tfw_pool_free<Big>();
|
||||
benchmark_tfw_pool_mix_free();
|
||||
benchmark_tfw_pool_create_and_destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 150 KiB |
@@ -0,0 +1,114 @@
|
||||
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.
|
||||
|
||||
V0.6.*: * Rename M_DEFAULT_OPLIST in M_BASIC_OPLIST
|
||||
* Remove experimental macro M_IF_DEFAULT1.
|
||||
* Remove M_INVERT
|
||||
* String functions with _str suffix for C strings have been renamed with _cstr suffix (like string_cat_str ==> m_string_cat_cstr)
|
||||
Note: the compatible layer still keeps the old naming,
|
||||
so except if you are using the prefixed version of the strings
|
||||
or the bounded strings API, you won't need to upgrade your code.
|
||||
|
||||
V0.7.2: * Rename m-mutex.h header in m-thread.h
|
||||
|
||||
V0.7.3 : * DICT_STOREHASH_DEF2 / DICT_STOREHASH_DEF2_AS are deprecated.
|
||||
Use DICT_DEF2 / DICT_DEF2_AS
|
||||
|
||||
V0.8.0 : * Memory interface massive compatibility break to allow more efficient integration of custom allocators.
|
||||
The prototypes of NEW / DEL REALLOC / FREE operators are incompatible:
|
||||
* Add the old number of elements of the array as argument of REALLOC
|
||||
* Add the number of elements of the array and its base type as arguments of FREE.
|
||||
* Add the context argument (which shall be ignored in not specific build)
|
||||
(You can ignore the new arguments which are only hints provided to memory functions).
|
||||
Also impact M_MEMORY_NEW / M_MEMORY_DEL / M_MEMORY_REALLOC & M_MEMORY_FREE
|
||||
M_MEMORY_FULL: replace the failed size allocation size argument into the base type and the number of elements that failed to be allocated.
|
||||
* m-buffer:
|
||||
* non-thread safe queue & stack are moved into their dedicated header (m-queue)
|
||||
* BUFFER_THREAD_UNSAFE policy is no longer supported.
|
||||
* Disabling BUFFER_BLOCKING policy is no longer supported (default policy is now forced).
|
||||
* _push / _pop now returns now void like other containers instead of a bool (it was undocumented)
|
||||
* Remove MEMPOOL support from list & R/B tree
|
||||
* m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove). Use new M_USE_CONTEXT interface to pass local pool context.
|
||||
* M*LIB becomes stricter for the INIT_MOVE operator:
|
||||
The Emulation layer using CLEAR+INIT_SET methods, when there is no INIT_MOVE operator, has been removed:
|
||||
either default INIT_MOVE operator (operator '=') is working, or a method is provided for INIT_MOVE or it is disabled.
|
||||
If it is an array of size 1, you can use M_COPY_A1_DEFAULT as a default method.
|
||||
(It's because supporting emulation layer with new memory context parameter was complicated)
|
||||
* Remove obsole headers: m-c-mempool, m-mempool, m-shared, m-i-shared, -mconcurrent
|
||||
|
||||
V0.8.1 : * m-algo: Update interface of _transform to be more flexible: adding user context pointer, and filtering of the input elements.
|
||||
* m-algo: Update interface of _reduce to be more user friendly: return value indicates if the reduction is empty or not.
|
||||
* m-algo: Rename _map_reduce into _transform_reduce and update its interface to be more flexible: adding user context pointer, and filtering of the input elements and return value indicates if the reduction is empty or not.
|
||||
* Rename _push_raw method by _push_back_raw for all containers (clearer on the semantic)
|
||||
@@ -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
|
||||
@@ -2,39 +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.
|
||||
NOTE: valgrind seems completly lost in all the tests which spawn a lot of threads.
|
||||
|
||||
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.
|
||||
|
||||
6) Publish the release
|
||||
4) Publish the release
|
||||
|
||||
In case of problem, open a problem report.
|
||||
|
||||
List of primary systems
|
||||
=======================
|
||||
|
||||
* 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 6 on windows/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
|
||||
@@ -0,0 +1,820 @@
|
||||
*Long term issues*
|
||||
==========================================================
|
||||
|
||||
* DONE #34 : Pass old size arguments to memory allocator :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
|
||||
Some custom allocators don't store the old size of an object to maximize memory usage
|
||||
used by the allocated objects. On realloc, they need the old size argument.
|
||||
This is inline with the GMP allocator which provides the old size argument.
|
||||
There is no difficulty in the data structure to compute the old size of the object
|
||||
(it is quite easily available).
|
||||
It is needed for REALLOC operator (and FREE)
|
||||
|
||||
** Solution #1
|
||||
|
||||
Add the oldsize argument to the REALLOC and FREE operators.
|
||||
|
||||
** Solution #2
|
||||
|
||||
Create a local variable m_local_old_size before calling the REALLOC or FREE operators
|
||||
Modify GAIA interface to link OLDSIZE patttern to m_local_old_size
|
||||
Need to handle the warnings correctly.
|
||||
|
||||
** Tradeof analysis
|
||||
|
||||
Solution #1 is simpler but breaks API. However custom allocators are not common.
|
||||
Solution #2 keeps API as it is but increases code complexity by adding more hacks into the codebase.
|
||||
|
||||
* TODO #33 : Handling of partially constructed object :ANOMALY:
|
||||
** State
|
||||
|
||||
Support of partially constructed object needs special code to handle it
|
||||
correctly (register a correct cleanup function in case of exception).
|
||||
|
||||
Current containers don't support such features.
|
||||
|
||||
> NOTE:
|
||||
An exception for init_set supposes that the object is *not* initialized.
|
||||
An exception for set supposes that the object *remains* initialized.
|
||||
Some containers perform an init_set using init+set
|
||||
others perform a set using a clear+init_set
|
||||
The property of init_set (resp. set) is broken if an exception is raised in the set (resp. init_set):
|
||||
the object is not let in the expected uninitialized (resp. initialized) state.
|
||||
|
||||
** Actions
|
||||
|
||||
Add such support in M*LIB containers.
|
||||
Need to analyse each function for execption safety.
|
||||
|
||||
It can be difficult. For example, for array _init_set
|
||||
function due to the copy of the object one per one. Each copied sub object
|
||||
may throw an exception, so we always need to have the container in a correct
|
||||
state so that it can be cleanup.
|
||||
|
||||
* DONE #32 : User specialization fields in the container :ENHANCEMENT:
|
||||
** State
|
||||
|
||||
Some methods of a contained object may need to have some options that
|
||||
are neither constant nor global, but are specialized in function of the container.
|
||||
|
||||
For example, a memory handler may need a parameter which is needed to identify
|
||||
which pool of memory has to be used.
|
||||
|
||||
** Plan:
|
||||
|
||||
Add a new operator "CONTEXT" which is a type to be added in the
|
||||
defined container. Then it can be accessed by the operator through an extension
|
||||
of the GAIA by adding support for identification of specialization like this:
|
||||
|
||||
( CONTEXT( memory_pool_ref ),
|
||||
NEW( API(NONE, memory_pool_alloc, CONTEXT, ARG1)),
|
||||
DEL( API(NONE, memory_pool_free, CONTEXT, ARG1)) )
|
||||
|
||||
** Open points:
|
||||
|
||||
- How to get access to the specialization field of the container?
|
||||
==> Define the "self" name as the name of the container for all methods?
|
||||
- What to do when there are several containers for a method?
|
||||
==> self shall be the destination?
|
||||
|
||||
- How to initialize the specialization field of the container? provide custom initialization functions? It seems to be the hard point.
|
||||
Use GAIA interface and a local variable with force naming : m_local_context for example.
|
||||
|
||||
** Proposed Solution:
|
||||
|
||||
New operator USER_CONTEXT created. If operator USER_CONTEXT exist:
|
||||
+ add a USER_CONTEXT user_data in the data structure.
|
||||
+ for INIT & INIT_WITH, add a new parameter to the function to pass the context to initialize
|
||||
+ for INIT_SET & INIT_MOVE & MOVE, initialize it with the source object (FIXME: This may not be what we want for INIT_SET if we want to copy an object from an allocator to another)
|
||||
+ for each functions that use an operator that may use the USER_CONTEXT, add a local variable m_local_context and initialize to the user context
|
||||
==> Limit user context to pointer or integer (Good enough)
|
||||
+ Expand GAIA interface to handle specially the term USER_CONTEXT: if it exists, expands it to m_local_context. The user will therefore be able to expand its operator with the user provided local context.
|
||||
+ Update OPLIST of data structure to change the call to INIT & INIT_WITH to use GAIA/USER_CONTEXT if the basic type has a USER_CONTEXT
|
||||
+ To be checked: EMPLACE_TYPE ?
|
||||
+ Create M_USING_CONTEXT to initialize a local variable m_local_context and initalize it with the user context to be used y the M_LET macro:
|
||||
M_USING_CONTEXT(int *, &y)
|
||||
M_LET(x, object_t) {
|
||||
|
||||
}
|
||||
|
||||
Done in branch feature/user-data-v2 with a full working implementation for array
|
||||
|
||||
** Solution limitation:
|
||||
|
||||
INIT & INIT_WITH interface change for the user. This however is an acceptable limitation.
|
||||
|
||||
Adding a user context to each data structure will increase a lot the size of the data structure in case of recursive data structures: For example, an array of string_t. Each string_t will need a user data context for it to work properly, so we'll need N*sizeof(user data context) memory just to make it work. This becomes even more problematic if we chain more data structures.
|
||||
And in general, we use custom allocators to be faster and use less memory: this will defeat the purpose of custom allocators a lot.
|
||||
|
||||
Another limitation is that string_t / bitset_t are not supported correctly. We can make this change globally but it will prevent mixing different codebase that uses the string_t together (one expects a user context, the other not).
|
||||
|
||||
** Alternative #1
|
||||
|
||||
Passing user context arguments to each function call seems to be a little bit better.
|
||||
It might however reduces code optimization as one more register will be user everywhere in the calling chain, which may huge.
|
||||
|
||||
** Alternative #2
|
||||
|
||||
The custom allocator could have a thread default allocator as a global variable (thread attribute). It seems to be a better solution, more scalable.
|
||||
The custom allocator will need to be able to switch quickly between scrach arena and permanent arena. This seems to be easy.
|
||||
|
||||
However switching allocators puts a burden to the user:
|
||||
the user needs to properly be sure to call the destructor with the custom allocator set to be the same as when it was created.
|
||||
This might not even be possible in case of exceptions.
|
||||
|
||||
* TODO #31 : Uniformize parametrization options of containers :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
|
||||
Currently in order to pass some parametrization of the containers,
|
||||
the parameters are passed to the generation macros through:
|
||||
|
||||
- extra parameters of the macros,
|
||||
- special operators of the contained object oplist.
|
||||
|
||||
The extra parameters of some generation macros break the uniformity
|
||||
of the interface.
|
||||
It is conceptually wrong to put some special operators of the contained object
|
||||
that have only meanings for the container object.
|
||||
In case of adding new options, it break the existing interface or put another
|
||||
operator in the contained object oplist.
|
||||
|
||||
|
||||
The following parameters are used:
|
||||
|
||||
- Fixed size of a queue (buffer / B+Tree),
|
||||
- Policy of a queue (buffer),
|
||||
- Type of the container, IT type of the container, Ref type of the iterator
|
||||
|
||||
The following operators are used:
|
||||
|
||||
- NEW / DEL / REALLOC / FREE
|
||||
- MEMPOOL / MEMPOOL_LINKAGE
|
||||
|
||||
The following new options is planned:
|
||||
|
||||
- Interface (See #28)
|
||||
- Extra parameter for memory allocation function
|
||||
|
||||
** Plan
|
||||
|
||||
The M\_*\_DEF\_AS macros shall be changed like this:
|
||||
|
||||
M_*_DEF_AS(name, cont_oplist, type[, type_oplist])
|
||||
|
||||
with cont\_oplist being the container oplist that gives parametrization to the container definition.
|
||||
The following operators are planned:
|
||||
|
||||
- TYPE: to define the type of the container,
|
||||
- IT\_TYPE: to define the IT type of the container,
|
||||
- SUBTYPE: to define the type pointed by the iterator,
|
||||
- FIXED\_SIZE: to define the fixed size of a container,
|
||||
- POLICY: to define the policy of a container,
|
||||
- NEW / DEL / REALLOC / FREE: to define the memory interface,
|
||||
- MEMPOOL / MEMPOOL_LINKAGE: to request a definition of a specialized memory interface,
|
||||
- INTERFACE: to request a pure header definition, an implementation or both (see #28),
|
||||
- CONTEXT: to request an extra context parameter to add in the container.
|
||||
|
||||
All operators should be optional.
|
||||
|
||||
The NEW / DEL / REALLOC / FREE / MEMPOOL / MEMPOOL_LINKAGE won't have any effects anymore if defined in the contained object oplist.
|
||||
|
||||
** Pro:
|
||||
|
||||
- Uniformize interface
|
||||
|
||||
** Con:
|
||||
|
||||
- API breakage. It can be mitigated by providing an adaptating layer by prividing the new interface for M\_*\_DEF\_AS only
|
||||
and *\_DEF\_AS will provide a translation layer.
|
||||
|
||||
* TODO #30 : Serialization rework :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Currently, each container supports 3 serialization methods:
|
||||
|
||||
- old format to FILE
|
||||
- old format to string
|
||||
- generic serialization
|
||||
|
||||
Generic serialiation connect the container format to the serialization object constraints.
|
||||
It is done through a vtable. As such there is a performance penality and it avoids proper inlining.
|
||||
It is however quite flexible and decouple the data structure from the serialization format.
|
||||
|
||||
** Evolution
|
||||
|
||||
Old format should be deprecated and the functions implemented it shall use the generic serialization interface.
|
||||
|
||||
Serialization object shall provide a special OPLIST of serialization.
|
||||
For example M-CORE will provide OLD Format oplist and M-SERIAL-JSON will provide JSON format oplist.
|
||||
Each oplist will provide the suffix needed for the serialization, and the interface
|
||||
(see already existing interface).
|
||||
|
||||
Then a container will generate specialized serialization methods for each provided oplist.
|
||||
|
||||
** Pros:
|
||||
|
||||
- Faster
|
||||
- In the M*LIB philosphy: much like other oplist usage.
|
||||
|
||||
** Cons:
|
||||
|
||||
- compatibility breakage.
|
||||
- increase code complexity.
|
||||
|
||||
** Open point:
|
||||
|
||||
- how can a user add a new serialization object? ==> See solution implemented by M-GENERIC.
|
||||
- Can we make a generic serialization object to support migration path? Seems possible.
|
||||
|
||||
** Example
|
||||
|
||||
serial-json provides
|
||||
|
||||
#define M_SERIAL_1() (NAME(_json), READ_INT(...), WRITE_INT(...) )
|
||||
|
||||
containers provides
|
||||
|
||||
For i in 1 100 ; do
|
||||
if do exist M_SERIAL_ ## i ()
|
||||
expand(SERIAL_METHOD with M_SERIAL_1())
|
||||
|
||||
SERIAL_METHOD(name, ....)
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(M_F(name, _out_serial),M_GET_NAME(serial_op) )(M_GET_TYPE(serial_op) f, const list_t list) \
|
||||
|
||||
* DONE #29 : Support of partial initialized object :ANOMALY:
|
||||
|
||||
** State
|
||||
|
||||
In case of exception during the construction of an object,
|
||||
if the object is partially constructed, there is no destructor to call.
|
||||
Therefore if there is some partially constructed object
|
||||
(with some fields already fully constructed), there will be some links.
|
||||
This is the same problem with C++
|
||||
|
||||
** Proposition
|
||||
|
||||
Provide new macros to perform the partial initialization before doing the remaining taf.
|
||||
Something like:
|
||||
|
||||
M_CHAIN_INIT( init_code, clear_code)
|
||||
|
||||
or
|
||||
|
||||
x is { string_t s; string_t d; int num; }
|
||||
|
||||
void struct_init_set(struct_t x, const struct_t y)
|
||||
{
|
||||
// First thing is Chained Initialization
|
||||
M_CHAIN_INIT( string_init_set(x->s, y->s), string_clear(x->s) );
|
||||
M_CHAIN_INIT( string_init_set(x->d, y->d), string_clear(x->d) );
|
||||
// End of chain init
|
||||
x->num = y->num;
|
||||
}
|
||||
|
||||
M_CHAIN_INIT will push the clean code pretty much like M_LET.
|
||||
Everything else is done in M_LET: when the constructor fully returns,
|
||||
the index of the clean code to call is reset to its value before calling
|
||||
the constructor. It means that the partially initialized code will be removed
|
||||
from this stack before the clean method of the structure itself is pushed.
|
||||
|
||||
If an exception is raised after a M_CHAIN_INIT, only the clean methods
|
||||
of the M_CHAIN_INIT are called.
|
||||
|
||||
* TODO #28 : Separate generation of interface to implementation :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Enable support for generating an interface only for the headers
|
||||
and an implementation only for the source code.
|
||||
|
||||
** Analysis
|
||||
Try to keep API compatibility
|
||||
==> Only modify renamed macro with M_ prefix by giving a new mandatory
|
||||
argument for such generation.
|
||||
|
||||
This argument is a generation parametric argument.
|
||||
oplist is a parameter that define the property of the contained type.
|
||||
It could be used to pass this information but it will be an abuse of interface.
|
||||
Another argument is needed.
|
||||
|
||||
Used arguments to parameter generation not related to the contained type:
|
||||
|
||||
- memory interface (NEW / DEL / ...)
|
||||
- queue policy
|
||||
- fixed size for queue
|
||||
- fixed node size for B+Tree
|
||||
- generate static inline, public (extern) or private (define) functions.
|
||||
- name of the type.
|
||||
- name of the iterator
|
||||
- name of the iterated element.
|
||||
- ...
|
||||
|
||||
Use another oplist as argument for M_.._DEF_AS (See #31)
|
||||
|
||||
M_BUFFER_DEF_AS(name, (TYPE(toto), FIXED_SIZE(10), POLICY(STACK), INTERFACE(header)), int, M_BASIC_OPLIST)
|
||||
|
||||
* TODO #27 : Uniformization of m-buffer interface :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
|
||||
The m-buffer interface requires special argument to work:
|
||||
- size & policy for BUFFER,
|
||||
- policy only for the others.
|
||||
This is not uniform with the others generation macros and not uniform with each other.
|
||||
Moreover the others are the only one which can be used in a shared memory, so
|
||||
a fixed size will be good to have too for such interface.
|
||||
|
||||
** Plan
|
||||
|
||||
- Uniformization of the interface (See #31)
|
||||
- Provide static size for all QUEUE.
|
||||
|
||||
* DONE #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
|
||||
|
||||
Can also (should?) use SIMD to test for several hash entries at the same times
|
||||
In which case a complete new implementation will be needed
|
||||
Note: SIMD doesn't seem to be a win if not handled properly.
|
||||
Since the first guess of a good hashtable shall give the right entry > 90% of the time.
|
||||
So 90% of the times SIMD will pay the cost of reading not needed memory.
|
||||
It might still be a win, but proper tuning needs to be done.
|
||||
|
||||
* TODO #25 : Support of error return model for error handling. :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
Find a way to support error return code for the API in case of allocation
|
||||
failure.
|
||||
|
||||
** Analysis
|
||||
Any service that returns void shall return a "int" (or another type).
|
||||
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 but returns the error code embedded (like a NULL pointer).
|
||||
|
||||
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? Maybe only supports those.
|
||||
|
||||
* TODO #24 : New MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
See https://en.wikipedia.org/wiki/Min-max_heap
|
||||
as DPRIORITY_QUEUE_DEF ?
|
||||
|
||||
** Analysis
|
||||
NOTE: Needs for such container?
|
||||
On hold until a user needs it.
|
||||
|
||||
* DONE #23 : Strict MOVE semantic to clarify :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
|
||||
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 constraint
|
||||
|
||||
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
|
||||
|
||||
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 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 compatible.
|
||||
==> Analyse limitation and possible constraint usages.
|
||||
|
||||
Being able to define a correct default for INIT_MOVE will be really good
|
||||
(compatible with trivial move copy).
|
||||
In such case, all INIT_MOVE & MOVE operators can be removed from oplist
|
||||
to only use the default, and theses operators can be disabled or defined
|
||||
only when really needed in the oplist.
|
||||
However creating a default INIT_MOVE macro seems problematic.
|
||||
If the type is typedef T t[1] then passing such an argument to a function,
|
||||
will transform the argument to T*, and the type of the argument doesn't match
|
||||
what is expecting resulting in a move of the pointers, not a move of the design data.
|
||||
|
||||
Defining this type seems possible with C11 _Generic and a TYPE in the oplist,
|
||||
but without C11 _Generic I don't see any way to define such macro
|
||||
and we still need to target C99 for such basic feature.
|
||||
|
||||
Without a way to write such a macro, the ticket seems pretty much a dead end.
|
||||
|
||||
* TODO #20 : New: Bucket priority queue :ENHANCEMENT:
|
||||
** State
|
||||
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.
|
||||
|
||||
** Analysis
|
||||
NOTE: Needs for such container?
|
||||
On hold until a user needs it.
|
||||
|
||||
* CANC #19 : New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
** State
|
||||
Add intrusive red black tree.
|
||||
Look also for AVL tree (NOTE: Is there a performance difference between the two?)
|
||||
|
||||
** Analysis
|
||||
Only needed for unmovable objects for which B+Tree cannot do the job.
|
||||
But standard Read/Black Tree will do the job just fine.
|
||||
There is really no need for it.
|
||||
==> Cancelled
|
||||
|
||||
* TODO #18 : Missing methods :ENHANCEMENT:
|
||||
** State
|
||||
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
|
||||
|
||||
** Analysis
|
||||
Analyzed each missing methods and fill in the gap
|
||||
|
||||
* TODO #17 : New: Ressource handler :ENHANCEMENT:
|
||||
|
||||
** State
|
||||
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 ?
|
||||
|
||||
** Analysis
|
||||
- use of variant: Pro : easy. Con: 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: Con: more work, API more complex. Pro: 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
|
||||
|
||||
NOTE: m-c-mempool doesn't seem to be fully robust. random failure of the test cases appear (more notably with Visual C++, but it is still quite rare).
|
||||
|
||||
* DONE #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.
|
||||
|
||||
Duplicate with #32 which is more generic ==> Closed
|
||||
|
||||
* TODO #12 : New: Atomic shared pointer :ENHANCEMENT:
|
||||
** State
|
||||
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:
|
||||
** State
|
||||
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.
|
||||
|
||||
* DONE #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?
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 71 KiB |
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
mkdir -p /tmp/prepro-$USER
|
||||
name=/tmp/prepro-$USER/$$.c
|
||||
param1=""
|
||||
param2=""
|
||||
while test $# -gt 0 ; do
|
||||
case $1 in
|
||||
-c) param2="$param2 -c" ;;
|
||||
-o) param2="$param2 -o $2" ; shift ;;
|
||||
*\.c) param1="$param1 $1" ;;
|
||||
*) param1="$param1 $1" ; param2="$param2 $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
cc $param1 -E |grep -v '^#' > ${name} \
|
||||
&& perl -pi -e 's/\;/\;\n/g' ${name} \
|
||||
&& cc $param2 ${name}
|
||||
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 40 KiB |
@@ -1,18 +1,63 @@
|
||||
# Copyright (c) 2017-2023, 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 -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wno-unused-function -g
|
||||
GMP_DIR=
|
||||
MPFR_DIR=$(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) $< -o $@ `cat config` `cat config.curl` $(LDFLAGS)
|
||||
|
||||
all:
|
||||
.c.o:
|
||||
@$(MAKE) config
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -O2 `cat config.link` -DNDEBUG -g $< -c -o $@
|
||||
|
||||
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
|
||||
$(MAKE) exm.exe exn.exe
|
||||
|
||||
exm.exe: exm-lib.o exm-main.o
|
||||
$(CC) `cat config.link` -g $^ -o $@
|
||||
|
||||
exn.exe: exn-lib.o exn-main.o
|
||||
$(CC) `cat config.link` -g $^ -o $@
|
||||
|
||||
config:
|
||||
printf "#include <gmp.h>\nint main(void){mpz_t z; mpz_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
|
||||
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
|
||||
printf "#include <curl/curl.h>\nint main(void){curl_global_init(CURL_GLOBAL_DEFAULT);}" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c `curl-config --cflags --libs` -o config-test.exe 2> /dev/null && echo "-DHAVE_CURL=1 `curl-config --cflags --libs`" > config.curl || echo "-DHAVE_CURL=0 " > config.curl
|
||||
printf "#include <stdio.h>\nint main(void){printf(\"Ok\"); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c -ffunction-sections -fdata-sections -Wl,--gc-sections 2> /dev/null && echo "-ffunction-sections -fdata-sections -Wl,--gc-sections" > config.link || echo "" > config.link
|
||||
$(RM) config-test.c config-test.exe
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat
|
||||
|
||||
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config config.link config.curl
|
||||
@@ -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 (using implicitely M_BASIC_OPLIST) */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
/* Define some standards algorithms on this dynamic array. We can reuse the prefix of the dynamic array */
|
||||
ALGO_DEF(vector_int, vector_int_t)
|
||||
|
||||
/* Define a dynamic array of bool */
|
||||
ARRAY_DEF(vector_bool, bool)
|
||||
/* 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. We can reuse the prefix of the 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");
|
||||
} /* End of M_LET: myvector & tmp are automaticly cleared */
|
||||
|
||||
// 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) );
|
||||
} /* End of M_LET: myvector & tmp are automaticly cleared */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define a dictionnary (or hash_map or unordered_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_BASIC_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 the key 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 = 0;
|
||||
// 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 dictionnary
|
||||
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' and fills tmp with it */
|
||||
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,41 @@
|
||||
#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)
|
||||
|
||||
/* 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 initialize 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 = 0, product = 0;
|
||||
|
||||
// Compute the sum of theses integers.
|
||||
// 'add' is a registered keyword, recognized by M*LIB to perform a sum.
|
||||
ALGO_REDUCE(sum, v, vector_int_t, add);
|
||||
|
||||
// Compute the product of theses integers.
|
||||
// 'mul' is a registered keyword, recognized by M*LIB to perform a product.
|
||||
ALGO_REDUCE(product, v, vector_int_t, mul);
|
||||
|
||||
/* Example of reduction with a transformation of the type from int to string_t
|
||||
By default, the result ("s") should be of the same type as the base type
|
||||
of the container. This is not the case here, we want to transform the
|
||||
type. As such, we add the precision of the type 'string_t' to 's'.
|
||||
The transformation from string to integer is done by string_set_si */
|
||||
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, string_set_si);
|
||||
|
||||
printf ("sum: %d\n"
|
||||
"product: %d\n"
|
||||
"dash str: %s\n", sum, product, string_get_cstr(s));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t allocated_size = 0;
|
||||
|
||||
static void* my_alloc(size_t s)
|
||||
{
|
||||
printf("Alloc called s=%lu!\n", s);
|
||||
allocated_size += s;
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
static void my_free(void *ptr, size_t s)
|
||||
{
|
||||
printf("Free called s=%lu!\n", s);
|
||||
allocated_size -= s;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static void *last_alloc;
|
||||
|
||||
static void* my_array_alloc(size_t s, void *org, size_t n)
|
||||
{
|
||||
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
|
||||
last_alloc = realloc(org, s*n);
|
||||
return last_alloc;
|
||||
}
|
||||
|
||||
static void my_array_free(void *ptr)
|
||||
{
|
||||
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
|
||||
if (ptr != last_alloc) {
|
||||
printf("Somthing went wrong.\n");
|
||||
exit(4);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Allocate for single object
|
||||
# define M_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type))
|
||||
# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr)
|
||||
|
||||
// Allocate for array of objects
|
||||
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
|
||||
# define M_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr)
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
LIST_DEF(list_int, int)
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
printf("List demo\n");
|
||||
|
||||
list_int_t list;
|
||||
list_int_init(list);
|
||||
|
||||
list_int_push_back(list, 34);
|
||||
list_int_push_back(list, 34);
|
||||
|
||||
if (allocated_size == 0) {
|
||||
printf("Nothing was allocated... Very strange...\n");
|
||||
exit(1);
|
||||
}
|
||||
list_int_clear(list);
|
||||
|
||||
if (allocated_size != 0) {
|
||||
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
|
||||
exit(2);
|
||||
}
|
||||
printf("Global custom allocator for list works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
printf("Array demo\n");
|
||||
|
||||
array_int_t array;
|
||||
array_int_init(array);
|
||||
|
||||
array_int_push_back(array, 34);
|
||||
array_int_push_back(array, 34);
|
||||
|
||||
array_int_clear(array);
|
||||
|
||||
printf("Global custom allocator for array works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
test_array();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t allocated_size = 0;
|
||||
|
||||
static void* my_alloc(size_t s)
|
||||
{
|
||||
printf("Alloc called s=%lu!\n", s);
|
||||
allocated_size += s;
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
static void my_free(void *ptr, size_t s)
|
||||
{
|
||||
printf("Free called s=%lu!\n", s);
|
||||
allocated_size -= s;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// Allocate for single object
|
||||
# define MY_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type))
|
||||
# define MY_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Override only for this container the memory allocation function
|
||||
LIST_DEF(list_int, int, M_OPEXTEND(M_BASIC_OPLIST, NEW(MY_MEMORY_ALLOC), DEL(MY_MEMORY_DEL)))
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
printf("List demo\n");
|
||||
|
||||
list_int_t list;
|
||||
list_int_init(list);
|
||||
|
||||
list_int_push_back(list, 34);
|
||||
list_int_push_back(list, 34);
|
||||
|
||||
if (allocated_size == 0) {
|
||||
printf("Nothing was allocated... Very strange...\n");
|
||||
exit(1);
|
||||
}
|
||||
list_int_clear(list);
|
||||
|
||||
if (allocated_size != 0) {
|
||||
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
|
||||
exit(2);
|
||||
}
|
||||
printf("Global custom allocator for list works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static void *last_alloc;
|
||||
|
||||
static void* my_array_alloc(size_t s, void *org, size_t n)
|
||||
{
|
||||
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
|
||||
last_alloc = realloc(org, s*n);
|
||||
return last_alloc;
|
||||
}
|
||||
|
||||
static void my_array_free(void *ptr)
|
||||
{
|
||||
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
|
||||
if (ptr != last_alloc) {
|
||||
printf("Somthing went wrong.\n");
|
||||
exit(4);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// Allocate for array of objects
|
||||
# define MY_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
|
||||
# define MY_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Override only for this container the memory allocation function
|
||||
ARRAY_DEF(array_int, int, M_OPEXTEND(M_BASIC_OPLIST, REALLOC(MY_MEMORY_REALLOC), FREE(MY_MEMORY_FREE)))
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
printf("Array demo\n");
|
||||
|
||||
array_int_t array;
|
||||
array_int_init(array);
|
||||
|
||||
array_int_push_back(array, 34);
|
||||
array_int_push_back(array, 34);
|
||||
|
||||
array_int_clear(array);
|
||||
|
||||
printf("Global custom allocator for array works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
test_array();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,629 @@
|
||||
/* 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_BASIC_OPLIST will be used.
|
||||
For bool, M_BOOL_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_BASIC_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_BASIC_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 C string.
|
||||
We *** need *** an explicit oplist to tell M*LIB
|
||||
to consider the type as a constant C 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[16];
|
||||
// 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 an integer
|
||||
int j = atoi(p);
|
||||
s += j;
|
||||
}
|
||||
|
||||
// We also need a special unalloc pass
|
||||
// to free all constant strings we have allocated using my_strdup
|
||||
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 dynamic 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_set_si(str, 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 free each term of the array
|
||||
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. As 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.
|
||||
// As the basic type of the container is a pointer,
|
||||
// and r_vintptr_get return a pointer to the basic type
|
||||
// we need to dereference its return value to get the pointer value.
|
||||
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;
|
||||
rock.other = 0.0f;
|
||||
// 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;
|
||||
rock->other = 0.0f;
|
||||
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;
|
||||
rock->other = 0.0f;
|
||||
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_BASIC_OPLIST is used by default.
|
||||
|
||||
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.
|
||||
|
||||
The main advantage of a tuple over a classic structure is that you get
|
||||
free classic methods of your structure.
|
||||
*/
|
||||
TUPLE_DEF2(rock_you, (n, int), (other, float))
|
||||
|
||||
ARRAY_DEF(r_rockme3, rock_you_t, TUPLE_OPLIST(rock_you, M_BASIC_OPLIST, M_BASIC_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_BASIC_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_BASIC_OPLIST, M_BASIC_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_rockme4(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);
|
||||
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
#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){
|
||||
mpz_add(*d, *d, a);
|
||||
}
|
||||
static inline void my_mpz_sqr(mpz_t *d, const mpz_t a){
|
||||
static inline bool my_mpz_sqr(mpz_t *d, const mpz_t a, void *data){
|
||||
(void) data;
|
||||
mpz_mul(*d, a, a);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -19,14 +25,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) */
|
||||
array_mpz_map_reduce (&z, a, my_mpz_inc, my_mpz_sqr);
|
||||
|
||||
/* Compute z = sum (a[i]^2) */
|
||||
array_mpz_transform_reduce (&z, a, my_mpz_inc, my_mpz_sqr, NULL);
|
||||
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,117 @@
|
||||
#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.
|
||||
The Manual defines the different supported API.
|
||||
*/
|
||||
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,70 @@
|
||||
#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_BASIC_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_BASIC_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"));
|
||||
|
||||
// You can also emplace the structure
|
||||
map_employee_id_emplace_val(Employees, 4258, "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")));
|
||||
// Print using emplace (we give a const char [] isntead of a const string_t, avoiding macro STRING_CTE)
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get_emplace(Employees_r, "Elisabeth"));
|
||||
} /* Employees_r is cleared beyond this point */
|
||||
|
||||
// But employee is not since we don't use M_LET
|
||||
map_employee_id_clear(Employees);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_MULTI_DEF2(multimap, 5, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST)
|
||||
#define M_OPL_map_multimap_t() BPTREE_OPLIST2(multimap, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// Fill in with multiple value
|
||||
static void
|
||||
fill_in(multimap_t map)
|
||||
{
|
||||
for(int i = 1 ; i < 100; i++)
|
||||
multimap_set_at(map, i, i);
|
||||
for(int i = 1 ; i < 100; i+=2)
|
||||
multimap_set_at(map, i, i*i);
|
||||
for(int i = 1 ; i < 100; i+=3)
|
||||
multimap_set_at(map, i, i*i*i);
|
||||
}
|
||||
|
||||
// Count the number of occurence of a key
|
||||
static int
|
||||
count(multimap_t map, int key)
|
||||
{
|
||||
int n = 0;
|
||||
multimap_it_t it;
|
||||
// it_from is O(n*ln n) complexity
|
||||
// it_while_p and next are O(1) complexity
|
||||
for(multimap_it_from(it, map, key); multimap_it_while_p(it, key); multimap_next(it))
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
// Print the map in details
|
||||
static void
|
||||
print(multimap_t map)
|
||||
{
|
||||
for(int i = 0; i < 101;i++) {
|
||||
printf("Key=%d Count=%d ", i, count(map, i));
|
||||
multimap_it_t it;
|
||||
for(multimap_it_from(it, map, i); multimap_it_while_p(it, i); multimap_next(it)) {
|
||||
printf("Value=%d ", *multimap_ref(it)->value_ptr );
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
multimap_t map;
|
||||
multimap_init(map);
|
||||
fill_in(map);
|
||||
print(map);
|
||||
multimap_clear(map);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-buffer.h"
|
||||
#include "m-shared.h"
|
||||
#include "m-mutex.h"
|
||||
#include "m-shared-ptr.h"
|
||||
#include "m-thread.h"
|
||||
|
||||
/* Global variable to stop scheduling */
|
||||
atomic_bool continue_threading_g;
|
||||
@@ -99,8 +99,8 @@ SHARED_PTR_DEF(shared_bigdata, 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
|
||||
BUFFER_DEF(buffer_bigdata, shared_bigdata_t, MY_QUEUE_SIZE,
|
||||
BUFFER_QUEUE|BUFFER_PUSH_INIT_POP_MOVE, SHARED_PTR_OPLIST(shared_bigdata))
|
||||
BUFFER_DEF(buffer_bigdata, shared_bigdata_t *, MY_QUEUE_SIZE,
|
||||
BUFFER_QUEUE|BUFFER_PUSH_INIT_POP_MOVE, SHARED_PTR_OPLIST(shared_bigdata, M_OPL_bigdata_t()))
|
||||
|
||||
/* Let's build a Thread synchros tree:
|
||||
*
|
||||
@@ -134,8 +134,7 @@ static void thread1 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_init_new (ptr);
|
||||
shared_bigdata_t *ptr = shared_bigdata_new ();
|
||||
perform_acquisition(*shared_bigdata_ref(ptr));
|
||||
buffer_bigdata_push(buf_t1tot2, ptr);
|
||||
buffer_bigdata_push(buf_t1tot3, ptr);
|
||||
@@ -146,7 +145,7 @@ static void thread2 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_t *ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot2); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation2(*shared_bigdata_ref(ptr));
|
||||
shared_bigdata_clear(ptr);
|
||||
@@ -156,7 +155,7 @@ static void thread3 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_t *ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t1tot3); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation3(*shared_bigdata_ref(ptr));
|
||||
buffer_bigdata_push(buf_t3tot4, ptr);
|
||||
@@ -167,7 +166,7 @@ static void thread4 (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
while (atomic_load(&continue_threading_g)) {
|
||||
shared_bigdata_t ptr;
|
||||
shared_bigdata_t *ptr;
|
||||
buffer_bigdata_pop(&ptr, buf_t3tot4); // NOTE: Pop has been configured to init ptr
|
||||
perform_computation4(*shared_bigdata_ref(ptr));
|
||||
shared_bigdata_clear(ptr);
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
#if HAVE_CURL
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "m-dict.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-string.h"
|
||||
#include "m-list.h"
|
||||
#include "m-serial-json.h"
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
// Define container types
|
||||
// First a generic map string to string
|
||||
DICT_DEF2(map_str, string_t, string_t)
|
||||
#define M_OPL_map_str_t() DICT_OPLIST(map_str, STRING_OPLIST, STRING_OPLIST)
|
||||
|
||||
// This structure matches the JSON structure returns by the used WEB server
|
||||
// for the GET command.
|
||||
// It can be whatever you want provided it matches what is expected by the WEB server
|
||||
TUPLE_DEF2(web_data,
|
||||
(args, map_str_t),
|
||||
(headers, map_str_t),
|
||||
(origin, string_t),
|
||||
(url, string_t))
|
||||
#define M_OPL_web_data_t() TUPLE_OPLIST(web_data, M_OPL_map_str_t(), M_OPL_map_str_t(), STRING_T, STRING_T)
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
static size_t
|
||||
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
(void) size; // Parameter not used
|
||||
char *src = buffer;
|
||||
string_ptr str = userp;
|
||||
for(size_t i = 0; i < nmemb; i++) {
|
||||
string_push_back(str, src[i]);
|
||||
}
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static bool get_data(web_data_t data, const char url[])
|
||||
{
|
||||
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||
CURLcode res;
|
||||
string_t str;
|
||||
CURL *handle = curl_easy_init();
|
||||
if (handle) {
|
||||
string_init(str);
|
||||
// Perform an http GET request and fill in str with the JSON answer
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, str);
|
||||
res = curl_easy_perform(handle);
|
||||
curl_easy_cleanup(handle);
|
||||
if (res == CURLE_OK) {
|
||||
// Parse the string and fill in the object
|
||||
m_serial_str_json_read_t serial;
|
||||
m_serial_str_json_read_init(serial, string_get_cstr(str));
|
||||
r = web_data_in_serial(data, serial);
|
||||
m_serial_str_json_read_clear(serial);
|
||||
}
|
||||
string_clear(str);
|
||||
}
|
||||
return r == M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
static size_t
|
||||
ignore_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
(void) buffer; // Parameter not used
|
||||
(void) size; // Parameter not used
|
||||
(void) userp; // Parameter not used
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static bool post_data(web_data_t data, const char url[], bool display_answer)
|
||||
{
|
||||
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||
CURLcode res = 0;
|
||||
string_t str;
|
||||
CURL *handle = curl_easy_init();
|
||||
if (handle) {
|
||||
string_init(str);
|
||||
// Get a JSON string
|
||||
m_serial_str_json_write_t serial;
|
||||
m_serial_str_json_write_init(serial, str);
|
||||
r = web_data_out_serial(serial, data);
|
||||
m_serial_str_json_write_clear(serial);
|
||||
if (r == M_SERIAL_OK_DONE) {
|
||||
// Post JSON string
|
||||
struct curl_slist *headers=NULL;
|
||||
headers = curl_slist_append(headers, "Content-Type: text/json");
|
||||
if (headers != NULL) {
|
||||
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, string_get_cstr(str));
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
|
||||
if (display_answer == false) {
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ignore_data);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
|
||||
}
|
||||
res = curl_easy_perform(handle);
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
}
|
||||
curl_easy_cleanup(handle);
|
||||
string_clear(str);
|
||||
}
|
||||
return (r == M_SERIAL_OK_DONE) && (res == CURLE_OK);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
// Remote server URL
|
||||
#define URL_GET "https://httpbin.org/get"
|
||||
#define URL_POST "https://httpbin.org/post"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURLcode ret = curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
if (ret != CURLE_OK) abort();
|
||||
|
||||
web_data_t data;
|
||||
web_data_init(data);
|
||||
|
||||
// Test http GET
|
||||
bool b = get_data(data, URL_GET);
|
||||
if (b) {
|
||||
// We success receiving the JSON object and fill in the C object web_data with it.
|
||||
// Let's display the object content:
|
||||
printf("SUCCESS. Receive data =\n");
|
||||
web_data_out_str(stdout, data);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("ERROR: Cannot GET data or get data are not in expected format\n");
|
||||
}
|
||||
|
||||
// Test http POST
|
||||
web_data_emplace_origin(data, "This is the origin");
|
||||
web_data_emplace_url(data, "This is the URL");
|
||||
//web_data_set_origin(data, STRING_CTE("This is the origin"));
|
||||
//web_data_set_url(data, STRING_CTE("This is the URL"));
|
||||
b = post_data(data, URL_POST, false);
|
||||
if (b) {
|
||||
printf("SUCCESS: Post\n");
|
||||
} else {
|
||||
printf("ERROR post\n");
|
||||
}
|
||||
|
||||
web_data_clear(data);
|
||||
|
||||
curl_global_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "m-core.h"
|
||||
|
||||
/* This example show how to use the M_LET_IF macro
|
||||
that enables to construct an object and continue
|
||||
if the construction succeeds.
|
||||
*/
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -4,44 +4,45 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a dictionnary of string --> int
|
||||
// named 'str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
// Define a dictionary of string --> int
|
||||
// named 'dict_str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Declare the dictionnary 'h'
|
||||
// Declare the dictionary 'h'
|
||||
dict_str_t h;
|
||||
int max = 1;
|
||||
// Declare the string 'key'
|
||||
string_t key;
|
||||
|
||||
// Initialize the dictionnary & the string
|
||||
// Initialize the dictionary & the string
|
||||
dict_str_init(h);
|
||||
string_init (key);
|
||||
|
||||
// While there is some data in the stream
|
||||
while (!feof(stdin))
|
||||
while (true)
|
||||
{
|
||||
// Read a complete line from the stream and fill in the string 'key'
|
||||
string_fgets (key, stdin, STRING_READ_PURE_LINE);
|
||||
// If the 'key' exists in the dictionnary
|
||||
if (feof(stdin)) break;
|
||||
// If the 'key' exists in the dictionary
|
||||
int *v = dict_str_get (h, key);
|
||||
if (v != NULL) {
|
||||
// Increment the counter in the dictionnary
|
||||
// Increment the counter in the dictionary
|
||||
(*v)++;
|
||||
max = M_MAX(*v, max);
|
||||
} else {
|
||||
// Update the dictionnary with h[key] = 1
|
||||
// Update the dictionary with h[key] = 1
|
||||
dict_str_set_at(h, key, 1);
|
||||
}
|
||||
}
|
||||
printf ("Max occurence = %d\n", max);
|
||||
printf ("Max occurrence = %d\n", max);
|
||||
|
||||
// Iterate on the dictionnary
|
||||
// Iterate on the dictionary
|
||||
dict_str_it_t it;
|
||||
for(dict_str_it(it, h); !dict_str_end_p(it); dict_str_next(it)) {
|
||||
// Get a constant reference on the pair stored in the dictionnary
|
||||
// Get a constant reference on the pair stored in the dictionary
|
||||
const struct dict_str_pair_s *pair = dict_str_cref(it);
|
||||
printf ("Key=%s Value=%d\n",
|
||||
string_get_cstr(pair->key), pair->value);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "m-dict.h"
|
||||
|
||||
// Let's define a dictionary of 'unsigned int' --> 'char
|
||||
DICT_DEF2(dict_m32, unsigned int, M_DEFAULT_OPLIST, char, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(dict_m32, unsigned int, M_BASIC_OPLIST, char, M_BASIC_OPLIST)
|
||||
|
||||
// Let's create a synonym for its oplist.
|
||||
#define M32_OPLIST DICT_OPLIST(dict_m32, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M32_OPLIST DICT_OPLIST(dict_m32, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
#if 1 // Non macro version.
|
||||
|
||||
@@ -14,8 +14,8 @@ int main(void) {
|
||||
dict_m32_set_at (h, 5, 10); // h[5] = 10
|
||||
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
|
||||
assert (is_missing); (void) is_missing;
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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-dict.h"
|
||||
|
||||
/*
|
||||
* Provide OOR methods for OA Hashmap.
|
||||
* See documentation for definition of OOR
|
||||
* OOR values are represented as:
|
||||
* empty (0) is INT_MIN
|
||||
* deleted (1) is INT_MIN + 1
|
||||
* So valid range for integers are [INT_MIN+2, INT_MAX]
|
||||
*/
|
||||
static inline bool oor_equal_p(int k, char n)
|
||||
{
|
||||
return k == INT_MIN + n;
|
||||
}
|
||||
|
||||
static inline int oor_set(char n)
|
||||
{
|
||||
return INT_MIN + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a custom hash function (optional for OA)
|
||||
*/
|
||||
static inline size_t hash(int n)
|
||||
{
|
||||
return (size_t) n; // Identity hash!
|
||||
}
|
||||
|
||||
/* Define an OA dictionnay which performs a hashmap between an int to an int */
|
||||
DICT_OA_DEF2(dict_oa,
|
||||
int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)),
|
||||
int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_oa_t d;
|
||||
dict_oa_init(d);
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
dict_oa_set_at(d, i*i, 4*i);
|
||||
}
|
||||
dict_oa_set_at(d, 3, -17);
|
||||
|
||||
printf("DICT[3] = %d\n", *dict_oa_get(d, 3));
|
||||
|
||||
dict_oa_it_t it;
|
||||
printf("DICT=");
|
||||
for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) {
|
||||
printf("%d:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
dict_oa_clear(d);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include "m-dict.h"
|
||||
|
||||
/*
|
||||
* Provide OOR methods for OA Hashmap.
|
||||
* See documentation for definition of OOR
|
||||
* OOR values are represented as:
|
||||
* empty (0) is "EMPTY"
|
||||
* deleted (1) is "DELETED"
|
||||
*/
|
||||
static const char empty_str[] = "EMPTY";
|
||||
static const char deleted_str[] = "DELETED";
|
||||
static const char *const oor_table[] = { empty_str, deleted_str };
|
||||
|
||||
static inline bool oor_equal_p(const char *k, int n)
|
||||
{
|
||||
return k == oor_table[n];
|
||||
}
|
||||
|
||||
static inline const char *oor_set(int n)
|
||||
{
|
||||
return oor_table[n];
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a custom hash function (optional for OA)
|
||||
*/
|
||||
static inline size_t hash(const char *k)
|
||||
{
|
||||
size_t r = 17;
|
||||
while (*k) {
|
||||
r = *k * 33 + r;
|
||||
k++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Define an OA dictionnay which performs a hashmap between a CSTR to an int */
|
||||
DICT_OA_DEF2(dict_oa,
|
||||
const char *, M_OPEXTEND(M_CSTR_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)),
|
||||
int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_oa_t d;
|
||||
dict_oa_init(d);
|
||||
|
||||
dict_oa_set_at(d, "THIS", -17);
|
||||
dict_oa_set_at(d, "IS", -170);
|
||||
dict_oa_set_at(d, "AN", 7);
|
||||
dict_oa_set_at(d, "EXAMPLE", 77);
|
||||
|
||||
printf("DICT[\"AN\"] = %d\n", *dict_oa_get(d, "AN"));
|
||||
|
||||
dict_oa_it_t it;
|
||||
printf("DICT=");
|
||||
for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) {
|
||||
printf("%s:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
dict_oa_clear(d);
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "m-i-list.h"
|
||||
|
||||
typedef struct data_s {
|
||||
M_ILIST_INTERFACE(list1, struct data_s);
|
||||
char *ptr;
|
||||
int n;
|
||||
} data_t;
|
||||
|
||||
static void
|
||||
data_init(data_t *p)
|
||||
{
|
||||
M_ILIST_INIT_FIELD(list1, *p);
|
||||
p->ptr = malloc(100);
|
||||
p->n = 100;
|
||||
}
|
||||
|
||||
static void
|
||||
data_clear(data_t *p)
|
||||
{
|
||||
free(p->ptr);
|
||||
p->n = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
data_init_set(data_t *p, data_t s)
|
||||
{
|
||||
p->ptr = malloc(s.n);
|
||||
p->n = s.n;
|
||||
memcpy(p->ptr, s.ptr, s.n);
|
||||
}
|
||||
|
||||
#define DATA_OP (INIT(API_2(data_init)), INIT_SET(API_2(data_init_set)), CLEAR(API_2(data_clear)) )
|
||||
|
||||
M_ILIST_DEF(list1, data_t, DATA_OP)
|
||||
|
||||
data_t pool[100];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
list1_t l;
|
||||
|
||||
list1_init(l);
|
||||
data_init(&pool[0]);
|
||||
list1_push_back(l, &pool[0]);
|
||||
data_init(&pool[1]);
|
||||
list1_push_back(l, &pool[1]);
|
||||
|
||||
list1_it_t it;
|
||||
list1_it(it, l);
|
||||
data_init(&pool[2]);
|
||||
list1_insert(l, it, &pool[2]);
|
||||
|
||||
list1_clear(l);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -8,43 +8,54 @@
|
||||
#include "m-string.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
// Let's create a list of string.
|
||||
// Let's create a list of string by using the M*LIB dynamic string 'string_t'
|
||||
// The prefix used for generating functions will be 'list_string'
|
||||
LIST_DEF(list_string, string_t)
|
||||
|
||||
// Let's register the oplist globally so that other m*lib macros
|
||||
// Let's register the oplist globally so that other M*LIB macros
|
||||
// can get the oplist without us giving it explictly to them.
|
||||
// An oplist is the association of operators to the provided methods
|
||||
// so that generic code can use correctly an object of such type.
|
||||
// LIST_OPLIST is a macro used to generate the oplist associated to the
|
||||
// list itself. It needs the prefix used for generating the list (aka list_string here)
|
||||
// and the oplist of the item in the list (aka the string oplist)
|
||||
#define M_OPL_list_string_t() LIST_OPLIST(list_string, STRING_OPLIST)
|
||||
|
||||
// Let's define some basic algorithms over this list of string.
|
||||
ALGO_DEF(astring, M_OPL_list_string_t())
|
||||
// We reuse the prefix of the list to simplify usage, but algorithms can use separate namespace.
|
||||
ALGO_DEF(list_string, M_OPL_list_string_t())
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's create a variable named 'grow' which is a list of string_t
|
||||
// Let's create a variable named 'list' which is a list of string_t
|
||||
// This variable is only defined within the associated '{' '}' block.
|
||||
// The constructor/destructor of the variable will be called within this block
|
||||
// You can also define the variable (list_string_t) and use explicitly
|
||||
// its constructor (list_string_init) / destructor (list_string_clear).
|
||||
M_LET (grow, list_string_t)
|
||||
M_LET (list, list_string_t)
|
||||
M_LET (tmpstr, string_t) { // And let's create also a string_t
|
||||
|
||||
// add string elements to the list
|
||||
list_string_push_back (grow, STRING_CTE("AB"));
|
||||
// add string elements to the list in different ways
|
||||
// First is pushing a const string.
|
||||
// The macro STRING_CTE creates a const string_t based on the given const char * string.
|
||||
list_string_push_back (list, STRING_CTE("AB"));
|
||||
// Second is creating a separate string_t and then pushing it in the list
|
||||
string_printf(tmpstr, "%d", 12);
|
||||
list_string_push_back (grow, tmpstr);
|
||||
list_string_push_back (grow, STRING_CTE("CD"));
|
||||
list_string_push_back (list, tmpstr);
|
||||
// Third is to emplace directly in the list by constructing a new string_t based on the given const char *
|
||||
list_string_emplace_back (list, "CD");
|
||||
|
||||
// Serialize the list of string into a big string.
|
||||
list_string_get_str (tmpstr, grow, false);
|
||||
list_string_get_str (tmpstr, list, false);
|
||||
|
||||
// print out
|
||||
printf("Number of elements = %zu\n", list_string_size(grow));
|
||||
// print it
|
||||
printf("Number of elements = %zu\n", list_string_size(list));
|
||||
printf("Final string = %s\n", string_get_cstr(tmpstr));
|
||||
|
||||
// Let's iterate over each element of the list
|
||||
// using the macro for iteration over a container.
|
||||
printf ("Using macro EACH :\n");
|
||||
for M_EACH (item, grow, list_string_t) {
|
||||
printf ("Using macro EACH:\n");
|
||||
for M_EACH (item, list, list_string_t) {
|
||||
printf ("Item = ");
|
||||
string_fputs (stdout, *item);
|
||||
printf ("\n");
|
||||
@@ -52,34 +63,59 @@ int main(void)
|
||||
|
||||
// You can also use classic iterator:
|
||||
list_string_it_t it;
|
||||
printf ("Using iterators :\n");
|
||||
for(list_string_it(it, grow) ; !list_string_end_p(it) ; list_string_next(it)) {
|
||||
printf ("Using iterators:\n");
|
||||
for(list_string_it(it, list) ; !list_string_end_p(it) ; list_string_next(it)) {
|
||||
const string_t *item = list_string_cref (it);
|
||||
printf ("Item = ");
|
||||
string_fputs (stdout, *item);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
// Another way: we map each element to the M_PRINT function.
|
||||
printf ("Using macro ALGO_FOR_EACH:");
|
||||
ALGO_FOR_EACH(list, list_string_t, M_PRINT, "\nItem = ");
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
// Get the min and the max of the list
|
||||
string_t *p = astring_min(grow);
|
||||
string_t *p = list_string_min(list);
|
||||
printf ("Min string is %s\n", string_get_cstr(*p));
|
||||
p = astring_max(grow);
|
||||
p = list_string_max(list);
|
||||
printf ("Max string is %s\n", string_get_cstr(*p));
|
||||
|
||||
// We can even sort the list.
|
||||
astring_sort(grow);
|
||||
for M_EACH (item, grow, list_string_t) {
|
||||
list_string_sort(list);
|
||||
for M_EACH (item, list, list_string_t) {
|
||||
printf ("Sort Item = %s\n", string_get_cstr(*item) );
|
||||
}
|
||||
|
||||
// Split a string into a list.
|
||||
string_set_str(tmpstr, "HELLO;JOHN;HOW;ARE;YOU");
|
||||
astring_split(grow, tmpstr, ';');
|
||||
for M_EACH (item, grow, list_string_t) {
|
||||
list_string_split(list, tmpstr, ';');
|
||||
// Iterate over the splitted list
|
||||
for M_EACH (item, list, list_string_t) {
|
||||
printf ("Split Item = %s\n", string_get_cstr(*item) );
|
||||
}
|
||||
|
||||
} // Everything is cleared after this point.
|
||||
|
||||
// Let's create another list of string and init it.
|
||||
list_string_t list;
|
||||
list_string_init(list);
|
||||
// Let's put some elements in it:
|
||||
list_string_emplace_back (list, "A");
|
||||
list_string_emplace_back (list, "B");
|
||||
list_string_emplace_back (list, "C");
|
||||
list_string_emplace_back (list, "D");
|
||||
// Reverse it
|
||||
list_string_reverse(list);
|
||||
// Let's display the string by serializing the elements of the list:
|
||||
printf ("List of string = ");
|
||||
list_string_out_str(stdout, list);
|
||||
printf ("\n");
|
||||
// Don't forget to clear the list before leaving
|
||||
list_string_clear(list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
#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_BASIC_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_BASIC_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now 'arr' won't change anymore and we can get reliable pointers from it.
|
||||
for M_EACH(item, arr, array_string_t) {
|
||||
dict_mph_set_at(dict, string_get_cstr(*item), 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,63 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "m-variant.h"
|
||||
#include "m-string.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Define a variant over two integers named integer_t
|
||||
Notice than mpz_t has special init & clear functions
|
||||
mpz_init & mpz_clear.
|
||||
This is handle by the library.
|
||||
*/
|
||||
VARIANT_DEF2(my_integer,
|
||||
(n, long long, M_DEFAULT_OPLIST),
|
||||
(z, mpz_t, M_CLASSIC_OPLIST(mpz)))
|
||||
/* Define the oplist associated to this variant */
|
||||
#define MY_INTEGER_OPLIST VARIANT_OPLIST(my_integer, M_DEFAULT_OPLIST, M_CLASSIC_OPLIST(mpz))
|
||||
|
||||
/* Define a dictionary of string --> integer named dict_my_t */
|
||||
DICT_DEF2(my_dict,
|
||||
string_t, STRING_OPLIST,
|
||||
my_integer_t, MY_INTEGER_OPLIST)
|
||||
/* Define the oplist associated to this dictionary */
|
||||
#define MY_DICT_OPLIST DICT_OPLIST(my_dict, STRING_OPLIST, MY_INTEGER_OPLIST)
|
||||
|
||||
/* Define an array of such dictionary named array_my_t */
|
||||
ARRAY_DEF(my_array, my_dict_t, MY_DICT_OPLIST)
|
||||
/* Define the oplist associated to this array of dictionary of variant */
|
||||
#define MY_ARRAY_OPLIST ARRAY_OPLIST(my_array, MY_DICT_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(z, MY_INTEGER_OPLIST) /* Define & init & clear an instance of a variant of integer */
|
||||
M_LET(dict, MY_DICT_OPLIST) /* Define & init & clear an instance of a dictionary of variant */
|
||||
M_LET(array, MY_ARRAY_OPLIST) /* Define & init & clear an intance of an array of dictionary of variant */
|
||||
M_LET(gmp, M_CLASSIC_OPLIST(mpz)) /* M_LET allows even with non container type */
|
||||
{
|
||||
my_integer_set_n (z, 17LL); // Set z as the long long 17
|
||||
my_dict_set_at(dict, STRING_CTE("n1"), z); // Push it in the dictionary
|
||||
mpz_set_str(gmp, "25446846874687468746874687468746874686874", 10); // Set gmp to a very long integer.
|
||||
my_integer_set_z (z, gmp); // Set z as the mpz_t variable
|
||||
my_dict_set_at(dict, STRING_CTE("n2"), z); // Push it in the dictionary
|
||||
my_array_push_back (array, dict); // Push the dictionary in the array
|
||||
|
||||
// Iterate over the array container
|
||||
for M_EACH(item, array, MY_ARRAY_OPLIST) {
|
||||
// Iterate over the dictionary container
|
||||
for M_EACH(p, *item, MY_DICT_OPLIST) {
|
||||
// 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));
|
||||
}
|
||||
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));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* All variables are automatically cleared beyond this point */
|
||||
}
|
||||
@@ -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)
|
||||
@@ -82,8 +84,8 @@ DICT_DEF2(dict_json, string_t, STRING_OPLIST, json_t, JSON_OPLIST)
|
||||
ARRAY_DEF(array_json, json_t, JSON_OPLIST)
|
||||
|
||||
VARIANT_DEF2(variant_json,
|
||||
(boolean, bool, M_OPEXTEND(M_DEFAULT_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
|
||||
(real, float, M_OPEXTEND (M_DEFAULT_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
|
||||
(boolean, bool, M_OPEXTEND(M_BASIC_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
|
||||
(real, float, M_OPEXTEND (M_BASIC_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
|
||||
(array, array_json_t, ARRAY_OPLIST(array_json, JSON_OPLIST)),
|
||||
(dict, dict_json_t, DICT_OPLIST(dict_json, STRING_OPLIST, JSON_OPLIST)))
|
||||
|
||||
|
||||
@@ -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_BASIC_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, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
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, STRING_OPLIST, M_OPL_my_tuple_t() )
|
||||
|
||||
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_BASIC_OPLIST, M_OPL_trbuff_t())
|
||||
|
||||
TUPLE_DEF2(mlib_point, (x, int), (y, int))
|
||||
#define M_OPL_mlib_point_t() \
|
||||
TUPLE_OPLIST(mlib_point, M_BASIC_OPLIST, M_BASIC_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,38 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* This example show ARRAY_DEF usage with string,
|
||||
M_LET macro usage with complex initialization condition:
|
||||
how to initialize a dynamic array and initialize it with the given arguments.
|
||||
It show also the M_EACH keywork
|
||||
*/
|
||||
|
||||
// Let's create a dynamic array of string_t and register it globaly
|
||||
// a so called std::vector<std::string> in C++
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Micro example to test if M*LIB supports not using stdio.h
|
||||
*/
|
||||
#define M_USE_STDIO 0
|
||||
#define M_RAISE_FATAL(...) abort()
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(arr, int)
|
||||
|
||||
int main(void) {
|
||||
arr_t a;
|
||||
arr_init(a);
|
||||
arr_push_back(a, 4);
|
||||
arr_clear(a);
|
||||
return 0;
|
||||
}
|
||||
@@ -4,6 +4,14 @@
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
// Let's define one utility function.
|
||||
static 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 +20,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 +32,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,45 @@
|
||||
#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_BASIC_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 into the dictionnary 'map'
|
||||
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) {
|
||||
// In C11 version we can use the M_PRINT macro that simplifies formatting.
|
||||
#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,39 @@
|
||||
#include <stdio.h>
|
||||
#include "m-tree.h"
|
||||
|
||||
TREE_DEF(tree, int)
|
||||
|
||||
// Compute sum of the tree using iterator and a pre-order walk
|
||||
static int tree_sum_iter(tree_t t)
|
||||
{
|
||||
int s = 0;
|
||||
for(tree_it_t it = tree_it(t); !tree_end_p(it); tree_next(&it)) {
|
||||
s += *tree_cref(it);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// Compute sum of the tree using recursive call
|
||||
static int tree_sum_recur(tree_it_t it)
|
||||
{
|
||||
if (tree_end_p(it))
|
||||
return 0;
|
||||
if (tree_leaf_p(it))
|
||||
return *tree_cref(it);
|
||||
assert( tree_degree(it) == 2);
|
||||
return *tree_cref(it) + tree_sum_recur(tree_down(it)) + tree_sum_recur(tree_right(tree_down(it)));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
tree_t t;
|
||||
tree_init(t);
|
||||
tree_it_t r = tree_set_root(t, 1);
|
||||
tree_it_t l = tree_insert_child(r, 2);
|
||||
tree_insert_child(r, 5);
|
||||
tree_insert_child(l, 3);
|
||||
tree_insert_child(l, 4);
|
||||
printf("sum = %d vs %d\n", tree_sum_iter(t), tree_sum_recur(tree_it(t)));
|
||||
tree_clear(t);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "m-try.h"
|
||||
#include "m-array.h"
|
||||
|
||||
// Define & register an array of int
|
||||
ARRAY_DEF(array, int)
|
||||
#define M_OPL_array_t() ARRAY_OPLIST(array, M_BASIC_OPLIST)
|
||||
|
||||
// This shall be defined once per program to define the global variables needed
|
||||
// to handle the exceptions.
|
||||
M_TRY_DEF_ONCE()
|
||||
|
||||
static void f(void)
|
||||
{
|
||||
M_TRY(f_exception) {
|
||||
// Let's define a variable and do stuff:
|
||||
// Using M_LET allows the register of destructors for the exception handler.
|
||||
M_LET(a, array_t) {
|
||||
array_push_back(a, 5);
|
||||
array_push_back(a, 4);
|
||||
array_push_back(a, 3);
|
||||
array_push_back(a, 2);
|
||||
array_push_back(a, 1);
|
||||
// Throw a M_ERROR_MEMORY exception
|
||||
M_THROW(M_ERROR_MEMORY);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
} M_CATCH(f_exception, M_ERROR_MEMORY) {
|
||||
// Exception handler than catches the M_ERROR_MEMORY errors.
|
||||
// Here the destructor of variable a has been called to free memory
|
||||
printf("Memory exception %d received in f function, thrown by %s:%d\n",
|
||||
f_exception->error_code, f_exception->filename, f_exception->line);
|
||||
}
|
||||
}
|
||||
|
||||
static void g(void)
|
||||
{
|
||||
M_TRY(f_exception) {
|
||||
// Let's define a variable and do stuff:
|
||||
// Using M_LET allows the register of destructors for the exception handler.
|
||||
M_LET(a, array_t) {
|
||||
array_push_back(a, 5);
|
||||
array_push_back(a, 4);
|
||||
array_push_back(a, 3);
|
||||
array_push_back(a, 2);
|
||||
array_push_back(a, 1);
|
||||
// Throw an unkown exception
|
||||
M_THROW(42);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
} M_CATCH(f_exception, M_ERROR_MEMORY) {
|
||||
printf("Memory exception %d received in f function, thrown by %s:%d\n",
|
||||
f_exception->error_code, f_exception->filename, f_exception->line);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's do a global exception handler
|
||||
M_TRY(main_exception) {
|
||||
f();
|
||||
g();
|
||||
} M_CATCH(main_exception, 0) {
|
||||
// Exception handler than catches all errors.
|
||||
// Here the destructor of variable a has been called to free memory
|
||||
printf("Exception %d received in main function, thrown by %s:%d\n",
|
||||
main_exception->error_code, main_exception->filename, main_exception->line);
|
||||
}
|
||||
printf("You should run it under valgrind to check that all memory allocations are freed.\n");
|
||||
exit(0);
|
||||
}
|
||||
@@ -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_BASIC_OPLIST, M_BASIC_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,69 @@
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-string.h"
|
||||
|
||||
ARRAY_DEF(array_int, int)
|
||||
#define M_OPL_array_int_t() ARRAY_OPLIST(array_int, M_BASIC_OPLIST)
|
||||
ALGO_DEF(array_int, array_int_t)
|
||||
|
||||
static bool callback1(int *out, int in, void *data)
|
||||
{
|
||||
int *cpt = data;
|
||||
bool ret = true;
|
||||
if (*cpt == -1 && in == 11)
|
||||
*cpt = 0; // Start when first reach 11
|
||||
ret &= (*cpt >= 0); // Skip initial numbers unequal 11
|
||||
ret &= (in % 2 != 0); // Collect odd numbers
|
||||
(*cpt) += ret;
|
||||
ret &= (*cpt <= 5); // Only take five numbers
|
||||
*out = in * in; // Square each number
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void callback_add_int(int *out, int in)
|
||||
{
|
||||
*out += in;
|
||||
}
|
||||
|
||||
static void demo(void)
|
||||
{
|
||||
M_LET( (t, M_SEQ(0, 30)), vector, array_int_t) {
|
||||
printf("t="); array_int_out_str(stdout, t);
|
||||
int b = -1;
|
||||
array_int_transform(vector, t, callback1, &b);
|
||||
printf("\nvector="); array_int_out_str(stdout, vector); printf("\n");
|
||||
array_int_reduce(&b, vector, callback_add_int);
|
||||
printf("Sum=%d\n", b);
|
||||
}
|
||||
}
|
||||
|
||||
ARRAY_DEF(array_str, string_t)
|
||||
#define M_OPL_array_str_t() ARRAY_OPLIST(array_str, M_STRING_OPLIST)
|
||||
ALGO_DEF(array_str, array_str_t)
|
||||
|
||||
static bool callback2(string_t *out, const string_t in, void *data)
|
||||
{
|
||||
char *cp = data, c = *cp;
|
||||
if (string_search_char(in, c) == M_STRING_FAILURE)
|
||||
return false;
|
||||
string_set(*out, in);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void demo_split(void)
|
||||
{
|
||||
M_LET( (s, ("This is a sentence in C11.")), string_t)
|
||||
M_LET(words, f_words, array_str_t) {
|
||||
array_str_split(words, s, ' ');
|
||||
array_str_transform(f_words, words, callback2, &(char){'i'});
|
||||
printf("f_words="); array_str_out_str(stdout, f_words); printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
demo();
|
||||
demo_split();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "m-tuple.h"
|
||||
#include "m-tree.h"
|
||||
#include "m-worker.h"
|
||||
#include "m-string.h"
|
||||
#include "m-atomic.h"
|
||||
|
||||
|
||||
/* Define the comparison function for atomic_uint type
|
||||
to sort the atomic unsigned int with the biggest value first. */
|
||||
static inline int atomic_uint_cmp(const atomic_uint *a, const atomic_uint *b)
|
||||
{
|
||||
unsigned ai = atomic_load(a), bi = atomic_load(b);
|
||||
return ai > bi ? -1 : ai < bi;
|
||||
}
|
||||
|
||||
/* Define the oplist for atomic_uint and register it globally.
|
||||
This oplist extends the basic oplist by:
|
||||
* disabling HASH for atomic as the default hash method won't work.
|
||||
* providing the methods for CMP, INIT_SET and SET operators (with their API adaptator) */
|
||||
#define M_OPL_atomic_uint() M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(API_6(atomic_uint_cmp)), INIT_SET(API_2(atomic_store)), SET(API_2(atomic_store)))
|
||||
|
||||
|
||||
/* Define a directory as a tree where each node contains:
|
||||
* the number of lines of the files in this directory,
|
||||
* and the name of the directory/
|
||||
Since we want to sort with the number of lines only, we extend the oplist of a string by disabling the compare method.
|
||||
So first, let's define the node as a tuple of such elements:
|
||||
*/
|
||||
M_TUPLE_DEF2( dir, (nlines, atomic_uint), (name, m_string_t, M_OPEXTEND(M_STRING_OPLIST, CMP(0))))
|
||||
/* Register globally the oplist of this tuple */
|
||||
#define M_OPL_dir_t() M_TUPLE_OPLIST(dir, M_OPL_atomic_uint(), M_STRING_OPLIST)
|
||||
|
||||
/* Define a hierarchical tree of directory.
|
||||
Note that it will use the globally registered oplist associated to dir_t to use it */
|
||||
M_TREE_DEF(tree, dir_t)
|
||||
|
||||
|
||||
/* Maximum number of characters read by file */
|
||||
#define MAX_READ_BUFFER 8192
|
||||
|
||||
/* Maximum number of directory to scan */
|
||||
#define MAX_DIRECTORY 100000
|
||||
|
||||
|
||||
/* Define the pool of worker threads */
|
||||
m_worker_t workers;
|
||||
|
||||
/* Global synchronous block for all threads */
|
||||
m_worker_sync_t workers_block;
|
||||
|
||||
/* Add a specialization of the spawn function for the scan_file function.
|
||||
This functions takes as input an iterator of a tree (treated as a POD data),
|
||||
and a file name */
|
||||
M_WORKER_SPAWN_DEF2(scan_file, (parent, tree_it_t, M_POD_OPLIST), (filename, m_string_t) )
|
||||
|
||||
|
||||
/* Add either the root node or a child to parent in function of the existence of parent */
|
||||
static tree_it_t
|
||||
add_directory(tree_it_t parent, const m_string_t dirname)
|
||||
{
|
||||
if (tree_end_p(parent)) {
|
||||
return tree_emplace_root( tree_tree(parent), 0, dirname);
|
||||
} else {
|
||||
return tree_emplace_child(parent, 0, dirname);
|
||||
}
|
||||
}
|
||||
|
||||
/* count the number of end of line character in the buffer */
|
||||
static unsigned
|
||||
count_eol(size_t num, const char buffer[num])
|
||||
{
|
||||
unsigned count = 0;
|
||||
for(size_t i = 0; i < num; i++) {
|
||||
count += buffer[i] == '\n';
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Test if a filename suffix ends with a C++ or C suffix */
|
||||
static bool
|
||||
is_a_c_file(const m_string_t filename)
|
||||
{
|
||||
return (m_string_end_with_str_p(filename, ".c")
|
||||
|| m_string_end_with_str_p(filename, ".h")
|
||||
|| m_string_end_with_str_p(filename, ".cpp")
|
||||
|| m_string_end_with_str_p(filename, ".hpp"));
|
||||
}
|
||||
|
||||
/* Scan the file and count its number of lines */
|
||||
static void
|
||||
scan_file(tree_it_t parent, m_string_t filename)
|
||||
{
|
||||
FILE *f = fopen(m_string_get_cstr(filename), "rt");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", m_string_get_cstr(filename) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read the FILE per bulk of MAX_READ_BUFFER */
|
||||
char buffer[MAX_READ_BUFFER];
|
||||
unsigned count = 0;
|
||||
size_t num;
|
||||
do {
|
||||
num = fread (buffer, 1, MAX_READ_BUFFER, f);
|
||||
count += count_eol(num, buffer);
|
||||
} while (num == MAX_READ_BUFFER);
|
||||
fclose(f);
|
||||
|
||||
/* Adding the number of lines to the parent directory */
|
||||
dir_t *d = tree_ref(parent);
|
||||
/* atomic add because the scan of files is done in parallel */
|
||||
atomic_fetch_add( &(*d)->nlines, count );
|
||||
}
|
||||
|
||||
/* Scan the directories recursively for all files */
|
||||
static void
|
||||
scan_directories(tree_it_t parent, const m_string_t dirname)
|
||||
{
|
||||
tree_it_t it = add_directory(parent, dirname);
|
||||
|
||||
m_string_t filename;
|
||||
m_string_init(filename);
|
||||
DIR *dir = opendir(m_string_get_cstr(dirname));
|
||||
if (dir == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", m_string_get_cstr(dirname) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Scan all entries in the directory
|
||||
struct dirent *entry = readdir(dir);
|
||||
while (entry) {
|
||||
// Ignore hidden entries (including '.' and '..')
|
||||
if (entry->d_name[0] != '.') {
|
||||
// Construct the path to the filename by concatenating dirname, "/" and d_name
|
||||
m_string_sets(filename, dirname, "/", entry->d_name);
|
||||
// Get the property of this filename
|
||||
struct stat buf;
|
||||
int err = stat(m_string_get_cstr(filename), &buf);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot stat %s\n", m_string_get_cstr(filename));
|
||||
exit(2);
|
||||
}
|
||||
// Further scanning in function of the kind of entry
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
scan_directories(it, filename);
|
||||
} else if (is_a_c_file(filename)) {
|
||||
// Spawn a scan of file to available workers or run it ourselves
|
||||
m_worker_spawn_scan_file(workers_block, scan_file, it, filename);
|
||||
}
|
||||
}
|
||||
// Next entry in the directory
|
||||
entry = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
m_string_clear(filename);
|
||||
}
|
||||
|
||||
/* Consolidate all lines number to the parent directory */
|
||||
static void
|
||||
consolidate_directories(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the children, then the parent
|
||||
for(tree_it_t it = tree_it_post(directories) ; !tree_end_p(it) ; tree_next_post(&it) ) {
|
||||
dir_t *parent = tree_up_ref(it);
|
||||
dir_t *myself = tree_ref(it);
|
||||
if (parent != NULL) {
|
||||
// Add the child number of lines to the parent
|
||||
atomic_fetch_add_explicit(&(*parent)->nlines, (*myself)->nlines, memory_order_relaxed);
|
||||
}
|
||||
// Sort the data of the children by the number of lines
|
||||
tree_sort_child(it);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the consolidated results on stdout */
|
||||
static void
|
||||
print_result(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the parent, then the children
|
||||
for(tree_it_t it = tree_it(directories) ; !tree_end_p(it) ; tree_next(&it) ) {
|
||||
int i, depth = tree_depth(it);
|
||||
for(i = 0; i < depth; i++) printf("+");
|
||||
for( ; i < 8; i++) printf(" ");
|
||||
const dir_t *d = tree_cref(it);
|
||||
printf("%6u %s\n", (unsigned) (*d)->nlines, m_string_get_cstr( (*d)->name ) );
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
tree_t directories;
|
||||
m_string_t str;
|
||||
|
||||
printf("Count the number of C/C++ lines of code\n");
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "ERROR. Usage is '%s <directory>'.\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Initialize the worker threads */
|
||||
m_worker_init(workers);
|
||||
|
||||
/* Init the tree, reserve for at least the number of max directory
|
||||
and prevent any further increase of allocation:
|
||||
this is to ensure that other threads can deref a dir safely */
|
||||
tree_init(directories);
|
||||
tree_reserve(directories, MAX_DIRECTORY);
|
||||
tree_lock(directories, true);
|
||||
m_string_init_set_cstr(str, argv[1]);
|
||||
tree_it_t it = tree_it_end(directories);
|
||||
|
||||
/* Main processing */
|
||||
m_worker_start(workers_block, workers);
|
||||
scan_directories(it, str);
|
||||
worker_sync(workers_block);
|
||||
consolidate_directories(directories);
|
||||
print_result(directories);
|
||||
|
||||
/* Clear everything & quit */
|
||||
m_string_clear(str);
|
||||
tree_clear(directories);
|
||||
m_worker_clear(workers);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "m-list.h"
|
||||
#include "m-generic.h"
|
||||
|
||||
LIST_DEF(list_uint, unsigned int)
|
||||
// Register for M_LET & M_EACH
|
||||
#define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST)
|
||||
// Register for Generic:
|
||||
#define M_GENERIC_ORG_1() (USER)
|
||||
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_list_uint_t()
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(list, list_uint_t) {
|
||||
// We can push in the list. It will call the registered method.
|
||||
push(list, 42);
|
||||
push(list, 17);
|
||||
// We can iterate over the list
|
||||
for each(item, list) {
|
||||
M_PRINT("ITEM=", *item, "\n");
|
||||
}
|
||||
// We can print directly the list. It will use the registered method
|
||||
M_PRINT("List = ", list, "\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#if HAVE_GMP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-list.h"
|
||||
#include "m-generic.h"
|
||||
|
||||
// Register an organization for generic: USER
|
||||
// Each index (here '1') shall be unique for the whole program
|
||||
#define M_GENERIC_ORG_1() (USER)
|
||||
// Register a component for the organization USER: CORE
|
||||
// Each index (here '1') shall be unique for the whole organization
|
||||
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
|
||||
|
||||
// Register the oplist of a mpz_t. It is a classic oplist.
|
||||
// Adding support for emplace and initialization
|
||||
// Adding the ability to output its value for serialization/printing
|
||||
// Adding type information for handling correctly the generic association
|
||||
#define M_OPL_mpz_t() M_OPEXTEND(M_CLASSIC_OPLIST(mpz), \
|
||||
INIT_WITH(mpz_init_set_ui), EMPLACE_TYPE(unsigned int), \
|
||||
OUT_STR( API( mpz_out_str, VOID, ARG1, 10, ARG2)), \
|
||||
GENTYPE(__mpz_struct *), TYPE(mpz_t) )
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
// Each index (here '1') shall be unique for the whole component
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_mpz_t()
|
||||
|
||||
// Define an instance of an array of mpz_t (both type and function)
|
||||
ARRAY_DEF(array_mpz, mpz_t)
|
||||
// Register the oplist of the created instance of array of mpz_t
|
||||
#define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t())
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
// Each index (here '10') shall be unique for the whole component
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_10() M_OPL_array_mpz_t()
|
||||
|
||||
// Define an instance of a list of mpz_t (both type and function)
|
||||
LIST_DEF(list_mpz, mpz_t)
|
||||
// Register the oplist of the created instance of array of mpz_t
|
||||
#define M_OPL_list_mpz_t() LIST_OPLIST(list_mpz, M_OPL_mpz_t())
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_11() M_OPL_list_mpz_t()
|
||||
|
||||
// Define an instance of a list of unsigned int (both type and function)
|
||||
LIST_DEF(list_uint, unsigned)
|
||||
// Register the oplist of the created instance of list of unsigned
|
||||
#define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST)
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_12() M_OPL_list_uint_t()
|
||||
|
||||
// Define an instance of a array of unsigned int (both type and function)
|
||||
ARRAY_DEF(array_uint, unsigned)
|
||||
// Register the oplist of the created instance of list of unsigned
|
||||
#define M_OPL_array_uint_t() ARRAY_OPLIST(array_uint, M_BASIC_OPLIST)
|
||||
// Register the oplist as a generic type of the component CORE of the organization USER
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_13() M_OPL_array_uint_t()
|
||||
|
||||
int main(void) {
|
||||
|
||||
print("LIST UINT = ");
|
||||
// Initialize list as list_uint_t and push 17 & 42 in it.
|
||||
let( (list, 17, 42), list_uint_t) {
|
||||
push(list, 1742);
|
||||
// Iterate over all elements of the list of unsigned int
|
||||
for each (item, list) {
|
||||
// Print the element
|
||||
print(*item, " ");
|
||||
}
|
||||
// Print the full list too
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
// Now list has been cleared.
|
||||
|
||||
print("Array UINT = ");
|
||||
// Initialize list as array_uint_t and push 17 & 42 in it.
|
||||
let( (list, 17, 42), array_uint_t) {
|
||||
push(list, 1742);
|
||||
// Iterate over all elements of the array of unsigned int
|
||||
for each (item, list) {
|
||||
// Print the element
|
||||
print(*item, " ");
|
||||
}
|
||||
// Print the full array too
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
// Now array has been cleared.
|
||||
|
||||
print("LIST MPZ = ");
|
||||
// Initialize list as array_mpz_t and push_emplace mpz_t from 17 & 42 in it.
|
||||
// The parenthesis around 17 in (17) means to emplace
|
||||
let( (list, (17), (42)), list_mpz_t) {
|
||||
list_mpz_emplace_back(list, 1742); // Generic emplace is not supported yet
|
||||
// Iterate over all elements of the array of mpz_t
|
||||
for each (item, list) {
|
||||
// Print the element
|
||||
// Since we registered the out_str of a mpz_t, we can display it directly
|
||||
print(*item, " ");
|
||||
}
|
||||
// Print the full list too
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
|
||||
print("ARRAY MPZ = ");
|
||||
// Same as before but for array
|
||||
let( (list, (17), (42)), array_mpz_t) {
|
||||
array_mpz_emplace_back(list, 1742);
|
||||
for each (item, list) {
|
||||
print(*item, " ");
|
||||
}
|
||||
print("\n","List=", list, "\n");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {}
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
// Based on https://github.com/nanopb/nanopb/blob/master/examples/simple/simple.c
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-serial-json.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a structure with one field
|
||||
TUPLE_DEF2(SimpleMessage,
|
||||
(lucky_number, int))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
string_t buffer;
|
||||
m_serial_return_code_t status;
|
||||
|
||||
/* Let's define a string 'buffer' that will receive the JSON representation of our message*/
|
||||
string_init(buffer);
|
||||
|
||||
/* Encode our message */
|
||||
{
|
||||
SimpleMessage_t message;
|
||||
SimpleMessage_init(message);
|
||||
|
||||
/* Create a stream that will write to our string buffer. */
|
||||
m_serial_str_json_write_t stream;
|
||||
m_serial_str_json_write_init(stream, buffer);
|
||||
|
||||
/* Fill in the lucky number */
|
||||
message->lucky_number = 13;
|
||||
|
||||
/* Now we are ready to encode the message! */
|
||||
status = SimpleMessage_out_serial(stream, message);
|
||||
|
||||
/* Then just check for any errors.. */
|
||||
if (status != M_SERIAL_OK_DONE)
|
||||
{
|
||||
printf("Encoding failed: %d\n", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Clear the objets */
|
||||
m_serial_str_json_write_clear(stream);
|
||||
SimpleMessage_clear(message);
|
||||
}
|
||||
|
||||
/* Now we could transmit the message over network, store it in a file
|
||||
* It is represented in a string 'buffer'
|
||||
* but we are doing it right now.
|
||||
*/
|
||||
|
||||
{
|
||||
/* Allocate another space for the decoded message. */
|
||||
SimpleMessage_t message;
|
||||
SimpleMessage_init(message);
|
||||
|
||||
/* Create a stream that reads from the buffer. */
|
||||
m_serial_str_json_read_t stream;
|
||||
m_serial_str_json_read_init(stream, string_get_cstr(buffer));
|
||||
|
||||
/* Now we are ready to decode the message. */
|
||||
status = SimpleMessage_in_serial(message, stream);
|
||||
|
||||
/* Check for errors... */
|
||||
if (status != M_SERIAL_OK_DONE)
|
||||
{
|
||||
printf("Decoding failed: %d\n", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print the data contained in the message. */
|
||||
printf("Your lucky number was %d!\n", message->lucky_number);
|
||||
|
||||
/* Clear the objets */
|
||||
m_serial_str_json_read_clear(stream);
|
||||
SimpleMessage_clear(message);
|
||||
}
|
||||
|
||||
string_clear(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "m-serial-json.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Basic example to show JSON serialization */
|
||||
|
||||
// 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, STRING_OPLIST, M_BASIC_OPLIST, M_BOOL_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");
|
||||
base_emplace_back(base, STRING_CTE("John"), 40, false);
|
||||
// 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}
|
||||
]
|
||||
|
||||
|
||||