Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a96845fac | ||
|
|
b742881ebc | ||
|
|
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 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push]
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -10,25 +10,144 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make
|
||||
run: make
|
||||
- name: make check
|
||||
run: make check
|
||||
- uses: actions/checkout@v3
|
||||
- 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_windows_mingw:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [windows-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
build_linux32:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install MINGW
|
||||
run: choco install mingw --no-progress
|
||||
- name: make
|
||||
- uses: actions/checkout@v3
|
||||
- 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@v3
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- name: Clone TCC
|
||||
shell: bash
|
||||
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1"
|
||||
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: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_linux_sanitize:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: make sanitize
|
||||
working-directory: ./tests
|
||||
run: make sanitize -j 2
|
||||
|
||||
build_windows_mingw:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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@v3
|
||||
- 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@v3
|
||||
- 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@v3
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat clang-cl
|
||||
|
||||
build_freebsd:
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0
|
||||
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@v3
|
||||
- uses: uraimo/run-on-arch-action@v2.5.0
|
||||
name: Run commands on aarch64
|
||||
id: make
|
||||
with:
|
||||
arch: aarch64
|
||||
distro: bullseye
|
||||
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
|
||||
@@ -38,3 +38,13 @@ depend
|
||||
other/
|
||||
a*.dat
|
||||
config
|
||||
config.link
|
||||
*.log
|
||||
.vscode
|
||||
.vs
|
||||
tmp-serial.*
|
||||
*~
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
*.synt
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2019, Patrick Pelissier
|
||||
Copyright (c) 2017-2023, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
# 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.
|
||||
|
||||
# Environnement variable. To customize if needed.
|
||||
RM=rm -f
|
||||
MKDIR=mkdir -p
|
||||
RMDIR=rmdir
|
||||
INSTALL=install
|
||||
INSTALL_PROGRAM=${INSTALL}
|
||||
INSTALL_DATA=${INSTALL} -m 644
|
||||
@@ -10,15 +33,15 @@ PREFIX=/usr/local
|
||||
DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m*lib-$(VERSION)
|
||||
VERSION=0.3.0
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.7.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-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h
|
||||
DOC1=LICENSE README.md
|
||||
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png
|
||||
EXAMPLE=example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.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-json01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-rbtree01.c example/ex-section.c example/Makefile
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/wip-mregister.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
|
||||
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
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
@@ -35,17 +58,18 @@ checkall:
|
||||
cd tests && $(MAKE) checkall
|
||||
cd example && $(MAKE) all
|
||||
|
||||
html: doc
|
||||
doc: README.md doc/depend.png
|
||||
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) README.html depend.dot
|
||||
$(RM) -r 'm*lib-$(VERSION)'
|
||||
$(RM) 'm*lib-$(VERSION).tar.bz2'
|
||||
$(RM) -r 'm_lib-$(VERSION)'
|
||||
$(RM) 'm_lib-$(VERSION).tar.bz2'
|
||||
|
||||
distclean: clean
|
||||
cd tests && $(MAKE) distclean
|
||||
@@ -58,7 +82,7 @@ doc/depend.png: $(HEADER)
|
||||
dot -Tpng depend.dot -o doc/depend.png
|
||||
optipng -o7 doc/depend.png
|
||||
|
||||
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean
|
||||
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean versioncheck
|
||||
$(MKDIR) '$(PACKAGE)'
|
||||
$(MKDIR) '$(PACKAGE)/doc'
|
||||
$(MKDIR) '$(PACKAGE)/tests'
|
||||
@@ -73,9 +97,22 @@ dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean
|
||||
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
|
||||
$(INSTALL_DATA) $(HEADER) $(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/$$i ; done
|
||||
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,3 +1,25 @@
|
||||
# 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=c11
|
||||
CXX=c++ -std=c++11
|
||||
CFLAGS=-O2 -march=native -Wall
|
||||
@@ -7,7 +29,7 @@ N=4
|
||||
BENCH_DEF=
|
||||
RM=rm -rf
|
||||
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain
|
||||
.PHONY: all pgo container queue mempool string plain bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-emhash bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
|
||||
|
||||
all: container queue mempool string plain
|
||||
|
||||
@@ -17,10 +39,10 @@ pgo:
|
||||
|
||||
#########################################################################
|
||||
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-sparsepp bench-collectionc bench-tommyds bench-flathashmap bench-hopscotchmap
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-emhash bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap bench-ctl bench-stc bench-pottery bench-CC
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost
|
||||
queue: bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-rigtorp-mpmc-queue
|
||||
@echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
|
||||
mempool: bench-mempool
|
||||
@@ -96,7 +118,7 @@ bench-stl:
|
||||
bench-qt:
|
||||
@if test -n "$${QT}" ; then $(MAKE) bench-qt0 ; else echo "Nothing to be done for QT." ; fi
|
||||
bench-qt0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core` bench-qt.cpp common.c -o bench-qt.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -fPIC bench-qt.cpp common.c -o bench-qt.exe `PKG_CONFIG_PATH="$${QT}" pkg-config --libs --cflags Qt5Core`
|
||||
@./bench-qt.exe 10
|
||||
@./bench-qt.exe 20
|
||||
@./bench-qt.exe 30
|
||||
@@ -130,12 +152,22 @@ bench-klib0:
|
||||
@./bench-klib.exe 41
|
||||
@./bench-klib.exe 50
|
||||
|
||||
# LIBDYNAMIC shall point to the the directory containing the file libdynamic.pc
|
||||
# CMC shall point to the directory where the CMC main header is
|
||||
bench-cmc:
|
||||
@if test -n "$${CMC}" ; then $(MAKE) bench-cmc0 ; else echo "Nothing to be done for CMC." ; fi
|
||||
|
||||
bench-cmc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CMC} bench-cmc.c common.c -o bench-cmc.exe
|
||||
@./bench-cmc.exe 20
|
||||
@./bench-cmc.exe 30
|
||||
@./bench-cmc.exe 40
|
||||
|
||||
# LIBDYNAMIC shall point to the the source directory where the source is built
|
||||
bench-libdynamic:
|
||||
@if test -n "$${LIBDYNAMIC}" ; then $(MAKE) bench-libdynamic0 ; else echo "Nothing to be done for LIBDYNAMIC." ; fi
|
||||
|
||||
bench-libdynamic0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe `PKG_CONFIG_PATH="$${LIBDYNAMIC}" pkg-config --libs --cflags libdynamic`
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) bench-libdynamic.c common.c -o bench-libdynamic.exe -I$${LIBDYNAMIC}/src $${LIBDYNAMIC}/.libs/libdynamic.a
|
||||
@./bench-libdynamic.exe 20
|
||||
@./bench-libdynamic.exe 40
|
||||
@./bench-libdynamic.exe 41
|
||||
@@ -160,12 +192,12 @@ bench-densehashmap0:
|
||||
@./bench-densehashmap.exe 42
|
||||
@./bench-densehashmap.exe 43
|
||||
|
||||
# COLLECTIONC shall point to the directory where the 'src' directory is.
|
||||
# COLLECTIONC shall point to the directory where it is installed
|
||||
bench-collectionc:
|
||||
@if test -n "$${COLLECTIONC}" ; then $(MAKE) bench-collectionc0 ; else echo "Nothing to be done for COLLECTIONC." ; fi
|
||||
|
||||
bench-collectionc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include" -L "$${COLLECTIONC}" -static bench-collectionc.c common.c -lcollectc -o bench-collectionc.exe
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${COLLECTIONC}/include/collectc" bench-collectionc.c common.c "$${COLLECTIONC}/lib/libcollectc.a" -o bench-collectionc.exe
|
||||
@./bench-collectionc.exe 10
|
||||
@./bench-collectionc.exe 20
|
||||
@./bench-collectionc.exe 30
|
||||
@@ -196,6 +228,28 @@ bench-flathashmap0:
|
||||
@./bench-flathashmap.exe 46
|
||||
@./bench-flathashmap.exe 43
|
||||
|
||||
# EMILIB shall point to the directory where the headers are
|
||||
bench-emilib:
|
||||
@if test -n "$${EMILIB}" ; then $(MAKE) bench-emilib0 ; else echo "Nothing to be done for EMILIB." ; fi
|
||||
|
||||
bench-emilib0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMILIB}" bench-emilib.cpp common.c -o bench-emilib.exe
|
||||
@./bench-emilib.exe 41
|
||||
@./bench-emilib.exe 42
|
||||
@./bench-emilib.exe 46
|
||||
@./bench-emilib.exe 43
|
||||
|
||||
# EMHASh shall point to the directory where the headers are
|
||||
bench-emhash:
|
||||
@if test -n "$${EMHASH}" ; then $(MAKE) bench-emhash0 ; else echo "Nothing to be done for EMHASH." ; fi
|
||||
|
||||
bench-emhash0:
|
||||
$(CXX) -std=c++14 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${EMHASH}" bench-emhash.cpp common.c -o bench-emhash.exe
|
||||
@./bench-emhash.exe 41
|
||||
@./bench-emhash.exe 42
|
||||
@./bench-emhash.exe 46
|
||||
@./bench-emhash.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
|
||||
@@ -214,9 +268,8 @@ bench-uthash0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${UTHASH}" bench-uthash.c common.c -o bench-uthash.exe
|
||||
@./bench-uthash.exe 10
|
||||
@./bench-uthash.exe 20
|
||||
@./bench-uthash.exe 40
|
||||
@./bench-uthash.exe 41
|
||||
@./bench-uthash.exe 42
|
||||
@./bench-uthash.exe 43
|
||||
@./bench-uthash.exe 50
|
||||
|
||||
# QLIBC shall point to the directory where the library is installed.
|
||||
@@ -228,21 +281,14 @@ bench-qlibc0:
|
||||
@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
|
||||
# The library shall be built.
|
||||
# LIBSRT shall point to the directory where it is installed
|
||||
bench-libsrt:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-libsrt0 ; else echo "Nothing to be done for LIBSRT." ; fi
|
||||
|
||||
bench-libsrt0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/libsrt.a
|
||||
@./bench-libsrt.exe 10
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${LIBSRT}/src" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/src/.libs/libsrt.a
|
||||
@./bench-libsrt.exe 20
|
||||
@./bench-libsrt.exe 41
|
||||
@./bench-libsrt.exe 42
|
||||
@./bench-libsrt.exe 43
|
||||
@./bench-libsrt.exe 50
|
||||
|
||||
|
||||
@@ -297,6 +343,77 @@ bench-rigtorp-hashmap0:
|
||||
@./bench-rigtorp-hashmap.exe 41
|
||||
@./bench-rigtorp-hashmap.exe 43
|
||||
|
||||
# RIGTORP_MPMC_QUEUE shall point to the directory where the headers are
|
||||
bench-rigtorp-mpmc-queue:
|
||||
@if test -n "$${RIGTORP_MPMC_QUEUE}" ; then $(MAKE) bench-rigtorp-mpmc-queue0 ; else echo "Nothing to be done for RIGTORP_MPMC_QUEUE." ; fi
|
||||
bench-rigtorp-mpmc-queue0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_MPMC_QUEUE}" bench-rigtorp-mpmcqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-mpmcqueue.exe -lpthread
|
||||
@./bench-mpmcqueue.exe 60
|
||||
|
||||
# CTL shall point to the source directory (not where the headers are)
|
||||
bench-ctl:
|
||||
@if test -n "$${CTL}" ; then $(MAKE) bench-ctl0 ; else echo "Nothing to be done for CTL." ; fi
|
||||
|
||||
bench-ctl0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CTL} bench-ctl.c common.c -o bench-ctl.exe
|
||||
@./bench-ctl.exe 10
|
||||
@./bench-ctl.exe 20
|
||||
@./bench-ctl.exe 30
|
||||
@./bench-ctl.exe 40
|
||||
@./bench-ctl.exe 50
|
||||
|
||||
# STC shall point to the source directory (not where the headers are)
|
||||
bench-stc:
|
||||
@if test -n "$${STC}" ; then $(MAKE) bench-stc0 ; else echo "Nothing to be done for STC." ; fi
|
||||
|
||||
bench-stc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${STC}/include bench-stc.c common.c -o bench-stc.exe
|
||||
@./bench-stc.exe 10
|
||||
@./bench-stc.exe 20
|
||||
@./bench-stc.exe 30
|
||||
@./bench-stc.exe 40
|
||||
@./bench-stc.exe 41
|
||||
@./bench-stc.exe 50
|
||||
|
||||
# POTTERY shall point to the source directory (not where the headers are)
|
||||
bench-pottery:
|
||||
@if test -n "$${POTTERY}" ; then $(MAKE) bench-pottery0 ; else echo "Nothing to be done for POTTERY." ; fi
|
||||
|
||||
bench-pottery0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DPOTTERY_AVAILABLE=1 -I $${POTTERY}/include bench-pottery.c common.c -o bench-pottery.exe
|
||||
@./bench-pottery.exe 10
|
||||
@./bench-pottery.exe 20
|
||||
@./bench-pottery.exe 30
|
||||
@./bench-pottery.exe 40
|
||||
@./bench-pottery.exe 41
|
||||
@./bench-pottery.exe 50
|
||||
|
||||
# CCLIB shall point to the source directory of CC (where the headers are)
|
||||
bench-CC:
|
||||
@if test -n "$${CCLIB}" ; then $(MAKE) bench-CC0 ; else echo "Nothing to be done for CC." ; fi
|
||||
|
||||
bench-CC0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CCLIB}/ bench-CC.c common.c -o bench-CC.exe
|
||||
@./bench-CC.exe 10
|
||||
@./bench-CC.exe 20
|
||||
@./bench-CC.exe 40
|
||||
@./bench-CC.exe 41
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
@./bench-mlib.exe 110
|
||||
@./bench-mlib.exe 111
|
||||
@./bench-mlib.exe 112
|
||||
|
||||
bench-rapidjson:
|
||||
@if test -n "$${RAPIDJSON}" ; then $(MAKE) bench-rapidjson0 ; else echo "Nothing to be done for RAPIDJSON." ; fi
|
||||
bench-rapidjson0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RAPIDJSON}/" bench-rapidjson.cpp common.c -o bench-rapidjson.exe
|
||||
@./bench-rapidjson.exe 110
|
||||
@./bench-rapidjson.exe 111
|
||||
@./bench-rapidjson.exe 112
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-plain:
|
||||
@@ -325,27 +442,27 @@ bench-string:
|
||||
@if test -n "$${BSTRLIB}" ; then $(MAKE) bench-string-step1 BENCH_DEF="-DBENCH_CAN_USE_BSTRLIB -I ${BSTRLIB} $${BSTRLIB}/obj/bstrlib.o $${BSTRLIB}/obj/bstraux.o $${BSTRLIB}/obj/bstrwrap.o" ; else $(MAKE) bench-string-step1 ; fi
|
||||
|
||||
bench-string-step1:
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
@if test -n "$${LIBSRT}" ; then $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_LIBSRT -I$${LIBSRT}/src $${LIBSRT}/src/.libs/libsrt.a" ; else $(MAKE) bench-string-step2 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
#NOTE: Need to build by hand sds.o since it is not build by default and sds.c is not compatible with C++
|
||||
bench-string-step2:
|
||||
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step3 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step3 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step3:
|
||||
@if test -n "$${RAPIDSTRING}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_RAPIDSTRING -I$${RAPIDSTRING}/ " ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
@if test -n "$${SDS}" ; then $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF) -fpermissive -DBENCH_CAN_USE_SDS -I$${SDS}/ $${SDS}/sds.o" ; else $(MAKE) bench-string-step4 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step4:
|
||||
@if test -n "$${GLIB}" ; then $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_GLIB $$(pkg-config --cflags --libs glib-2.0)" ; else $(MAKE) bench-string-step5 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step5:
|
||||
@if test -n "$${POTTERY}" ; then $(MAKE) bench-string-step6 BENCH_DEF="$(BENCH_DEF) -DBENCH_CAN_USE_POTTERY -I$${POTTERY}/include -I$${POTTERY}/util/ $${POTTERY}/util/pottery/string/string.c" ; else $(MAKE) bench-string-step6 BENCH_DEF="$(BENCH_DEF)"; fi
|
||||
|
||||
bench-string-step6:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string.cpp common.c $(BENCH_DEF) -o bench-string.exe
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DBENCH_CAN_USE_STL -DBENCH_CAN_USE_MSTARLIB bench-string-2.cpp common.c $(BENCH_DEF) -o bench-string-2.exe
|
||||
@./bench-string.exe
|
||||
@./bench-string-2.exe 2000000 0
|
||||
@./bench-string-2.exe 2000000 1
|
||||
@./bench-string-2.exe 2000000 2
|
||||
@./bench-string-2.exe 2000000 3
|
||||
@./bench-string-2.exe 2000000 4
|
||||
@./bench-string-2.exe 2000000 5
|
||||
|
||||
bench-string-pgo:
|
||||
$(MAKE) bench-string XCFLAGS="-fprofile-generate=pgo"
|
||||
@@ -353,11 +470,18 @@ bench-string-pgo:
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-find-sort:
|
||||
g++ bench-find-sort.cpp -O2 -march=native -std=c++11 -I.. -g common.c -o bench-find-sort.exe
|
||||
./bench-find-sort.exe 10000000
|
||||
|
||||
############################################################################
|
||||
|
||||
clean:
|
||||
$(RM) *.o bench-*.exe
|
||||
$(RM) bench-*.s *~ massif.out.*
|
||||
$(RM) plot-*.dat
|
||||
$(RM) pgo
|
||||
$(RM) tmp-serial.*
|
||||
cd nucleotide && $(MAKE) clean
|
||||
|
||||
############################################################################
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "cc.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec( unsigned int ) a1, a2;
|
||||
init(&a1);
|
||||
init(&a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
push(&a1, rand_get() );
|
||||
push(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *get(&a1, i ) * *get(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&a1);
|
||||
cleanup(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
list( unsigned int ) a1, a2;
|
||||
init(&a1);
|
||||
init(&a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
push(&a1, rand_get() );
|
||||
push(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned *it1 = first( &a1 ), *it2 = first( &a2 ); it1 != end( &a1 ); it1 = next( &a1, it1 ), it2 = next(&a2, it2) ) {
|
||||
s += *it1 * *it2;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&a1);
|
||||
cleanup(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
map( unsigned long, unsigned long ) dict;
|
||||
init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
insert(&dict, key, value);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long key = rand_get();
|
||||
const unsigned long *val = get(&dict, key);
|
||||
if (val != NULL)
|
||||
s += *val;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&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 bool char_cmp (const char_array_t *a, const char_array_t *b) { return strcmp(a->a,b->a); }
|
||||
static inline void char_clear (char_array_t *a) { (void)a; }
|
||||
static inline size_t char_hash(const char_array_t *a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a->a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
#define CC_DTOR char_array_t, { char_clear(&val); }
|
||||
#define CC_CMPR char_array_t, { return char_cmp(&val_1, &val_2); }
|
||||
#define CC_HASH char_array_t, { return char_hash(&val); }
|
||||
#include "cc.h"
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
map( char_array_t, char_array_t) dict;
|
||||
init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
insert(&dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
const char_array_t *val = get(&dict, s1);
|
||||
if (val != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cleanup(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// CMC list are dynamic array
|
||||
#define MY_LIST_PARAMS (list_uint, list_uint_s, , , unsigned int)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, LIST, MY_LIST_PARAMS, (STR))
|
||||
|
||||
struct list_uint_s_fval list_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
struct list_uint_s *a1 = list_uint_new(1, &list_fval);
|
||||
struct list_uint_s *a2 = list_uint_new(1, &list_fval);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
list_uint_push_back(a1, rand_get() );
|
||||
list_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += list_uint_get(a1, i ) * list_uint_get(a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
list_uint_free(a1);
|
||||
list_uint_free(a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define my_cmp(a,b) ( (a) < (b) ? -1 : (a) > (b) )
|
||||
|
||||
#define MY_TMAP_PARAMS (tree_ulong, tree_ulong_s, , unsigned long, bool)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, TREEMAP, MY_TMAP_PARAMS, (STR))
|
||||
|
||||
int cmp_ulong(unsigned long a, unsigned long b) { return my_cmp(a,b); }
|
||||
|
||||
struct tree_ulong_s_fkey tree_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
struct tree_ulong_s_fval tree_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
struct tree_ulong_s *tree;
|
||||
tree = tree_ulong_new(&tree_fkey, &tree_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
tree_ulong_insert(tree, j, true);
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (tree_ulong_get_ref(tree, j) != 0)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
tree_ulong_free(tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
#define hash_func(a) kh_int64_hash_func(a)
|
||||
size_t hash_ulong(unsigned long a)
|
||||
{
|
||||
return ( (a) >> 33 ) ^ (a) ^ ((a) << 11);
|
||||
}
|
||||
|
||||
#define MY_DICT_PARAMS (hmap, hmap_s, , unsigned long, unsigned long)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct hmap_s_fkey hmap_fkey = { .cmp = cmp_ulong,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = hash_ulong,
|
||||
.pri = NULL };
|
||||
|
||||
struct hmap_s_fval hmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
struct hmap_s *dict = hmap_new(16, 0.7, &hmap_fkey, &hmap_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
hmap_insert(dict, rand_get(), rand_get());
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long *val = hmap_get_ref(dict, rand_get());
|
||||
if (val != 0)
|
||||
s += *val;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
hmap_free(dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#if 0 // Not working issue in using not integer types
|
||||
|
||||
typedef struct {
|
||||
char a[256];
|
||||
} char_array_t;
|
||||
static inline int char_cmp (const char_array_t a, const char_array_t b) { return strcmp(a.a,b.a); }
|
||||
static inline size_t char_hash(const char_array_t a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define MY_DICTB_PARAMS (bhmap, bhmap_s, , char_array_t, char_array_t)
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, HASHMAP, MY_DICT_PARAMS, (STR))
|
||||
|
||||
struct bhmap_s_fkey bhmap_fkey = { .cmp = char_cmp,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = char_hash,
|
||||
.pri = NULL };
|
||||
|
||||
struct bhmap_s_fval bhmap_fval = { .cmp = NULL,
|
||||
.cpy = NULL,
|
||||
.str = NULL,
|
||||
.free = NULL,
|
||||
.hash = NULL,
|
||||
.pri = NULL };
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
struct bhmap_s *dict = bhmap_new(16, 0.7, &bhmap_fkey, &bhmap_fval);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
bhmap_insert(dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1.a, "%u", rand_get() );
|
||||
char_array_t *val = bhmap_get_ref(dict, s1);
|
||||
if (val != 0)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
bhmap_free(dict);
|
||||
}
|
||||
#endif
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
//{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CMC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-core.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/********************************************************************************************/
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec_uint a1 = vec_uint_init();
|
||||
vec_uint a2 = vec_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_uint_push_back(&a1, rand_get() );
|
||||
vec_uint_push_back(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *vec_uint_at(&a1, i ) * *vec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
vec_uint_free(&a1);
|
||||
vec_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/forward_list.h"
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
slist_uint a1 = slist_uint_init();
|
||||
slist_uint a2 = slist_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
slist_uint_push_front(&a1, rand_get());
|
||||
slist_uint_push_front(&a2, rand_get());
|
||||
}
|
||||
unsigned int s = 0;
|
||||
slist_uint_it it1 = slist_uint_begin(&a1);
|
||||
slist_uint_it it2 = slist_uint_begin(&a2);
|
||||
for( ; !slist_uint_it_done(&it1) ;
|
||||
slist_uint_it_next(&it1), slist_uint_it_next(&it2)) {
|
||||
s += *slist_uint_it_ref(&it1) * *slist_uint_it_ref(&it2);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
slist_uint_free(&a1);
|
||||
slist_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T ulong
|
||||
#include "ctl/set.h"
|
||||
|
||||
static inline int
|
||||
int_cmp(ulong *a, ulong *b) {
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set_ulong tree = set_ulong_init (int_cmp);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set_ulong_insert (&tree, rand_get() );
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (set_ulong_find_node(&tree, j) != NULL)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
set_ulong_free(&tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} pair_ulong;
|
||||
|
||||
// Use of M*LIB hash function
|
||||
static inline size_t
|
||||
pair_ulong_hash(pair_ulong *a)
|
||||
{
|
||||
return M_HASH_DEFAULT(a->key);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pair_ulong_equal(pair_ulong *a, pair_ulong *b)
|
||||
{
|
||||
return a->key == b->key;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pair_ulong_free(pair_ulong *a) {
|
||||
(void) a;
|
||||
}
|
||||
|
||||
static inline pair_ulong
|
||||
pair_ulong_copy(pair_ulong *self) {
|
||||
return (pair_ulong) { .key = self->key, .value = self->value };
|
||||
}
|
||||
|
||||
#define T pair_ulong
|
||||
#include <ctl/unordered_map.h>
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
umap_pair_ulong dict = umap_pair_ulong_init(pair_ulong_hash, pair_ulong_equal);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
umap_pair_ulong_insert(&dict, (pair_ulong) { key, value });
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_it it = umap_pair_ulong_find(&dict, (pair_ulong) { rand_get() , 0 } );
|
||||
if (!umap_pair_ulong_it_done(&it) )
|
||||
s += it.ref->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
umap_pair_ulong_free(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T float
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vec_float a1 = vec_float_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_float_push_back(&a1, rand_get());
|
||||
}
|
||||
vec_float_sort(&a1);
|
||||
g_result = *vec_float_at(&a1, 0);
|
||||
vec_float_free(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 50, "Sort", 10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CTL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hash_table7.hpp"
|
||||
|
||||
using namespace emhash7;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashMap<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
HashMap<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("EMHASH", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "emilib/hash_map.hpp"
|
||||
|
||||
using namespace emilib;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashMap<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
HashMap<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("EMILIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// program to find longest contiguous subsequence
|
||||
// based on https://www.geeksforgeeks.org/longest-consecutive-subsequence/
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int cpp_find_longest(int arr[], int n)
|
||||
{
|
||||
unordered_set<int> S;
|
||||
int ans = 0;
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
S.insert(arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
if (S.find(arr[i] - 1) == S.end()) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (S.find(j) != S.end())
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = max(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(int a, unsigned char c) { return a == ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
static inline void oor_set(int *a, unsigned char c) { *a = ((c == 0) ? INT_MIN : INT_MAX); }
|
||||
|
||||
DICT_OASET_DEF(dict_int, int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)))
|
||||
|
||||
// Returns length of the longest contiguous subsequence
|
||||
int mlib_find_longest(int arr[], int n)
|
||||
{
|
||||
dict_int_t S;
|
||||
int ans = 0;
|
||||
|
||||
dict_int_init(S);
|
||||
|
||||
// Hash all the array elements
|
||||
for (int i = 0; i < n; i++)
|
||||
dict_int_push(S, arr[i]);
|
||||
|
||||
// check each possible sequence from
|
||||
// the start then update optimal length
|
||||
for (int i = 0; i < n; i++) {
|
||||
// if current element is the starting
|
||||
// element of a sequence
|
||||
int *p = dict_int_get(S, arr[i]-1);
|
||||
if (p == NULL) {
|
||||
// Then check for next elements
|
||||
// in the sequence
|
||||
int j = arr[i] + 1;
|
||||
while (dict_int_get(S, j) != NULL)
|
||||
j++;
|
||||
|
||||
// update optimal length if
|
||||
// this length is more
|
||||
ans = M_MAX(ans, j - arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
dict_int_clear(S);
|
||||
return ans;
|
||||
}
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = argc == 1 ? 10000 : atoi(argv[1]);
|
||||
int *arr = (int*) malloc(n * sizeof(int));
|
||||
for(int i = 0; i < n; i++)
|
||||
arr[i] = rand_get();
|
||||
|
||||
unsigned long long t0 = cputime();
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< cpp_find_longest(arr, n) << endl;
|
||||
|
||||
unsigned long long t1 = cputime();
|
||||
|
||||
cout << "Length of the Longest contiguous subsequence is "
|
||||
<< mlib_find_longest(arr, n) << endl;
|
||||
unsigned long long t2 = cputime();
|
||||
|
||||
cout << "Time C++: " << (t1-t0) << " Time M*LIB: " << (t2-t1) << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -134,6 +134,6 @@ const config_func_t table[] = {
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("DENSE-HASPMAP", numberof(table), table, argc, argv);
|
||||
test("FLAT-HASPMAP", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Needed due to compilation error in pool.h
|
||||
#include <pthread.h>
|
||||
|
||||
#include "dynamic.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
sv_t *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
sv_t *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
srt_vector *a1 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
srt_vector *a2 = sv_alloc ( sizeof (unsigned int), 16, NULL);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
@@ -48,7 +48,7 @@ static int cmp_float (const void *a, const void *b)
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
sv_t *a1 = sv_alloc(sizeof(float), 16, cmp_float);
|
||||
srt_vector *a1 = sv_alloc(sizeof(float), 16, cmp_float);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
unsigned int value = rand_get();
|
||||
sv_push(&a1, &value );
|
||||
@@ -72,13 +72,3 @@ int main(int argc, const char *argv[])
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int n = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
if (n == 20)
|
||||
test_function("Array", 100000000, test_array);
|
||||
if (n == 50)
|
||||
test_function("Sort", 10000000, test_sort);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,18 @@
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-bptree.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-mempool.h"
|
||||
#include "m-string.h"
|
||||
#include "m-buffer.h"
|
||||
#include "m-mutex.h"
|
||||
#include "m-thread.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-concurrent.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-serial-bin.h"
|
||||
#include "m-serial-json.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -40,6 +44,26 @@ static void test_array(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
DEQUE_DEF(deque_uint, unsigned int)
|
||||
|
||||
static void test_deque(size_t n)
|
||||
{
|
||||
M_LET(a1, a2, DEQUE_OPLIST(deque_uint)) {
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
deque_uint_push_back(a1, rand_get() );
|
||||
deque_uint_push_back(a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
deque_uint_it_t it1, it2;
|
||||
for(deque_uint_it(it1, a1), deque_uint_it(it2, a2) ; !deque_uint_end_p(it1) ; deque_uint_next(it1), deque_uint_next(it2)) {
|
||||
s += *deque_uint_cref(it1 ) * *deque_uint_cref(it2 );
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// Two benched mode: with or without mempool
|
||||
#ifdef USE_MEMPOOL
|
||||
LIST_DEF(list_uint, unsigned int, (MEMPOOL( list_mpool), MEMPOOL_LINKAGE(static)))
|
||||
@@ -719,7 +743,6 @@ static void test_queue_single_bulk(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
DEQUE_DEF(deque_uint, unsigned int)
|
||||
CONCURRENT_DEF(cdeque_uint, deque_uint_t, M_OPEXTEND(DEQUE_OPLIST(deque_uint, M_DEFAULT_OPLIST), PUSH(deque_uint_push_front)))
|
||||
|
||||
DEQUE_DEF(deque_ull, unsigned long long)
|
||||
@@ -837,12 +860,198 @@ static void test_core_hash(size_t n)
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(vector_string, string_t)
|
||||
|
||||
vector_string_t vstring;
|
||||
vector_string_t vstring2;
|
||||
|
||||
static void
|
||||
bench_vector_string_init(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu", i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
vector_string_init(vstring2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_init_big(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
vector_string_init(vstring2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_bin_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_write_t) {
|
||||
vector_string_out_serial(serial, vstring);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.dat", "rb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_read_t) {
|
||||
vector_string_in_serial(vstring2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_write_t) {
|
||||
vector_string_out_serial(serial, vstring);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_read_t) {
|
||||
vector_string_in_serial(vstring2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (!vector_string_equal_p(vstring, vstring2)) {
|
||||
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
|
||||
abort();
|
||||
}
|
||||
vector_string_clear(vstring);
|
||||
vector_string_clear(vstring2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
ARRAY_DEF(vector_ulong, unsigned long)
|
||||
|
||||
vector_ulong_t vulong;
|
||||
vector_ulong_t vulong2;
|
||||
|
||||
static void
|
||||
bench_vector_ulong_init(size_t n)
|
||||
{
|
||||
vector_ulong_init(vulong);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
vector_ulong_push_back(vulong, i*i);
|
||||
}
|
||||
vector_ulong_init(vulong2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_bin_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_write_t) {
|
||||
vector_ulong_out_serial(serial, vulong);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.dat", "rb");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_bin_read_t) {
|
||||
vector_ulong_in_serial(vulong2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_write_t) {
|
||||
vector_ulong_out_serial(serial, vulong);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
M_LET( (serial, f), m_serial_json_read_t) {
|
||||
vector_ulong_in_serial(vulong2, serial);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (!vector_ulong_equal_p(vulong, vulong2)) {
|
||||
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
|
||||
abort();
|
||||
}
|
||||
vector_ulong_clear(vulong);
|
||||
vector_ulong_clear(vulong2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 11, "DPList", 10000000, 0, test_dlist, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 21, "Deque", 100000000, 0, test_deque, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 31, "B+tree", 1000000, 0, test_bptree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
@@ -861,11 +1070,17 @@ const config_func_t table[] = {
|
||||
{ 65,"Queue Concurrent", 1000000, 0, test_queue_concurrent, 0},
|
||||
{ 66,"Queue SPSC(Bulk)", 1000000, 0, test_queue_single_bulk, 0},
|
||||
{ 70,"M_HASH", 100000000, test_hash_prepare, test_hash, test_hash_final},
|
||||
{ 71,"Core Hash", 100000000, test_hash_prepare, test_core_hash, test_hash_final}
|
||||
{ 71,"Core Hash", 100000000, test_hash_prepare, test_core_hash, test_hash_final},
|
||||
{100, "serial-bin STR", 10000000, bench_vector_string_init, bench_vector_string_bin_run, bench_vector_string_clear},
|
||||
{101, "serial-bin STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_bin_run, bench_vector_string_clear},
|
||||
{102, "serial-bin INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_bin_run, bench_vector_ulong_clear},
|
||||
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("M-LIB", numberof(table), table, argc, argv);
|
||||
test("M*LIB", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ struct Pixel
|
||||
unsigned char r, g, b;
|
||||
};
|
||||
|
||||
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT)) )
|
||||
ARRAY_DEF(array_pixel, struct Pixel, (INIT(M_NOTHING_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT) ))
|
||||
|
||||
void UseMlib(void)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POTTERY_VECTOR_PREFIX vec_uint
|
||||
#define POTTERY_VECTOR_VALUE_TYPE unsigned int
|
||||
#define POTTERY_VECTOR_LIFECYCLE_BY_VALUE 1
|
||||
#include "pottery/vector/pottery_vector_static.t.h"
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec_uint_t a1, a2;
|
||||
|
||||
vec_uint_init(&a1);
|
||||
vec_uint_init(&a2);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_uint_insert_last(&a1, rand_get() );
|
||||
vec_uint_insert_last(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *vec_uint_at(&a1, i ) * *vec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
vec_uint_destroy(&a1);
|
||||
vec_uint_destroy(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct foo_s {
|
||||
struct foo_s* next;
|
||||
struct foo_s* previous;
|
||||
int data;
|
||||
} foo_t;
|
||||
|
||||
#define POTTERY_DOUBLY_LINKED_LIST_PREFIX foo_list
|
||||
#define POTTERY_DOUBLY_LINKED_LIST_VALUE_TYPE foo_t
|
||||
#include "pottery/doubly_linked_list/pottery_doubly_linked_list_static.t.h"
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
foo_list_t a1, a2;
|
||||
foo_list_init(&a1);
|
||||
foo_list_init(&a2);
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
foo_t *tmp = malloc(sizeof (foo_t));
|
||||
if (tmp == NULL) abort();
|
||||
tmp->data = rand_get();
|
||||
foo_list_link_last(&a1, tmp);
|
||||
|
||||
tmp = malloc(sizeof (foo_t));
|
||||
if (tmp == NULL) abort();
|
||||
tmp->data = rand_get();
|
||||
foo_list_link_last(&a2, tmp);
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(foo_t *it1 = foo_list_first(&a1), *it2 = foo_list_first(&a2) ;
|
||||
foo_list_entry_exists(&a1, it1) ;
|
||||
it1 = foo_list_next(&a1, it1), it2 = foo_list_next(&a2, it2)) {
|
||||
s += it1->data * it2->data;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
for(foo_t *it1 = foo_list_first(&a1);
|
||||
foo_list_entry_exists(&a1, it1) ;
|
||||
) {
|
||||
foo_t *tmp = it1;
|
||||
it1 = foo_list_next(&a1, it1);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
for(foo_t *it1 = foo_list_first(&a2);
|
||||
foo_list_entry_exists(&a2, it1) ;
|
||||
) {
|
||||
foo_t *tmp = it1;
|
||||
it1 = foo_list_next(&a2, it1);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// ERROR: it returns the wrong result.
|
||||
#define POTTERY_TREE_MAP_PREFIX set_ulong
|
||||
#define POTTERY_TREE_MAP_VALUE_TYPE unsigned long
|
||||
#define POTTERY_TREE_MAP_LIFECYCLE_MOVE_BY_VALUE 1
|
||||
#define POTTERY_TREE_MAP_COMPARE_THREE_WAY(a,b) ((a) < (b) ? -1 : (a) > (b))
|
||||
#define POTTERY_TREE_MAP_LIFECYCLE_DESTROY(a) (void) a
|
||||
#include "pottery/tree_map/pottery_tree_map_static.t.h"
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set_ulong_t tree;
|
||||
set_ulong_init(&tree);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set_ulong_insert(&tree, rand_get() );
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (set_ulong_find(&tree, &j ) != NULL)
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
set_ulong_destroy(&tree);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#include "m-core.h" // For M_HASH_DEFAULT
|
||||
typedef struct bar_s {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} bar_t;
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_PREFIX map_ulong
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_VALUE_TYPE bar_t
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_TYPE unsigned long
|
||||
#define POTTERY_OPEN_HASH_MAP_REF_KEY(v) v->key
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_HASH(x) M_HASH_DEFAULT(x)
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_EQUAL(x, y) x == y
|
||||
#define POTTERY_OPEN_HASH_MAP_LIFECYCLE_MOVE(p,q) memcpy(p, q, sizeof (bar_t))
|
||||
|
||||
#include "pottery/open_hash_map/pottery_open_hash_map_static.t.h"
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
map_ulong_t dict;
|
||||
map_ulong_init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
bar_t * kyle = pottery_null;
|
||||
map_ulong_emplace_key(&dict, key, &kyle, pottery_null);
|
||||
kyle->key = key;
|
||||
kyle->value = value;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
bar_t *kyle = map_ulong_find(&dict, rand_get());
|
||||
if (kyle != NULL)
|
||||
s += kyle->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
map_ulong_destroy(&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 void char_clear (char_array_t *a) { (void)a; }
|
||||
static inline size_t char_hash(const char_array_t *a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a->a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
typedef struct bars_s {
|
||||
char_array_t key;
|
||||
char_array_t value;
|
||||
} bars_t;
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_PREFIX map_achar
|
||||
|
||||
#define POTTERY_OPEN_HASH_MAP_VALUE_TYPE bars_t
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_TYPE char_array_t
|
||||
#define POTTERY_OPEN_HASH_MAP_REF_KEY(v) v->key
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_HASH(x) char_hash(&x)
|
||||
#define POTTERY_OPEN_HASH_MAP_KEY_EQUAL(x, y) char_equal_p(x, y)
|
||||
#define POTTERY_OPEN_HASH_MAP_LIFECYCLE_MOVE(p,q) memcpy(p, q, sizeof (bars_t))
|
||||
|
||||
#include "pottery/open_hash_map/pottery_open_hash_map_static.t.h"
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
map_achar_t dict;
|
||||
map_achar_init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
bars_t * kyle = pottery_null;
|
||||
map_achar_emplace_key(&dict, s1, &kyle, pottery_null);
|
||||
char_set(&kyle->key, s1);
|
||||
char_set(&kyle->value, 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());
|
||||
bars_t *kyle = map_achar_find(&dict, s1);
|
||||
if (kyle != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
map_achar_destroy(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POTTERY_VECTOR_PREFIX vec_float
|
||||
#define POTTERY_VECTOR_VALUE_TYPE float
|
||||
#define POTTERY_VECTOR_LIFECYCLE_BY_VALUE 1
|
||||
#include "pottery/vector/pottery_vector_static.t.h"
|
||||
|
||||
#define POTTERY_INTRO_SORT_PREFIX sort_float
|
||||
#define POTTERY_INTRO_SORT_VALUE_TYPE float
|
||||
#define POTTERY_INTRO_SORT_LIFECYCLE_MOVE_BY_VALUE 1
|
||||
#define POTTERY_INTRO_SORT_COMPARE_THREE_WAY(x, y) ( *x < *y ? -1 : *x > *y)
|
||||
#include "pottery/intro_sort/pottery_intro_sort_static.t.h"
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vec_float_t a1;
|
||||
vec_float_init(&a1);
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_float_insert_last(&a1, rand_get() );
|
||||
}
|
||||
sort_float(vec_float_at(&a1, 0), n);
|
||||
g_result = *vec_float_at(&a1, 0);
|
||||
vec_float_destroy(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("POTTERY", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#define NDEBUG
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<string> vstring;
|
||||
vector<string> vstring2;
|
||||
|
||||
static void
|
||||
bench_vector_string_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu", i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_init_big(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
char buff[100];
|
||||
snprintf(buff, sizeof(buff), "%zu%zu%zu%zu%zu%zu", i, i, i, i, i, i);
|
||||
std::string s(buff);
|
||||
vstring.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vstring.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.String(vstring[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vstring2.push_back(s.GetString());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vstring2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (vstring != vstring2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
vector<unsigned long> vulong;
|
||||
vector<unsigned long> vulong2;
|
||||
|
||||
static void
|
||||
bench_vector_ulong_init(size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
vulong.push_back(i*i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vulong.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
if (!f) abort();
|
||||
{
|
||||
// Prepare writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
typedef rapidjson::AutoUTFOutputStream<unsigned, rapidjson::FileWriteStream> OutputStream;
|
||||
rapidjson::FileWriteStream os(f, writeBuffer, sizeof(writeBuffer));
|
||||
OutputStream eos(os, rapidjson::kUTF8, false);
|
||||
rapidjson::PrettyWriter<OutputStream, rapidjson::UTF8<>, rapidjson::AutoUTF<unsigned> > writer(eos);
|
||||
|
||||
writer.StartArray();
|
||||
for(size_t i = 0; i < n; i++){
|
||||
writer.Int64(vulong[i]);
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
f = fopen("tmp-serial.json", "rt");
|
||||
if (!f) abort();
|
||||
{
|
||||
char readBuffer[65536];
|
||||
rapidjson::FileReadStream is(f, readBuffer, sizeof(readBuffer));
|
||||
rapidjson::Document d;
|
||||
d.ParseStream(is);
|
||||
for(size_t i = 0; i < d.Size(); i++) {
|
||||
rapidjson::Value& s = d[i];
|
||||
vulong2.push_back(s.GetInt64());
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (vulong2.size() != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (vulong != vulong2) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{110, "serial-json STR", 10000000, bench_vector_string_init, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{111, "serial-json STR.big", 10000000, bench_vector_string_init_big, bench_vector_string_json_run, bench_vector_string_clear},
|
||||
{112, "serial-json INT", 10000000, bench_vector_ulong_init, bench_vector_ulong_json_run, bench_vector_ulong_clear}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RAPIDJSON", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <rigtorp/MPMCQueue.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
rigtorp::MPMCQueue<unsigned int> g_buff(4*64);
|
||||
rigtorp::MPMCQueue<unsigned long long> g_final(4*64);
|
||||
|
||||
static void final(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*) arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long j, s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_final.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void conso(void *arg)
|
||||
{
|
||||
unsigned int j;
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
unsigned long long s = 0;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.pop(j);
|
||||
s += j;
|
||||
}
|
||||
g_final.push(s);
|
||||
}
|
||||
|
||||
static void prod(void *arg)
|
||||
{
|
||||
size_t *p_n = (size_t*)arg;
|
||||
size_t n = *p_n;
|
||||
size_t r = n;
|
||||
for(unsigned int i = 0; i < n;i++) {
|
||||
g_buff.push(r);
|
||||
r = r * 31421U + 6927U;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_queue(size_t n)
|
||||
{
|
||||
const int cpu_count = get_cpu_count();
|
||||
const int prod_count = cpu_count/2;
|
||||
const int conso_count = cpu_count - prod_count;
|
||||
if (cpu_count < 2) {
|
||||
fprintf(stderr, "WARNING: Can not measure Buffer performance.\n");
|
||||
return;
|
||||
}
|
||||
rand_get();
|
||||
// Create thread
|
||||
m_thread_t idx_p[prod_count];
|
||||
m_thread_t idx_c[conso_count];
|
||||
m_thread_t idx_final;
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_create (idx_p[i], prod, &n);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_create (idx_c[i], conso, &n);
|
||||
}
|
||||
size_t n2 = conso_count;
|
||||
m_thread_create(idx_final, final, &n2);
|
||||
|
||||
// Wait for jobs to be done.
|
||||
for(int i = 0; i < prod_count; i++) {
|
||||
m_thread_join(idx_p[i]);
|
||||
}
|
||||
for(int i = 0; i < conso_count; i++) {
|
||||
m_thread_join(idx_c[i]);
|
||||
}
|
||||
m_thread_join(idx_final);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("RIGTORP-MPMC-QUEUE", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_val unsigned int
|
||||
#define i_tag uint
|
||||
#include <stc/cvec.h>
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
cvec_uint a1 = cvec_uint_init(), a2 = cvec_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
cvec_uint_push_back(&a1, rand_get() );
|
||||
cvec_uint_push_back(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *cvec_uint_at(&a1, i ) * *cvec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cvec_uint_drop(&a1);
|
||||
cvec_uint_drop(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
#define i_val unsigned int
|
||||
#define i_tag uint
|
||||
#include <stc/clist.h>
|
||||
|
||||
static void test_list(size_t n)
|
||||
{
|
||||
clist_uint a1 = clist_uint_init(), a2 = clist_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
clist_uint_push_front(&a1, rand_get() );
|
||||
clist_uint_push_front(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(clist_uint_iter it1 = clist_uint_begin(&a1), it2 = clist_uint_begin(&a2) ;
|
||||
it1.ref != clist_uint_end(&a1).ref ;
|
||||
clist_uint_next(&it1), clist_uint_next(&it2) ) {
|
||||
s += *it1.ref * *it2.ref;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
clist_uint_drop(&a1);
|
||||
clist_uint_drop(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_tag ulong
|
||||
#define i_key unsigned long
|
||||
#include <stc/csset.h>
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
csset_ulong tree = csset_ulong_init();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
csset_ulong_insert(&tree, rand_get() );
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (csset_ulong_get(&tree, j ) != NULL)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
csset_ulong_drop(&tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_tag ulong
|
||||
#define i_key unsigned long
|
||||
#define i_val unsigned long
|
||||
#include <stc/cmap.h>
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
cmap_ulong dict = cmap_ulong_init();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
cmap_ulong_insert_or_assign(&dict, key, value);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
const cmap_ulong_value*val = cmap_ulong_get(&dict, rand_get());
|
||||
if (val != NULL)
|
||||
s += val->second;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cmap_ulong_drop(&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 void char_clear (char_array_t *a) { (void)a; }
|
||||
static inline size_t char_hash(const char_array_t *a) {
|
||||
size_t hash = 0;
|
||||
const char *s = a->a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define i_tag achar
|
||||
#define i_key char_array_t
|
||||
#define i_val char_array_t
|
||||
#define i_hash char_hash
|
||||
#define i_eq char_equal_p
|
||||
#include <stc/cmap.h>
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
cmap_achar dict = cmap_achar_init();
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
cmap_achar_insert_or_assign(&dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_t s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
const cmap_achar_value*val = cmap_achar_get(&dict, s1);
|
||||
if (val != NULL)
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
cmap_achar_drop(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define i_val float
|
||||
#define i_tag float
|
||||
#include <stc/cvec.h>
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
cvec_float a1 = cvec_float_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
cvec_float_push_back(&a1, rand_get() );
|
||||
}
|
||||
cvec_float_sort(&a1);
|
||||
g_result = *cvec_float_at(&a1, 0);
|
||||
cvec_float_drop(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "Sort",10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("STC", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
@@ -53,6 +54,23 @@ static void test_array(size_t n)
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_deque(size_t n)
|
||||
{
|
||||
deque<unsigned int> a1, a2;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
a1.push_back(rand_get() );
|
||||
a2.push_back(rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(auto it1 = a1.cbegin(), it2 = a2.cbegin();
|
||||
it1 != a1.cend() ;it1++, it2++) {
|
||||
s += *it1 * *it2;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set<unsigned long> tree;
|
||||
@@ -241,6 +259,7 @@ static void test_stable_sort(size_t n)
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 21, "Deque", 100000000, 0, test_deque, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict(m)", 1000000, 0, test_dict1, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* 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:
|
||||
@@ -22,11 +22,14 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define NDEBUG
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define M_USE_SMALL_NAME 0
|
||||
#include "common.h"
|
||||
|
||||
#include "m-string.h"
|
||||
@@ -37,16 +40,16 @@ extern "C" {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
#include "rapidstring.h"
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
#include "bstrlib.h"
|
||||
#include "bstrwrap.h"
|
||||
#include "bstraux.h"
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
#include "pottery/string/string.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BENCH
|
||||
* 2000000
|
||||
@@ -77,6 +80,17 @@ void random_permutation(unsigned n)
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void replace_all_stl(string &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_stl(unsigned n)
|
||||
{
|
||||
vector<string> tab;
|
||||
@@ -89,55 +103,36 @@ size_t bench_stl(unsigned n)
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find("1234", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
|
||||
pos = 0;
|
||||
do {
|
||||
pos = str.find("56789", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
replace_all_stl(str, "1234", "WELL");
|
||||
replace_all_stl(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
|
||||
size_t bench_mlib(unsigned n)
|
||||
{
|
||||
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
|
||||
m_string_t *tab = (m_string_t*) malloc (n * sizeof (m_string_t));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_init(tab[i]);
|
||||
string_printf(tab[i], "%u", rand_get());
|
||||
m_string_init(tab[i]);
|
||||
m_string_set_ui(tab[i], rand_get());
|
||||
}
|
||||
// P2
|
||||
string_t str;
|
||||
string_init(str);
|
||||
m_string_t str;
|
||||
m_string_init(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_cat(str, tab[permutation_tab[i]]);
|
||||
m_string_cat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
size_t i = 0;
|
||||
do {
|
||||
i = string_replace_str(str, "1234", "WELL", i);
|
||||
} while (i != STRING_FAILURE);
|
||||
// P4
|
||||
i = 0;
|
||||
do {
|
||||
i = string_replace_str(str, "56789", "DONE", i);
|
||||
} while (i != STRING_FAILURE);
|
||||
size_t length = string_size(str);
|
||||
m_string_replace_all_cstr(str, "1234", "WELL");
|
||||
m_string_replace_all_cstr(str, "56789", "DONE");
|
||||
size_t length = m_string_size(str);
|
||||
|
||||
// Clean
|
||||
string_clear(str);
|
||||
m_string_clear(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_clear(tab[i]);
|
||||
m_string_clear(tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
@@ -145,6 +140,18 @@ size_t bench_mlib(unsigned n)
|
||||
|
||||
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
|
||||
static void replace_all_bstrlib(CBString &str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find(pattern, pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
}
|
||||
|
||||
size_t bench_bstrlib(unsigned n)
|
||||
{
|
||||
vector<CBString> tab;
|
||||
@@ -160,21 +167,8 @@ size_t bench_bstrlib(unsigned n)
|
||||
str += tab[permutation_tab[i]];
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
do {
|
||||
pos = str.find("1234", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
|
||||
pos = 0;
|
||||
do {
|
||||
pos = str.find("56789", pos);
|
||||
if (pos != string::npos) {
|
||||
str.replace (pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != string::npos);
|
||||
replace_all_bstrlib(str, "1234", "WELL");
|
||||
replace_all_bstrlib(str, "56789", "DONE");
|
||||
|
||||
return str.length();
|
||||
}
|
||||
@@ -191,6 +185,19 @@ sds SDS_replace_at(sds str, size_t pos, size_t len, const char str2[])
|
||||
return a;
|
||||
}
|
||||
|
||||
sds replace_all_sds(sds str, const char pattern[], const char replace[])
|
||||
{
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], pattern);
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, strlen(pattern), replace);
|
||||
}
|
||||
} while (pos != -1U);
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t bench_sds(unsigned n)
|
||||
{
|
||||
sds *tab = (sds*) malloc (n * sizeof (sds));
|
||||
@@ -205,25 +212,10 @@ size_t bench_sds(unsigned n)
|
||||
str = sdscat(str, tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], "1234");
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
// P4
|
||||
pos = 0;
|
||||
do {
|
||||
char *p = strstr(&str[pos], "56789");
|
||||
pos = p == NULL ? -1U : (p - str);
|
||||
if (pos != -1U) {
|
||||
str = SDS_replace_at(str, pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
size_t length = sdslen(str);
|
||||
str = replace_all_sds(str, "1234", "WELL");
|
||||
str = replace_all_sds(str, "56789", "DONE");
|
||||
// Clean
|
||||
size_t length = sdslen(str);
|
||||
sdsfree(str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
sdsfree(tab[i]);
|
||||
@@ -233,58 +225,52 @@ size_t bench_sds(unsigned n)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
void RAPIDSTRING_replace_at(rapidstring *str, size_t pos, size_t len, const char str2[])
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
|
||||
size_t pottery_find_cstr(string_t *b, size_t index, const char *pattern)
|
||||
{
|
||||
// simple implementation as replace is not available
|
||||
rapidstring a;
|
||||
|
||||
rs_init_w_n(&a, rs_data(str), pos);
|
||||
rs_cat(&a, str2);
|
||||
rs_cat(&a, &rs_data(str)[pos+len] );
|
||||
rs_free(str);
|
||||
*str = a;
|
||||
// I cannot find such function in the API
|
||||
const char *s = string_cstr(b);
|
||||
const char *r = strstr(&s[index], pattern);
|
||||
return r == NULL ? SIZE_MAX : r - s;
|
||||
}
|
||||
|
||||
size_t bench_rapidstring(unsigned n)
|
||||
void pottery_replace_all_str(string_t *str, const char *s, const char *d)
|
||||
{
|
||||
rapidstring *tab = (rapidstring*) malloc (n * sizeof (rapidstring));
|
||||
size_t i = 0;
|
||||
while (true) {
|
||||
i = pottery_find_cstr(str, i, s);
|
||||
if (i==SIZE_MAX) return;
|
||||
string_remove(str, i, strlen(s));
|
||||
string_insert_cstr(str, i, d);
|
||||
}
|
||||
}
|
||||
|
||||
size_t bench_pottery(unsigned n)
|
||||
{
|
||||
string_t *tab = (string_t*) malloc (n * sizeof (string_t));
|
||||
assert (tab != 0);
|
||||
// P1
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
char tmp[10];
|
||||
sprintf(tmp, "%u", rand_get());
|
||||
rs_init_w(&tab[i], tmp);
|
||||
string_init(&tab[i]);
|
||||
string_append_format(&tab[i], "%u", rand_get());
|
||||
}
|
||||
// P2
|
||||
rapidstring str;
|
||||
rs_init(&str);
|
||||
string_t str;
|
||||
string_init(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
rs_cat_rs(&str, &tab[permutation_tab[i]]);
|
||||
string_append_string(&str, &tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char *p = strstr(&rs_data(&str)[pos], "1234");
|
||||
pos = p == NULL ? -1U : (p - rs_data(&str));
|
||||
if (pos != -1U) {
|
||||
RAPIDSTRING_replace_at(&str, pos, 4, "WELL");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
// P4
|
||||
pos = 0;
|
||||
do {
|
||||
char *p = strstr(&rs_data(&str)[pos], "56789");
|
||||
pos = p == NULL ? -1U : (p - rs_data(&str));
|
||||
if (pos != -1U) {
|
||||
RAPIDSTRING_replace_at(&str, pos, 5, "DONE");
|
||||
}
|
||||
} while (pos != -1U);
|
||||
size_t length = rs_len(&str);
|
||||
|
||||
pottery_replace_all_str(&str, "1234", "WELL");
|
||||
pottery_replace_all_str(&str, "56789", "DONE");
|
||||
size_t length = string_length(&str);
|
||||
|
||||
// Clean
|
||||
rs_free(&str);
|
||||
string_clear(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
rs_free(&tab[i]);
|
||||
string_clear(&tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
@@ -315,17 +301,17 @@ int main(int argc, const char *argv[])
|
||||
name = "SDS";
|
||||
break;
|
||||
#endif
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
case 3:
|
||||
length = bench_rapidstring(n);
|
||||
name = "RAPID";
|
||||
break;
|
||||
#endif
|
||||
#ifdef BENCH_CAN_USE_BSTRLIB
|
||||
case 4:
|
||||
length = bench_bstrlib(n);
|
||||
name = "BSTRLIB";
|
||||
break;
|
||||
#endif
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
case 5:
|
||||
length = bench_pottery(n);
|
||||
name = "POTTERY";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit(0);
|
||||
@@ -335,4 +321,3 @@ int main(int argc, const char *argv[])
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS, RAPIDSTRING & GLIB
|
||||
Copyright (c) 2018-2019 Patrick Pelissier
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS, GLIB & POTTERY
|
||||
Copyright (c) 2018-2023 Patrick Pelissier
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -48,11 +48,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define NDEBUG
|
||||
#define M_USE_SMALL_NAME 0
|
||||
#include "common.h"
|
||||
|
||||
#ifdef BENCH_CAN_USE_MSTARLIB
|
||||
@@ -79,15 +81,14 @@ extern "C" {
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#if defined (BENCH_CAN_USE_RAPIDSTRING)
|
||||
#include "rapidstring.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BENCH_CAN_USE_GLIB)
|
||||
#include "gmodule.h"
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
#include "pottery/string/string.h"
|
||||
#endif
|
||||
|
||||
/* Time of a test */
|
||||
#define TEST_SECONDS (5)
|
||||
|
||||
@@ -438,11 +439,11 @@ int testSRT_concat (int count) {
|
||||
int testMLIB_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init(b);
|
||||
m_string_t b;
|
||||
m_string_init(b);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
c += m_string_size(b) ^i;
|
||||
m_string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -450,11 +451,11 @@ int testMLIB_emptyCtor (int count) {
|
||||
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);
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
c += m_string_size(b) ^i;
|
||||
m_string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -462,93 +463,93 @@ int testMLIB_nonemptyCtor (int count) {
|
||||
int testMLIB_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_set_str(b, SMALLTESTSTRING1);
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(b, SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
string_clear(b);
|
||||
c += m_string_size(b) ^i;
|
||||
m_string_clear(b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init(b);
|
||||
m_string_t b;
|
||||
m_string_init(b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_set_str(b, TESTSTRING1);
|
||||
m_string_set_cstr(b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_size(b) ^i;
|
||||
c += m_string_size(b) ^i;
|
||||
}
|
||||
string_clear(b);
|
||||
m_string_clear(b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
string_t b;
|
||||
string_init_set_str(b, TESTSTRING1);
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(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;
|
||||
c += m_string_get_char(b, (i & 7));
|
||||
c += m_string_get_char(b, (i & 7) ^ 8);
|
||||
c += m_string_get_char(b, (i & 7) ^ 4) ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(b);
|
||||
m_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.");
|
||||
m_string_t b;
|
||||
m_string_init_set_cstr(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;
|
||||
c += m_string_search_char (b, '.');
|
||||
c += m_string_search_cstr (b, "123");
|
||||
c += m_string_search_pbrk (b, "sm") ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(b);
|
||||
m_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);
|
||||
m_string_t a, accum;
|
||||
m_string_init_set_cstr(a, TESTSTRING1);
|
||||
m_string_init (accum);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
string_set_str(accum, "");
|
||||
m_string_set_cstr(accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
string_cat(accum, a);
|
||||
string_cat_str(accum, "!!");
|
||||
m_string_cat(accum, a);
|
||||
m_string_cat_cstr(accum, "!!");
|
||||
BARRIER(&accum);
|
||||
c += string_size(accum) ^i;
|
||||
c += m_string_size(accum) ^i;
|
||||
}
|
||||
}
|
||||
string_clear(a);
|
||||
string_clear(accum);
|
||||
m_string_clear(a);
|
||||
m_string_clear(accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testMLIB_replace (int count) {
|
||||
int j, c = 0;
|
||||
string_t a;
|
||||
string_init_set_str(a, TESTSTRING1);
|
||||
m_string_t a;
|
||||
m_string_init_set_cstr(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");
|
||||
m_string_replace_at(a, 11, 4, "XXXXXX");
|
||||
m_string_replace_at(a, 23, 2, "XXXXXX");
|
||||
m_string_replace_at(a, 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += string_size(a) ^j;
|
||||
c += m_string_size(a) ^j;
|
||||
}
|
||||
|
||||
string_clear(a);
|
||||
m_string_clear(a);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
@@ -682,121 +683,6 @@ int testSDS_replace (int count) {
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
int testRAPIDSTRING_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
rapidstring b;
|
||||
rs_init(&b);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
rs_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
rapidstring b;
|
||||
rs_init_w(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
rs_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
rapidstring b;
|
||||
rs_init_w(&b, SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
rs_free(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
rapidstring b;
|
||||
rs_init(&b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
rs_cpy(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += rs_len(&b) ^i;
|
||||
}
|
||||
rs_free(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
rapidstring b;
|
||||
rs_init_w(&b, TESTSTRING1);
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += rs_data_c(&b)[i & 7];
|
||||
c += rs_data_c(&b)[(i & 7) ^ 8];
|
||||
c += rs_data_c(&b)[(i & 7) ^ 4] ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
rs_free(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
rapidstring a, accum;
|
||||
rs_init_w(&a, TESTSTRING1);
|
||||
rs_init (&accum);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
rs_cpy(&accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
rs_cat_rs(&accum, &a);
|
||||
rs_cat(&accum, "!!");
|
||||
BARRIER(&accum);
|
||||
c += rs_len(&accum) ^i;
|
||||
}
|
||||
}
|
||||
rs_free(&a);
|
||||
rs_free(&accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
void RAPIDSTRING_replace_at(rapidstring *str, size_t pos, size_t len, const char str2[])
|
||||
{
|
||||
// simple implementation as replace is not available
|
||||
rapidstring a;
|
||||
|
||||
rs_init_w_n(&a, rs_data(str), pos);
|
||||
rs_cat(&a, str2);
|
||||
rs_cat(&a, &rs_data(str)[pos+len] );
|
||||
rs_free(str);
|
||||
*str = a;
|
||||
}
|
||||
|
||||
int testRAPIDSTRING_replace (int count) {
|
||||
int j, c = 0;
|
||||
rapidstring a;
|
||||
rs_init_w(&a, TESTSTRING1);
|
||||
for (j=0; j < count; j++) {
|
||||
RAPIDSTRING_replace_at(&a, 11, 4, "XXXXXX");
|
||||
RAPIDSTRING_replace_at(&a, 23, 2, "XXXXXX");
|
||||
RAPIDSTRING_replace_at(&a, 4, 8, "XX");
|
||||
BARRIER(&a);
|
||||
c += rs_len(&a) ^j;
|
||||
}
|
||||
rs_free(&a);
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BENCH_CAN_USE_GLIB
|
||||
int testGLIB_emptyCtor (int count) {
|
||||
@@ -894,6 +780,118 @@ int testGLIB_concat (int count) {
|
||||
//int testGLIB_replace (int count): not available
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_POTTERY
|
||||
int testPOTTERY_emptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init(&b);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
string_clear(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_nonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_cstr(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
string_clear(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_smallnonemptyCtor (int count) {
|
||||
int i, c = 0;
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_t b;
|
||||
string_init_cstr(&b, SMALLTESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
string_clear(&b);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_cstrAssignment (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init(&b);
|
||||
for (c=i=0; i < count; i++) {
|
||||
string_set_cstr(&b, TESTSTRING1);
|
||||
BARRIER(&b);
|
||||
c += string_length(&b) ^i;
|
||||
}
|
||||
string_clear(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_extraction (int count) {
|
||||
int i, c = 0;
|
||||
|
||||
string_t b;
|
||||
string_init_cstr(&b, TESTSTRING1);
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_cstr(&b)[(i & 7)];
|
||||
c += string_cstr(&b)[(i & 7) ^ 8];
|
||||
c += string_cstr(&b)[(i & 7) ^ 4] ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
size_t pottery_find_cstr(string_t *b, const char *pattern)
|
||||
{
|
||||
// I cannot find such function in the API
|
||||
const char *s = string_cstr(b);
|
||||
const char *r = strstr(s, pattern);
|
||||
return r == NULL ? SIZE_MAX : r - s;
|
||||
}
|
||||
|
||||
int testPOTTERY_scan (int count) {
|
||||
int i, c = 0;
|
||||
string_t b;
|
||||
string_init_cstr(&b, "Dot. 123. Some more data.");
|
||||
|
||||
for (c=i=0; i < count; i++) {
|
||||
c += string_find_char (&b, 0, '.');
|
||||
c += pottery_find_cstr (&b, "123");
|
||||
c += string_find_chars_cstr (&b, 0, "sm") ^i;
|
||||
BARRIER(&b);
|
||||
}
|
||||
string_clear(&b);
|
||||
return c;
|
||||
}
|
||||
|
||||
int testPOTTERY_concat (int count) {
|
||||
int i, j, c = 0;
|
||||
string_t a, accum;
|
||||
string_init_cstr(&a, TESTSTRING1);
|
||||
string_init (&accum);
|
||||
|
||||
for (j=0; j < count; j++) {
|
||||
string_set_cstr(&accum, "");
|
||||
for (i=0; i < 250; i++) {
|
||||
string_append_string(&accum, &a);
|
||||
string_append_cstr(&accum, "!!");
|
||||
BARRIER(&accum);
|
||||
c += string_length(&accum) ^i;
|
||||
}
|
||||
}
|
||||
string_clear(&a);
|
||||
string_clear(&accum);
|
||||
return c;
|
||||
}
|
||||
|
||||
// No replace function available
|
||||
#endif
|
||||
|
||||
|
||||
#define NTESTS 8
|
||||
struct flags {
|
||||
@@ -1088,37 +1086,6 @@ int benchTest (const struct flags * runflags) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_RAPIDSTRING
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_emptyCtor, 100000);
|
||||
print ("RAPIDSTRING", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_nonemptyCtor, 100000);
|
||||
print ("RAPIDSTRING", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_smallnonemptyCtor, 100000);
|
||||
print ("RAPIDSTRING", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_cstrAssignment, 100000);
|
||||
print ("RAPIDSTRING", "char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_extraction, 100000);
|
||||
print ("RAPIDSTRING", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_concat, 10);
|
||||
print ("RAPIDSTRING", "concatenation", cps * 250);
|
||||
}
|
||||
if (runflags->runtest[7]) {
|
||||
c += timeTest (cps, testRAPIDSTRING_replace, 10);
|
||||
print ("RAPIDSTRING", "replace", cps);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_GLIB
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testGLIB_emptyCtor, 100000);
|
||||
@@ -1150,6 +1117,37 @@ int benchTest (const struct flags * runflags) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BENCH_CAN_USE_POTTERY
|
||||
if (runflags->runtest[0]) {
|
||||
c += timeTest (cps, testPOTTERY_emptyCtor, 100000);
|
||||
print ("POTTERY", "empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[1]) {
|
||||
c += timeTest (cps, testPOTTERY_nonemptyCtor, 100000);
|
||||
print ("POTTERY", "non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[2]) {
|
||||
c += timeTest (cps, testPOTTERY_smallnonemptyCtor, 100000);
|
||||
print ("POTTERY", "small non-empty constructor", cps);
|
||||
}
|
||||
if (runflags->runtest[3]) {
|
||||
c += timeTest (cps, testPOTTERY_cstrAssignment, 100000);
|
||||
print ("POTTERY", "Char * assignment", cps);
|
||||
}
|
||||
if (runflags->runtest[4]) {
|
||||
c += timeTest (cps, testPOTTERY_extraction, 100000);
|
||||
print ("POTTERY", "char extraction", cps);
|
||||
}
|
||||
if (runflags->runtest[5]) {
|
||||
c += timeTest (cps, testPOTTERY_scan, 100000);
|
||||
print ("POTTERY", "scan", cps);
|
||||
}
|
||||
if (runflags->runtest[6]) {
|
||||
c += timeTest (cps, testPOTTERY_concat, 10);
|
||||
print ("POTTERY", "concatenation", cps * 250);
|
||||
}
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define NDEBUG
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -202,9 +203,8 @@ static void test_sort(size_t n)
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0}
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 50, "sort", 10000000, 0, test_sort, 0}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* 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:
|
||||
@@ -26,6 +26,9 @@
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
|
||||
// Maximum supported value for repeat argument
|
||||
#define MAX_REPEAT 10000
|
||||
|
||||
// The global result
|
||||
unsigned long g_result;
|
||||
|
||||
@@ -46,8 +49,9 @@ void compiler_barrier(void *p)
|
||||
struct parse_opt_s {
|
||||
int test_function;
|
||||
double from, to, step, grow;
|
||||
double within;
|
||||
unsigned repeat;
|
||||
bool graph, best, average, quiet;
|
||||
bool graph, best, best_within, average, quiet;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -62,9 +66,11 @@ parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
|
||||
opt->grow = 1.1;
|
||||
opt->graph = false;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
opt->average = false;
|
||||
opt->quiet = false;
|
||||
opt->repeat = 1;
|
||||
opt->within = .05;
|
||||
|
||||
for(int i = 1; i < argc ; i++)
|
||||
{
|
||||
@@ -88,14 +94,23 @@ parse_config(struct parse_opt_s *opt, int argc, const char *argv[])
|
||||
} else if (strcmp(argv[i], "--repeat") == 0) {
|
||||
i++;
|
||||
opt->repeat = strtol(argv[i], &end, 10);
|
||||
opt->repeat = (opt->repeat > MAX_REPEAT) ? MAX_REPEAT : opt->repeat;
|
||||
} else if (strcmp(argv[i], "--graph") == 0) {
|
||||
opt->graph = true;
|
||||
} else if (strcmp(argv[i], "--best") == 0) {
|
||||
opt->best = true;
|
||||
opt->average = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--best-within") == 0) {
|
||||
opt->best_within = true;
|
||||
opt->best = false;
|
||||
opt->average = false;
|
||||
i++;
|
||||
opt->within = strtod(argv[i], &end) / 100.0;
|
||||
} else if (strcmp(argv[i], "--average") == 0) {
|
||||
opt->average = true;
|
||||
opt->best = false;
|
||||
opt->best_within = false;
|
||||
} else if (strcmp(argv[i], "--quiet") == 0) {
|
||||
opt->quiet = true;
|
||||
} else {
|
||||
@@ -131,14 +146,78 @@ select_config(int func, size_t n, const config_func_t functions[])
|
||||
for(size_t i = 0; i < n;i++) {
|
||||
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
|
||||
}
|
||||
fprintf(stderr, "USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--best|--average] [--quiet|--graph]\n");
|
||||
fprintf(stderr,
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--graph]\n"
|
||||
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Utility function for qsort
|
||||
static int cmp_double(const void *pa, const void *pb)
|
||||
{
|
||||
const double *a = (const double *) pa, *b = (const double *)pb;
|
||||
return (*a < *b) ? -1 : *a > *b;
|
||||
}
|
||||
|
||||
/* Get the longest sequence of values within 'f'% */
|
||||
static int
|
||||
get_sequence(int i, int n, double tab[], double f)
|
||||
{
|
||||
int j;
|
||||
for(j = i + 1; j < n; j++) {
|
||||
if (tab[j] > f * tab[i])
|
||||
break;
|
||||
}
|
||||
return j-i;
|
||||
}
|
||||
|
||||
/* Return the minimum of the longest sequence of values with 'f'% */
|
||||
static double
|
||||
get_best_within(int n, double tab[], double f)
|
||||
{
|
||||
qsort(tab, n, sizeof(double), cmp_double);
|
||||
int best_i = 0;
|
||||
int best_seq = get_sequence(0, n, tab, f);
|
||||
for(int i = 1; i < n && (n-i) > best_seq ; i++) {
|
||||
int seq = get_sequence(i, n, tab, f);
|
||||
if (seq > best_seq) {
|
||||
best_i = i;
|
||||
best_seq = seq;
|
||||
}
|
||||
}
|
||||
return tab[best_i];
|
||||
}
|
||||
|
||||
// Integer sqrt function (to avoid depending on libm)
|
||||
static unsigned integer_sqrt(unsigned n)
|
||||
{
|
||||
// Find greatest shift.
|
||||
int shift = 2;
|
||||
unsigned nShifted = n >> shift;
|
||||
// We check for nShifted being n, since some implementations
|
||||
// perform shift operations modulo the word size.
|
||||
while (nShifted != 0 && nShifted != n){
|
||||
shift += 2;
|
||||
nShifted = n >> shift;
|
||||
}
|
||||
shift -= 2;
|
||||
// Find digits of result.
|
||||
unsigned result = 0;
|
||||
while (shift >= 0) {
|
||||
result = result << 1;
|
||||
unsigned candidateResult = result + 1;
|
||||
if (candidateResult*candidateResult <= n >> shift) {
|
||||
result = candidateResult;
|
||||
}
|
||||
shift -= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
test(const char library[], size_t n, const config_func_t functions[], int argc, const char *argv[])
|
||||
{
|
||||
// options
|
||||
// Init & parse arguments
|
||||
// NUMBER
|
||||
// --from NUMBER --to NUMBER --step NUMBER --grow NUMBER
|
||||
// --graph --best --average --quiet
|
||||
@@ -146,45 +225,76 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
|
||||
struct parse_opt_s arg;
|
||||
parse_config(&arg, argc, argv);
|
||||
int i = select_config(arg.test_function, n, functions);
|
||||
double from = arg.from == 0 ? functions[i].default_n : arg.from;
|
||||
double to = arg.from == 0 ? functions[i].default_n : arg.to;
|
||||
double from = (arg.from == 0) ? functions[i].default_n : arg.from;
|
||||
double to = (arg.to == 0) ? functions[i].default_n : arg.to;
|
||||
|
||||
// Open plot file if needed
|
||||
FILE *graph_file = NULL;
|
||||
if (arg.graph) {
|
||||
char filename[100];
|
||||
sprintf(filename, "plot-%s-%d.dat", library, arg.test_function);
|
||||
graph_file = fopen(filename, "wt");
|
||||
if (!graph_file) {
|
||||
fprintf(stderr, "ERROR: Cannot create plot.dat\n");
|
||||
fprintf(stderr, "ERROR: Cannot create the file '%s'\n", filename);
|
||||
exit(-2);
|
||||
}
|
||||
fprintf(graph_file, "# plotting %s-%d : %s\n# N T", library, arg.test_function, functions[i].funcname);
|
||||
}
|
||||
|
||||
// Do the bench
|
||||
for(double n = from; n <= to ; n = (arg.grow == 0 ? n + arg.step : n * arg.grow))
|
||||
for(double n = from; n <= to ; n = ((arg.grow == 0) ? n + arg.step : n * arg.grow))
|
||||
{
|
||||
double best = (1.0/0.0);
|
||||
double avg = 0.0;
|
||||
double variance = 0.0;
|
||||
static double measure[MAX_REPEAT];
|
||||
double ba = 0.0;
|
||||
|
||||
if (functions[i].init != NULL)
|
||||
functions[i].init(n);
|
||||
|
||||
// Measure the time of the test_function
|
||||
for(unsigned r = 0; r < arg.repeat; r++) {
|
||||
double t0 = test_function(arg.graph|arg.best|arg.average|arg.quiet ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
|
||||
best = t0 < best ? t0 : best;
|
||||
double t0 = test_function( (arg.graph|arg.best|arg.average|arg.quiet) ? NULL : functions[i].funcname, (size_t) n, functions[i].func);
|
||||
best = (t0 < best) ? t0 : best;
|
||||
avg += t0;
|
||||
variance += t0 * t0;
|
||||
measure[r] = t0;
|
||||
}
|
||||
|
||||
// Closure of the tests
|
||||
if (functions[i].clear != NULL)
|
||||
functions[i].clear();
|
||||
avg /= arg.repeat;
|
||||
|
||||
// Finish computing the different times
|
||||
if (arg.repeat > 1) {
|
||||
avg /= arg.repeat;
|
||||
variance = (variance - arg.repeat * avg * avg) / (arg.repeat - 1);
|
||||
ba = get_best_within(arg.repeat, measure, 1. + arg.within);
|
||||
} else {
|
||||
ba = avg;
|
||||
}
|
||||
|
||||
// The average value shall be around best_within (and greater)
|
||||
// otherwise the result doesn't seem reliable.
|
||||
bool reliable = (ba <= avg && ba * (1.0+arg.within/2) + 0.5 > avg);
|
||||
|
||||
// Print the result
|
||||
if (arg.graph) {
|
||||
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : best);
|
||||
fprintf(graph_file, "%f %f\n", n, arg.average ? avg : arg.best ? best : ba);
|
||||
} else if (arg.quiet) {
|
||||
printf("%lu\n", (unsigned long)(arg.average ? avg : best));
|
||||
printf("%ld\n", (long)(arg.average ? avg : arg.best ? best : reliable ? ba : -1));
|
||||
} else if (arg.repeat > 1) {
|
||||
if (arg.average == false)
|
||||
if (arg.average == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST ***\n", functions[i].funcname, (unsigned long) best, (unsigned long) n);
|
||||
if (arg.best == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, (unsigned long) n);
|
||||
if (arg.best == false && arg.best_within == false)
|
||||
printf ("%20.20s time %lu ms +/- %u ms for n = %lu *** AVERAGE ***\n", functions[i].funcname, (unsigned long) avg, 2*integer_sqrt(variance), (unsigned long) n);
|
||||
if (arg.best == false && arg.average == false)
|
||||
printf ("%20.20s time %lu ms for n = %lu *** BEST within %d%% *** %s\n", functions[i].funcname, (unsigned long) ba, (unsigned long) n, (int)(100*arg.within), reliable ? "" : "(unreliable result)");
|
||||
}
|
||||
}
|
||||
|
||||
// Close the FILE if needed
|
||||
if (arg.graph) {
|
||||
fclose(graph_file);
|
||||
printf("File plot-%s-%d.dat generated.\n"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* 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:
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
// Needed for M_THREAD_ATTR
|
||||
#if defined(MULTI_THREAD_MEASURE)
|
||||
#include "m-mutex.h"
|
||||
#include "m-thread.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -55,7 +55,7 @@
|
||||
// Number of elements of a table
|
||||
#define numberof(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
/* Get the current CPU time. */
|
||||
/* Get the current CPU time in microsecond. */
|
||||
#if defined(_WIN32)
|
||||
/* WINDOWS variant */
|
||||
static inline unsigned long long
|
||||
@@ -119,9 +119,8 @@ test_function(const char *str, size_t n, void (*func)(size_t))
|
||||
(*func)(n);
|
||||
end = cputime();
|
||||
result = (double)(end-start) / 1000.0;
|
||||
end = (end - start) / 1000U;
|
||||
if (str != NULL) {
|
||||
printf ("%20.20s time %lu ms for n = %lu [r=%lu]\n", str, (unsigned long) end, (unsigned long) n, g_result);
|
||||
printf ("%20.20s time %.2f ms for n = %lu [r=%lu]\n", str, result, (unsigned long) n, g_result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* 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:
|
||||
|
||||
@@ -35,10 +35,9 @@ static inline size_t my_hash(uint64_t key)
|
||||
{
|
||||
return ((key) ^ (key)>>7);
|
||||
}
|
||||
static inline void update_val(uint32_t *p, uint32_t v) { *p += v;}
|
||||
DICT_OA_DEF2(dict_oligonucleotide,
|
||||
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)),
|
||||
uint32_t, M_OPEXTEND(M_DEFAULT_OPLIST, UPDATE(update_val M_IPTR)))
|
||||
uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_oligonucleotide_t() DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)), M_DEFAULT_OPLIST)
|
||||
|
||||
// Define a B*TREE-21 of uint32_t --> uint64_t and register its oplist
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#undef NDEBUG
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
@@ -48,7 +43,7 @@ int test_int(int N, const unsigned *data)
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_remove(h, data[i]);
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
@@ -64,7 +59,7 @@ int test_str(int N, char * const *data)
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_remove(h, data[i]);
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-mempool.h"
|
||||
|
||||
DICT_DEF2(dict_int,
|
||||
DICT_STOREHASH_DEF2(dict_int,
|
||||
int, M_OPEXTEND(M_DEFAULT_OPLIST, MEMPOOL(mpool_int), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(dict_str,
|
||||
DICT_STOREHASH_DEF2(dict_str,
|
||||
const char *, M_OPEXTEND (M_CSTR_OPLIST, MEMPOOL(mpool_str), MEMPOOL_LINKAGE(static)),
|
||||
int, M_DEFAULT_OPLIST)
|
||||
|
||||
@@ -20,7 +20,7 @@ int test_int(int N, const unsigned *data)
|
||||
if (dict_int_get (h, data[i]) == NULL) {
|
||||
dict_int_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_int_remove(h, data[i]);
|
||||
dict_int_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_int_size(h);
|
||||
@@ -38,7 +38,7 @@ int test_str(int N, char * const *data)
|
||||
if (dict_str_get (h, data[i]) == NULL) {
|
||||
dict_str_set_at (h, data[i], i);
|
||||
} else {
|
||||
dict_str_remove(h, data[i]);
|
||||
dict_str_erase(h, data[i]);
|
||||
}
|
||||
}
|
||||
ret = (int)dict_str_size(h);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "../common.c"
|
||||
#define M_USE_DICT_OA_PROBING(s) 1
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(unsigned int k, unsigned char n)
|
||||
@@ -11,10 +12,10 @@ static inline void oor_set(unsigned int *k, unsigned char n)
|
||||
}
|
||||
|
||||
DICT_OA_DEF2(dict_oa_uint,
|
||||
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
unsigned int, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(hash_fn), OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)),
|
||||
unsigned int, M_DEFAULT_OPLIST)
|
||||
|
||||
void test_int(uint32_t n, uint32_t x0)
|
||||
uint32_t test_int(uint32_t n, uint32_t x0)
|
||||
{
|
||||
uint32_t i, x, z = 0;
|
||||
dict_oa_uint_t h;
|
||||
@@ -22,10 +23,12 @@ void test_int(uint32_t n, uint32_t x0)
|
||||
for (i = 0, x = x0; i < n; ++i) {
|
||||
x = hash32(x);
|
||||
unsigned int key = get_key(n, x);
|
||||
unsigned int *ptr = dict_oa_uint_get(h, key);
|
||||
if (ptr) { (*ptr)++; z+= *ptr; }
|
||||
else { dict_oa_uint_set_at(h, key, 1); z+=1; }
|
||||
unsigned int *ptr = dict_oa_uint_get_at(h, key);
|
||||
(*ptr)++;
|
||||
z += *ptr;
|
||||
}
|
||||
fprintf(stderr, "# unique keys: %d; checksum: %u\n", (int) dict_oa_uint_size(h), z);
|
||||
z = dict_oa_uint_size(h);
|
||||
dict_oa_uint_clear(h);
|
||||
return z;
|
||||
}
|
||||
@@ -38,4 +38,47 @@ V0.2.*: * worker_start takes a 'worker_t' as an additional parameter
|
||||
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.*: * Rename m-mutex.h header in m-thread.h
|
||||
@@ -17,17 +17,35 @@ How to make a release?
|
||||
In case of problem, open a problem report.
|
||||
|
||||
|
||||
List of tested systems
|
||||
=======================
|
||||
List of automatically tested systems
|
||||
====================================
|
||||
|
||||
* gcc 4.9, 7 & 8 on linux/x86-64
|
||||
* clang 3.5, 4 & 6 on linux/x86-64
|
||||
* g++ 7 & 8 on linux/x86-64
|
||||
* 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 7 on windows/x86-64
|
||||
* gcc 4.9 on linux/powerpc
|
||||
* gcc 6 on linux/armv7l
|
||||
* clang 3.8 on linux/armv7l
|
||||
* 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
|
||||
@@ -35,7 +53,7 @@ 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 test with a cross-compiler, do like the following
|
||||
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:
|
||||
|
||||
@@ -47,9 +65,8 @@ 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 closed and taken into account in less than (typically) one month,
|
||||
or before a release,
|
||||
it shall be moved into the long term issues included in the repository:
|
||||
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.
|
||||
|
||||
@@ -65,7 +82,7 @@ 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
|
||||
@@ -76,7 +93,7 @@ Different strategy for debugging the library itself are still possible:
|
||||
Add printf of interresting values in the debugged function.
|
||||
|
||||
|
||||
2) Preprocess the library and then compile the preprocessed file:
|
||||
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
|
||||
@@ -99,3 +116,41 @@ 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
|
||||
@@ -1,54 +1,364 @@
|
||||
|
||||
*Long term issues*
|
||||
------------------
|
||||
==========================================================
|
||||
|
||||
* 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.
|
||||
|
||||
** Actions
|
||||
|
||||
Add such support in M*LIB containers.
|
||||
|
||||
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.
|
||||
|
||||
* TODO #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?
|
||||
- How to initialize the specialization field of the container? provide custom initialization functions? It seems to be the hard point.
|
||||
|
||||
* TODO #31 : Uniformize parametrisation 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.
|
||||
|
||||
** Evolution
|
||||
|
||||
Old format should be deprecated and shall use the generic serialization interface.
|
||||
|
||||
Serialization object shall provide an OPLIST of serialization.
|
||||
For example CORE will provide OLD Format oplist and 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.
|
||||
|
||||
Open point:
|
||||
|
||||
- how can a user add a new serialization object?
|
||||
- Can we make a generic serialization object to support migration path?
|
||||
|
||||
** 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:
|
||||
|
||||
Enable support for generating an interface only for the headers
|
||||
and an implementation only for the source code.
|
||||
|
||||
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.
|
||||
|
||||
* TODO #26 : Hash-Map for huge objects :ENHANCEMENT:
|
||||
|
||||
Specialize Hashmap for huge objects on supported hardware:
|
||||
|
||||
|
||||
based on OA hash map of taggued pointer (needs space for tagging)
|
||||
low bits = low bits of hash
|
||||
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 detect collision without dereferencing object with 1/2^lowbits chances.
|
||||
Reduce cache usage ==> Shall be faster.
|
||||
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)
|
||||
|
||||
* TODO #25 : Support of error code model for error handling. :ENHANCEMENT:
|
||||
<---- PTR ----><-HASH->
|
||||
|
||||
#+BEGIN_SRC C
|
||||
#define LOW_BITS 16
|
||||
#define ALIGNED_BITS 2
|
||||
void *get_ptr(int64_t x) {
|
||||
return (void*) ((x >> LOW_BITS) << ALIGNED_BITS);
|
||||
}
|
||||
unsigned get_small_hash(int64_t x) {
|
||||
return x & ((1<<LOW_BITS)-1);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
* TODO #25 : Support of error return model for error handling. :ENHANCEMENT:
|
||||
|
||||
Find a way to support error return code for the API in case of allocation
|
||||
failure.
|
||||
|
||||
==> Any service that returns void shall return a "int".
|
||||
==> In case of allocation failure, it shall return an error.
|
||||
==> M_CALL macro shall stop its execution if the service returns an error code
|
||||
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.
|
||||
Services returning already something shall not be modified.
|
||||
|
||||
This model should be applied at the container level only and not globally.
|
||||
Different containers may need different levels of error handling.
|
||||
4 combinaison to take into account:
|
||||
|
||||
New operator: ERROR_MODEL which value is 0 (abort on error), 1 (throw on error)
|
||||
or 2 (return code on error).
|
||||
==> 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:
|
||||
|
||||
* TODO #24 : Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
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:
|
||||
|
||||
See https://en.wikipedia.org/wiki/Min-max_heap
|
||||
as DPRIORITY_QUEUE_DEF ?
|
||||
|
||||
NOTE: Needs for such container?
|
||||
|
||||
* TODO #23 : Strict MOVE semantic to clarify :ENHANCEMENT:
|
||||
|
||||
* TODO #23: Force MOVE semantic :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
|
||||
@@ -63,7 +373,7 @@ moving the data before they can be moved using MOVE. Two solutions:
|
||||
- New operator MOVE_SELF to fix a type after it has been moved.
|
||||
- If MOVE defined, force another table and then copy by hand the type. This will be slower and consumme more memory.
|
||||
|
||||
** MOVE in OPLIST :ENHANCEMENT:
|
||||
** 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
|
||||
@@ -82,8 +392,22 @@ defined with [1] tricks but without an explicit INIT_MOVE / MOVE
|
||||
operators as it uses MOVE_DEFAULT which is not (fully compatible).
|
||||
==> Analyse limitation and possible constraint usages.
|
||||
|
||||
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.
|
||||
|
||||
* TODO #20: Bucket priority queue :ENHANCEMENT:
|
||||
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.
|
||||
|
||||
Without a way to write such a macro, the ticket seems pretty much a dead end.
|
||||
|
||||
* TODO #20 : New: Bucket priority queue :ENHANCEMENT:
|
||||
|
||||
Add a new kind of priority queue.
|
||||
See https://en.wikipedia.org/wiki/Bucket_queue
|
||||
@@ -99,23 +423,20 @@ except that we can scan 64 entries at a time).
|
||||
Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
|
||||
implementation.
|
||||
|
||||
|
||||
* TODO #19: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
* TODO #19 : New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
|
||||
Add intrusive red black tree.
|
||||
Look also for AVL tree (NOTE: Is there a performance difference between the two?)
|
||||
|
||||
|
||||
* TODO #18: Missing methods :ENHANCEMENT:
|
||||
* TODO #18 : Missing methods :ENHANCEMENT:
|
||||
|
||||
Some containers don't have all the methods they should.
|
||||
See the cells in yellow here:
|
||||
http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html
|
||||
|
||||
* TODO #17 : New: Ressource handler :ENHANCEMENT:
|
||||
|
||||
* TODO #17: Ressource handler :ENHANCEMENT:
|
||||
|
||||
A ressouce handler which shall associated a unique handle to a ressource.
|
||||
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
|
||||
@@ -140,11 +461,10 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
|
||||
|
||||
How to handle multiple resource ?
|
||||
|
||||
* variant: works fine. Memory usage can be (much) higher than needed if there is a lot of dissimilarity between the size of the objects.
|
||||
* embedded the type in the ressource handler: more work, API more complex. Memory usage seems better.
|
||||
* 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: Lock Free List :ENHANCEMENT:
|
||||
* 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.
|
||||
@@ -167,30 +487,7 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
|
||||
- needs to be logically deleted : needs a previous field
|
||||
(NULL if not logically deleted) ? TBC
|
||||
|
||||
|
||||
* TODO #15: Prologue / Epilogue for Constructor / Destructor for error handling :ENHANCEMENT:
|
||||
|
||||
Constructor (and destructor) need to use user-defined prologue / epilogue.
|
||||
This is in order to register the constructed object into a proper Exception
|
||||
Handling Stack so that throwing exceptions may work reliably.
|
||||
|
||||
Proposal:
|
||||
|
||||
- M_CONSTRUCTOR_PROLOGUE(object, oplist);
|
||||
- M_CONSTRUCTOR_EPILOGUE(object, oplist);
|
||||
- M_DESTRUCTOR_PROLOGUE(object, oplist);
|
||||
- M_DESTRUCTOR_EPILOGUE(object, oplist);
|
||||
|
||||
Object creation will need to add all sub-objects into the stack,
|
||||
then unstack all to push instead the root object (which recursively remove them).
|
||||
|
||||
See also http://freetype.sourceforge.net/david/reliable-c.html#cseh
|
||||
|
||||
How to handle like allocation of the object?
|
||||
How to avoid calling the destructor multiple times? (It is needed?)
|
||||
|
||||
|
||||
* TODO #14: Memory allocation enhancement :ENHANCEMENT:
|
||||
* DONE #14 : Memory allocation enhancement :ENHANCEMENT:
|
||||
|
||||
Enhancement of the memory allocation scheme to find way to deal properly with advanced allocators:
|
||||
|
||||
@@ -224,8 +521,9 @@ Needs some formal operator in the oplist to support it fully and an example.
|
||||
|
||||
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: Atomic shared pointer :ENHANCEMENT:
|
||||
* TODO #12 : New: Atomic shared pointer :ENHANCEMENT:
|
||||
|
||||
Add an extension to the SHARED_PTR API:
|
||||
|
||||
@@ -299,13 +597,14 @@ Other alternative solution is to use the bit 0 to mark the pointer as being upda
|
||||
|
||||
Other implementation seems to have it hard to be lock-free: cf. https://github.com/llvm-mirror/libcxx/commit/5fec82dc0db3623546038e4a86baa44f749e554f
|
||||
|
||||
|
||||
|
||||
* TODO #5: Concurrent dictionary Container :ENHANCEMENT:
|
||||
* TODO #5 : New: Concurrent dictionary Container :ENHANCEMENT:
|
||||
|
||||
Implement a more efficient dictionary than lock + std dictionary for all operations when dealing with threads.
|
||||
See https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
|
||||
|
||||
The best parallel algorithm is still when there is as few synchronization as possible. A concurrent dictionary will fail at this and will result in average performance at best.
|
||||
The typical best case will be in RCU context (a lot of readers, few writers), so the interface shall be compatible with such structure.
|
||||
|
||||
** Multiple locks within the dictionnary
|
||||
|
||||
A potential implementation may be to request at initialization time the number of concurrent thread N.
|
||||
@@ -326,33 +625,24 @@ 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 (see 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). See also 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 persents different techniques used by linux kernel.
|
||||
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
|
||||
|
||||
** Context
|
||||
|
||||
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.
|
||||
|
||||
** Linked list
|
||||
|
||||
Another solution is to create a huge list of items which is:
|
||||
|
||||
- atomically updated,
|
||||
- in reverse order of the hash (bit 0 is highest bit, Bit 63 is the lowest bit).
|
||||
|
||||
Hash table will only give quick access to items to this list. Expanding the table won't change the order of the list (so the items will remain at the same place and always accessible by other threads) but just add sentinel in the sentinel at the right place (there won't be any reallocation of the list). Inserting will need to insert an item at the right place.
|
||||
Not sure it will really help. To analyse.
|
||||
|
||||
Concurrent dictionary is possible now with CONCURRENT_DEF + DICT_DEF.
|
||||
But it uses a global lock for all dictionary access.
|
||||
|
||||
** Open Addressing Indirect Table with a lock free node pool used as transaction pool.
|
||||
|
||||
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:
|
||||
@@ -390,6 +680,27 @@ push always succeed and the queue always keep the youngest element.
|
||||
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,16 @@
|
||||
#!/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" ;;
|
||||
*\.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}
|
||||
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 113 KiB |
@@ -1,6 +1,29 @@
|
||||
# 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
|
||||
RM=rm -f
|
||||
@@ -8,17 +31,33 @@ RM=rm -f
|
||||
.SUFFIXES: .c .exe
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` $(LDFLAGS)
|
||||
|
||||
.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) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp config-test.c -o config-test.exe 2> /dev/null && echo "-DHAVE_GMP=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0" > config
|
||||
$(RM) config-test.*
|
||||
$(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 <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 config
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config config.link
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -24,7 +24,8 @@
|
||||
/* Generate prototypes and inline functions
|
||||
for basic types.
|
||||
For integer and floats, there is no need to specify
|
||||
an oplist. M_DEFAULT_OPLIST will be used.
|
||||
an oplist. M_BASIC_OPLIST will be used.
|
||||
For bool, M_BOOL_OPLIST will be used.
|
||||
*/
|
||||
ARRAY_DEF(r_bool, bool)
|
||||
|
||||
@@ -105,7 +106,7 @@ test_int(int n)
|
||||
But with an explicit oplist.
|
||||
This generates exactly the same code than r_int
|
||||
*/
|
||||
ARRAY_DEF(r_int2, signed int, M_DEFAULT_OPLIST)
|
||||
ARRAY_DEF(r_int2, signed int, M_BASIC_OPLIST)
|
||||
|
||||
static int
|
||||
test_int2(int n)
|
||||
@@ -180,7 +181,7 @@ test_float(int n)
|
||||
|
||||
|
||||
/* Same with type double and an explicit oplist*/
|
||||
ARRAY_DEF(r_double, double, M_DEFAULT_OPLIST)
|
||||
ARRAY_DEF(r_double, double, M_BASIC_OPLIST)
|
||||
|
||||
static int
|
||||
test_double(int n)
|
||||
@@ -214,9 +215,9 @@ static char *my_strdup(const char *p)
|
||||
return d;
|
||||
}
|
||||
|
||||
/* Same with type const char *, representing a contant string.
|
||||
/* 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 string.
|
||||
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
|
||||
@@ -231,7 +232,7 @@ test_cstring(int n)
|
||||
|
||||
r_cstring_init(array);
|
||||
for(int i = 0; i < n; i++) {
|
||||
char buffer[10];
|
||||
char buffer[16];
|
||||
// Create a string from the integer
|
||||
sprintf(buffer, "%d", i);
|
||||
// We need to make an explicit copy of the string
|
||||
@@ -245,13 +246,13 @@ test_cstring(int n)
|
||||
for(int i = 0; i < n; i++) {
|
||||
// Get back the string
|
||||
const char *p = *r_cstring_get(array, i);
|
||||
// Convert it to integer
|
||||
// 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.
|
||||
// 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);
|
||||
@@ -264,7 +265,7 @@ test_cstring(int n)
|
||||
|
||||
|
||||
|
||||
/* Same with type string_t of M*LIB, representing a variable string.
|
||||
/* 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
|
||||
@@ -282,7 +283,7 @@ test_string(int n)
|
||||
|
||||
for(int i = 0; i < n; i++) {
|
||||
// create a string from an integer
|
||||
string_printf(str, "%d", i);
|
||||
string_set_si(str, i);
|
||||
// No need to make a copy in the container!
|
||||
r_string_push_back(array, str);
|
||||
}
|
||||
@@ -294,7 +295,7 @@ test_string(int n)
|
||||
s += j;
|
||||
}
|
||||
|
||||
// No need to explicit dealloc !
|
||||
// No need to explicit free each term of the array
|
||||
string_clear(str);
|
||||
r_string_clear(array);
|
||||
|
||||
@@ -304,7 +305,7 @@ test_string(int n)
|
||||
|
||||
|
||||
/* Same with type string_t of M*LIB, representing a variable string
|
||||
and its explicit oplist. And said above, it generates exactly the
|
||||
and its explicit oplist. As said above, it generates exactly the
|
||||
same code. */
|
||||
ARRAY_DEF(r_string2, string_t, STRING_OPLIST)
|
||||
|
||||
@@ -340,6 +341,9 @@ test_vintptr(int n)
|
||||
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;
|
||||
}
|
||||
@@ -374,6 +378,7 @@ test_rockme(int n)
|
||||
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);
|
||||
}
|
||||
@@ -414,6 +419,7 @@ test_rockme2(int n)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -458,6 +464,7 @@ test_rockme2b(int n)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -478,15 +485,18 @@ test_rockme2b(int n)
|
||||
/* Same with a structure type defined as a tuple.
|
||||
|
||||
We first define a tuple. No need to specify the oplist as it uses basic C types
|
||||
so M_DEFAULT_OPLIST is used.
|
||||
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_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
ARRAY_DEF(r_rockme3, rock_you_t, TUPLE_OPLIST(rock_you, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
|
||||
static int
|
||||
test_rockme3(int n)
|
||||
@@ -520,7 +530,7 @@ test_rockme3(int n)
|
||||
/* Same with a structure type defined as a tuple using global registeration.
|
||||
|
||||
We first define a tuple. No need to specify the oplist as it uses basic C types
|
||||
so M_DEFAULT_OPLIST is used.
|
||||
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.
|
||||
@@ -533,7 +543,7 @@ test_rockme3(int n)
|
||||
*/
|
||||
TUPLE_DEF2(rock_us, (n, int), (other, float))
|
||||
|
||||
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_rock_us_t() TUPLE_OPLIST(rock_us, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
ARRAY_DEF(r_rockme4, rock_us_t)
|
||||
|
||||
@@ -612,7 +622,7 @@ int main (int argc, const char *argv[])
|
||||
s = test_rockme3(n);
|
||||
printf ("S[rockme3] = %d\n", s);
|
||||
|
||||
s = test_rockme3(n);
|
||||
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);
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
/* This example show how to use complex structure with array
|
||||
embedding another library */
|
||||
|
||||
/* This is a trivial library */
|
||||
/* This is a typical trivial library with its interface */
|
||||
typedef struct lib_ext_struct {
|
||||
int id;
|
||||
// Other data
|
||||
// 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));
|
||||
@@ -18,6 +20,7 @@ static lib_ext_struct *lib_ext_struct_Duplicate(const lib_ext_struct *obj)
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Method to delete any object */
|
||||
static void lib_ext_struct_Delete(lib_ext_struct *obj)
|
||||
{
|
||||
free(obj);
|
||||
@@ -30,6 +33,11 @@ typedef struct {
|
||||
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;
|
||||
@@ -37,6 +45,12 @@ static void data_node_init(data_node *obj)
|
||||
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;
|
||||
@@ -47,6 +61,13 @@ static void data_node_init_set(data_node *obj, const data_node *src)
|
||||
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;
|
||||
@@ -59,6 +80,11 @@ static void data_node_set(data_node *obj, const data_node *src)
|
||||
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);
|
||||
@@ -66,13 +92,26 @@ static void data_node_clear(data_node *obj)
|
||||
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))))
|
||||
|
||||
ARRAY_DEF(array_data_node, data_node, (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));
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,33 @@
|
||||
#include "m-bptree.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a map int -> string
|
||||
// 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)
|
||||
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
// 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
|
||||
// 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)
|
||||
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
// 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
|
||||
// Assign the map with some data
|
||||
map_employee_id_set_at(Employees, 17425, STRING_CTE("Mike"));
|
||||
map_employee_id_set_at(Employees, 7147, STRING_CTE("Tango"));
|
||||
map_employee_id_set_at(Employees, 841, STRING_CTE("Charlie"));
|
||||
map_employee_id_set_at(Employees, 11632, STRING_CTE("John Do"));
|
||||
map_employee_id_set_at(Employees, 852, STRING_CTE("Peter"));
|
||||
map_employee_id_set_at(Employees, 530, STRING_CTE("Amanda"));
|
||||
map_employee_id_set_at(Employees, 4258, STRING_CTE("Elisabeth"));
|
||||
|
||||
// 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));
|
||||
|
||||
@@ -30,11 +36,13 @@ int main(void)
|
||||
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_type_t *e = map_employee_id_cref(it);
|
||||
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) {
|
||||
|
||||
@@ -51,10 +59,10 @@ int main(void)
|
||||
}
|
||||
|
||||
// Print
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
|
||||
|
||||
}
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get(Employees_r, STRING_CTE("Elisabeth")));
|
||||
} /* Employees_r is cleared beyond this point */
|
||||
|
||||
// But employee is not
|
||||
map_employee_id_clear(Employees);
|
||||
return 0;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "m-buffer.h"
|
||||
#include "m-shared.h"
|
||||
#include "m-mutex.h"
|
||||
#include "m-thread.h"
|
||||
|
||||
/* Global variable to stop scheduling */
|
||||
atomic_bool continue_threading_g;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "m-string.h"
|
||||
|
||||
// Define a dictionnary of string --> int
|
||||
// named 'str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
// named 'dict_str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
@@ -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,7 +14,7 @@ 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);
|
||||
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)) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/* 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))
|
||||
// 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 *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;
|
||||
}
|
||||
@@ -3,30 +3,54 @@
|
||||
#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) {
|
||||
M_LET(word, string_t)
|
||||
M_LET(positions, map_pos_t) {
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) return 1;
|
||||
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
|
||||
array_size_t *array = map_pos_get_at(positions, word);
|
||||
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -24,22 +24,25 @@
|
||||
|
||||
/* Define the needed data structure : */
|
||||
|
||||
// Define a dictionnary of constant string --> integer
|
||||
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_DEFAULT_OPLIST)
|
||||
// Define 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)
|
||||
|
||||
// Defin an array of integer
|
||||
// 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)
|
||||
|
||||
// Defin an array of integer
|
||||
// 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);
|
||||
@@ -121,7 +124,7 @@ CreateMinimalPerfectHash2(array_seed_t seed, array_value_t value,
|
||||
enought. */
|
||||
for(bool cont = true; cont ; ) {
|
||||
cont = false;
|
||||
array_seed_clean(slots);
|
||||
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)){
|
||||
@@ -191,7 +194,11 @@ static void
|
||||
dict_read_from_file(dict_mph_t dict, array_string_t arr, const char filename[])
|
||||
{
|
||||
FILE *f = fopen(filename, "rt");
|
||||
if (!f) abort();
|
||||
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)) {
|
||||
@@ -234,12 +241,14 @@ test(array_seed_t seed, array_value_t value, dict_mph_t dict)
|
||||
|
||||
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);
|
||||
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_get_at (p->bracket_map, left) = right;
|
||||
*array_int_get_at (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,70 +0,0 @@
|
||||
#if HAVE_GMP
|
||||
|
||||
#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 */
|
||||
}
|
||||
|
||||
#else
|
||||
// Nothing to do
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -4,7 +4,7 @@
|
||||
/* Register a dynamic seed to M*LIB hash function.
|
||||
This shall be done before any M*LIB header inclusion. */
|
||||
unsigned long long rand_seed;
|
||||
#define M_HASH_SEED rand_seed
|
||||
#define M_USE_HASH_SEED rand_seed
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-dict.h"
|
||||
@@ -84,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)))
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
order to show/test the good chaining of the structures */
|
||||
|
||||
TUPLE_DEF2(symbol, (type, int), (name, string_t))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
#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())
|
||||
@@ -19,13 +19,13 @@ 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)
|
||||
#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)
|
||||
#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() )
|
||||
@@ -37,11 +37,11 @@ BUFFER_DEF(trbuff, my_triple_tuple_t, 100, BUFFER_QUEUE)
|
||||
#define M_OPL_trbuff_t() BUFFER_OPLIST(trbuff, M_OPL_my_triple_tuple_t())
|
||||
|
||||
TUPLE_DEF2(my_junction, (active, bool), (buffer, trbuff_t))
|
||||
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_DEFAULT_OPLIST, M_OPL_trbuff_t())
|
||||
#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_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
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),
|
||||
@@ -51,6 +51,9 @@ TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
|
||||
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;
|
||||
@@ -68,6 +71,7 @@ static void let2(void)
|
||||
|
||||
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)
|
||||
|
||||
@@ -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,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,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,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;
|
||||
}
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
|
||||
// Serial json is not supported for standard types if not C11
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
/* Basic example to show JSON serialization */
|
||||
|
||||
// Let's define a 'person' composed of several fields.
|
||||
TUPLE_DEF2(person,
|
||||
@@ -11,10 +10,12 @@ TUPLE_DEF2(person,
|
||||
(age, int),
|
||||
(present, bool)
|
||||
)
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST, M_DEFAULT_OPLIST )
|
||||
// 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
|
||||
@@ -29,6 +30,7 @@ static void read(base_t base, const char filename[])
|
||||
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
|
||||
@@ -44,21 +46,18 @@ static void read(base_t base, const char filename[])
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's have base as a base_t
|
||||
M_LET(base, base_t) {
|
||||
read(base, "ex-json01.json");
|
||||
// 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));
|
||||
}
|
||||
if ((*el)->present) {
|
||||
printf("%s\n", string_get_cstr((*el)->surname));
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
#if HAVE_GMP && HAVE_MPFR
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gmp.h>
|
||||
#include <mpfr.h>
|
||||
|
||||
#include "m-variant.h"
|
||||
#include "m-string.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-algo.h"
|
||||
|
||||
// GMP doesn't provide a fast hash function (It is needed for being able to use mpz_t as key in a hashmap)
|
||||
static inline size_t
|
||||
mpz_fast_hash(const mpz_t z)
|
||||
{
|
||||
mp_size_t n = z->_mp_size;
|
||||
mp_limb_t *p = z->_mp_d;
|
||||
M_HASH_DECL(hash);
|
||||
|
||||
if (n <= 0) {
|
||||
M_HASH_UP (hash, 0x7F5C1458);
|
||||
if (n == 0) {
|
||||
return M_HASH_FINAL (hash);
|
||||
}
|
||||
n = -n;
|
||||
}
|
||||
while (n-- > 0) {
|
||||
M_HASH_UP (hash, *p++);
|
||||
}
|
||||
return M_HASH_FINAL (hash);
|
||||
}
|
||||
|
||||
/* Define the OPLIST of a mpz_t and register it globally */
|
||||
#define M_OPL_mpz_t() \
|
||||
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
|
||||
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
|
||||
EQUAL( API( mpz_cmp, EQ(0), ARG1, ARG2)), \
|
||||
CMP(mpz_cmp), \
|
||||
HASH(mpz_fast_hash), \
|
||||
OUT_STR( API( mpz_out_str, VOID, ARG1, 10, ARG2)), \
|
||||
IN_STR( API( mpz_inp_str, GT(0), ARG1, ARG2, 10)), \
|
||||
ADD(mpz_add), SUB(mpz_sub), MUL(mpz_mul), DIV(mpz_div), \
|
||||
EMPLACE_TYPE( LIST( (_si, mpz_init_set_si, int), \
|
||||
(_ui, mpz_init_set_ui, unsigned), \
|
||||
(_d, mpz_init_set_d, double), \
|
||||
(_cstr, API(mpz_init_set_str, VOID, ARG1, ARG2, 10), const char *), \
|
||||
(_str, API(mpz_init_set_str, VOID, ARG1, ARG2, 10), char *) )), \
|
||||
TYPE(mpz_t) )
|
||||
|
||||
|
||||
|
||||
// MPFR doesn't provide a fast hash function (It is needed for being able to use mpz_t as key in a hashmap)
|
||||
static size_t
|
||||
mpfr_fast_hash (const mpfr_t f)
|
||||
{
|
||||
mp_limb_t *p = f->_mpfr_d;
|
||||
mp_size_t n = (f->_mpfr_prec-1)/(sizeof(mp_limb_t)*CHAR_BIT)+1;
|
||||
M_HASH_DECL (h);
|
||||
|
||||
M_HASH_UP (h, f->_mpfr_exp);
|
||||
|
||||
if (MPFR_SIGN (f) < 0)
|
||||
M_HASH_UP (h, 1);
|
||||
|
||||
/* Special value: NAN, INF and ZERO */
|
||||
if (mpfr_nan_p (f) || mpfr_inf_p (f) || mpfr_zero_p (f))
|
||||
return M_HASH_FINAL (h);
|
||||
|
||||
/* Mantissa */
|
||||
do {
|
||||
M_HASH_UP (h, *p++);
|
||||
} while (--n > 0);
|
||||
return M_HASH_FINAL (h);
|
||||
}
|
||||
|
||||
/* Define the OPLIST of a mpfr_t and register it globally */
|
||||
#define M_OPL_mpfr_t() \
|
||||
(INIT(mpfr_init), INIT_SET(API(mpfr_init_set, VOID, ARG1, ARG2, MPFR_RNDN)), SET(API(mpfr_set, VOID, ARG1, ARG2, MPFR_RNDN)), CLEAR(mpfr_clear), \
|
||||
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
|
||||
EQUAL( API( mpfr_cmp, EQ(0), ARG1, ARG2)), \
|
||||
CMP(mpfr_cmp), \
|
||||
HASH(mpfr_fast_hash), \
|
||||
OUT_STR( API( mpfr_out_str, VOID, ARG1, 10, 0, ARG2, MPFR_RNDN)), \
|
||||
IN_STR( API( mpfr_inp_str, GT(0), ARG1, ARG2, 10, MPFR_RNDN)), \
|
||||
ADD( API(mpfr_add, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
SUB( API(mpfr_sub, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
MUL( API(mpfr_mul, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
DIV( API(mpfr_div, VOID, ARG1, ARG2, ARG3, MPFR_RNDN)), \
|
||||
EMPLACE_TYPE( LIST( (_si, API(mpfr_init_set_si, VOID, ARG1, ARG2, MPFR_RNDN), int), \
|
||||
(_ui, API(mpfr_init_set_ui, VOID, ARG1, ARG2, MPFR_RNDN), unsigned), \
|
||||
(_d, API(mpfr_init_set_d, VOID, ARG1, ARG2, MPFR_RNDN), double), \
|
||||
(_ld, API(mpfr_init_set_ld, VOID, ARG1, ARG2, MPFR_RNDN), long double), \
|
||||
(_z, API(mpfr_init_set_z, VOID, ARG1, ARG2, MPFR_RNDN), mpz_t), \
|
||||
(_zptr, API(mpfr_init_set_z, VOID, ARG1, ARG2, MPFR_RNDN), mpz_ptr), \
|
||||
(_cstr, API(mpfr_init_set_str, VOID, ARG1, ARG2, 10, MPFR_RNDN), const char *), \
|
||||
(_str, API(mpfr_init_set_str, VOID, ARG1, ARG2, 10, MPFR_RNDN), char *) )), \
|
||||
TYPE(mpfr_t) )
|
||||
|
||||
|
||||
/* Define a variant (aka a typed union) over three kind of numbers named my_number_t
|
||||
Notice than mpz_t/mpfr_t has special init & clear functions.
|
||||
This is handled by the library.
|
||||
*/
|
||||
VARIANT_DEF2(my_number,
|
||||
(n, long long),
|
||||
(z, mpz_t),
|
||||
(fr, mpfr_t) )
|
||||
/* Register the oplist associated to this variant named my_number_t */
|
||||
#define M_OPL_my_number_t() VARIANT_OPLIST(my_number, M_BASIC_OPLIST, M_OPL_mpz_t(), M_OPL_mpfr_t() )
|
||||
|
||||
|
||||
/* Define a dictionary of string_t --> my_number_t named my_dict_t */
|
||||
DICT_DEF2(my_dict, string_t, my_number_t)
|
||||
/* Register the oplist associated to this dictionary named my_dict_t */
|
||||
#define M_OPL_my_dict_t() DICT_OPLIST(my_dict, STRING_OPLIST, M_OPL_my_number_t() )
|
||||
|
||||
|
||||
/* Define an array of such dictionary named my_array_t */
|
||||
ARRAY_DEF(my_array, my_dict_t)
|
||||
/* Register the oplist associated to this array (of dictionary of variant) named my_array_t*/
|
||||
#define M_OPL_my_array_t() ARRAY_OPLIST(my_array, M_OPL_my_dict_t())
|
||||
|
||||
|
||||
// Show how to define an array of mpz_t and some algorithms on it
|
||||
ARRAY_DEF(array_mpz, mpz_t)
|
||||
#define M_OPL_array_mpz_t() ARRAY_OPLIST(array_mpz, M_OPL_mpz_t())
|
||||
ALGO_DEF(array_mpz, array_mpz_t)
|
||||
|
||||
// Show how to define an array of mpfr_t and some algorithms on it
|
||||
ARRAY_DEF(array_mpfr, mpfr_t)
|
||||
#define M_OPL_array_mpfr_t() ARRAY_OPLIST(array_mpfr, M_OPL_mpfr_t())
|
||||
ALGO_DEF(array_mpfr, array_mpfr_t)
|
||||
|
||||
static void
|
||||
compute_roots(array_mpfr_t roots, const array_mpz_t pol)
|
||||
{
|
||||
assert( array_mpz_size(pol) == 3);
|
||||
// Initialize mpfr_t variables from the mpz_t values in the array 'pol'
|
||||
M_LET( (a, (*array_mpz_get(pol, 0))),
|
||||
(b, (*array_mpz_get(pol, 1))),
|
||||
(c, (*array_mpz_get(pol, 2))),
|
||||
delta, tmp, mpfr_t) {
|
||||
// Reset the output array
|
||||
array_mpfr_reset(roots);
|
||||
// Compute the first root
|
||||
mpfr_mul(delta, b, b, MPFR_RNDN);
|
||||
mpfr_mul_ui(tmp, a, 4, MPFR_RNDN);
|
||||
mpfr_mul(tmp, tmp, c, MPFR_RNDN);
|
||||
mpfr_sub(delta, delta, tmp, MPFR_RNDN);
|
||||
mpfr_sqrt(delta, delta, MPFR_RNDN);
|
||||
mpfr_neg(tmp, b, MPFR_RNDN);
|
||||
mpfr_add(tmp, tmp, delta, MPFR_RNDN);
|
||||
mpfr_div(tmp, tmp, a, MPFR_RNDN);
|
||||
mpfr_div_2ui(tmp, tmp, 1, MPFR_RNDN);
|
||||
// Push first root
|
||||
array_mpfr_push_back(roots, tmp);
|
||||
// Compute second root
|
||||
mpfr_neg(tmp, b, MPFR_RNDN);
|
||||
mpfr_sub(tmp, tmp, delta, MPFR_RNDN);
|
||||
mpfr_div(tmp, tmp, a, MPFR_RNDN);
|
||||
mpfr_div_2ui(tmp, tmp, 1, MPFR_RNDN);
|
||||
// Push second root
|
||||
array_mpfr_push_back(roots, tmp);
|
||||
} // Clear the mpfr_t variables after this point.
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(z, my_number_t) /* Define & init & clear an instance of a variant of my_number_t */
|
||||
M_LET(dict, my_dict_t) /* Define & init & clear an instance of a dictionary of variant */
|
||||
M_LET(array, my_array_t) /* Define & init & clear an intance of an array of dictionary of variant */
|
||||
M_LET(gmp, mpz_t) /* M_LET allows even with non container type */
|
||||
{
|
||||
my_number_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_number_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
|
||||
|
||||
// Let's add a new element in the array through a mpfr_t set to 42.17
|
||||
M_LET( (fr, ("42.17")), mpfr_t) {
|
||||
my_number_set_fr(z, fr); // Set z as this variable.
|
||||
}
|
||||
my_dict_set_at(dict, STRING_CTE("n3"), z); // Push it in the dictionary
|
||||
|
||||
my_number_emplace_fr_si(z, 42); // Directly emplace the variant as a mpfr_t with a signed integer for init
|
||||
my_dict_set_at(dict, STRING_CTE("n4"), z); // Push it in the dictionary
|
||||
|
||||
my_number_emplace_z_ui(z, 189); // Directly emplace the variant as a mpz_t with an unsigned integer for init
|
||||
my_dict_set_at(dict, STRING_CTE("n5"), 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_t) {
|
||||
// Iterate over the dictionary '*item' container which is of type my_dict_t
|
||||
for M_EACH(p, *item, my_dict_t) {
|
||||
// Dictionary iterator are pair (key,value)
|
||||
printf("Key is '%s'. ", string_get_cstr(p->key));
|
||||
// In function of the type of value
|
||||
if (my_number_n_p(p->value)) {
|
||||
// Print it.
|
||||
M_PRINT("It is a long long, value = ", *my_number_cget_n(p->value), "\n");
|
||||
}
|
||||
if (my_number_z_p(p->value)) {
|
||||
// Print it. Since mpz_t isn't a native type, M_PRINT macro doesn't know it by default
|
||||
// So we need to add the type to the value.
|
||||
// M_PRINT will then look at its globally registered oplist
|
||||
// and known how to print it.
|
||||
M_PRINT("It is a mpz_t, value = ", (*my_number_cget_z(p->value), mpz_t), "\n");
|
||||
}
|
||||
if (my_number_fr_p(p->value)) {
|
||||
// Same but with a MPFR number.
|
||||
M_PRINT("It is a mpfr_t, value = ", (*my_number_cget_fr(p->value), mpfr_t), "\n");
|
||||
}
|
||||
}
|
||||
printf("Next element of array\n");
|
||||
}
|
||||
|
||||
// Print all the array in one step. Need to be done in C11 only
|
||||
M_PRINT("\nThe array is equal to ", (array, my_array_t), "\n");
|
||||
} /* All variables are automatically cleared beyond this point */
|
||||
|
||||
// Define an array of mpz_t as { 1, 2, 1 } (with auto promotion from integer / string / double)
|
||||
// The auto-promotion uses _Generic feature and is available only in C11.
|
||||
M_LET ( (az, (1), ("2"), (1.0)), array_mpz_t)
|
||||
M_LET ( roots, array_mpfr_t) {
|
||||
// Compute roots
|
||||
compute_roots(roots, az);
|
||||
// Display of roots:
|
||||
M_PRINT("Roots of ", (az, array_mpz_t), " are ", (roots, array_mpfr_t), "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
// Nothing to do
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-rbtree.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's define a Red Black Tree over the constant C strings
|
||||
// Notice that we need to specify the oplist for this case
|
||||
// so that M*LIB handle the pointers to const char correctly.
|
||||
RBTREE_DEF(tree_cstr, const char *, M_CSTR_OPLIST)
|
||||
|
||||
// The classic C way
|
||||
// It is probably the best for beginner in M*LIB to start like this.
|
||||
static void classic1(void)
|
||||
{
|
||||
// Let's declare a tree on the stack.
|
||||
// Even if the tree itself is allocated on the stack,
|
||||
// the nodes will be allocated on the heap.
|
||||
tree_cstr_t tree;
|
||||
// Initialize the tree using the provided constructor
|
||||
tree_cstr_init(tree);
|
||||
|
||||
// Let's fill in the tree
|
||||
// Note that the object of the tree are pointer
|
||||
// to array of char. Therefore the strings themselves
|
||||
// are not stored in the tree but only a reference to then
|
||||
// As such, the pointed objects shall not moved nor being
|
||||
// destroyed, which is the case for const C string.
|
||||
tree_cstr_push (tree, "Hello");
|
||||
tree_cstr_push (tree, "World");
|
||||
tree_cstr_push (tree, "How");
|
||||
tree_cstr_push (tree, "Are");
|
||||
tree_cstr_push (tree, "You");
|
||||
|
||||
// Let's print the tree.
|
||||
// We'll use the OUT_STR method to display the tree
|
||||
// without iterating ourself in the tree.
|
||||
printf("\nUsing C string, the generated (sorted) tree is ");
|
||||
tree_cstr_out_str(stdout, tree);
|
||||
printf ("\n");
|
||||
|
||||
// Let's search for the key "How" in the tree.
|
||||
// If it is not found a NULL pointer is returned.
|
||||
// Otherwise a pointer to the key within the tree is returned.
|
||||
// This pointer is valid until a modification operation on the tree is done.
|
||||
const char *present = tree_cstr_get(tree, "How") == NULL ? "not " : "";
|
||||
printf("The word 'How' is %spresent\n", present);
|
||||
|
||||
present = tree_cstr_get(tree, "Not") == NULL ? "not " : "";
|
||||
printf("The word 'Not' is %spresent\n", present);
|
||||
|
||||
// Destroy the tree by calling the destructor.
|
||||
tree_cstr_clear(tree);
|
||||
}
|
||||
|
||||
|
||||
// Let's define another Red Black Tree over the M*LIB strings
|
||||
// Notice that we don't need to specify the oplist for this case.
|
||||
// since the oplist of a string_t is registered globally.
|
||||
RBTREE_DEF(tree_str, string_t)
|
||||
|
||||
// The classic C way
|
||||
// It is probably the best for beginner in M*LIB to start like this.
|
||||
static void classic2(void)
|
||||
{
|
||||
tree_str_t tree;
|
||||
|
||||
tree_str_init(tree);
|
||||
|
||||
// STRING_CTE enables to construct a temporary const string_t from a const char *
|
||||
// usable for function call.
|
||||
// Note that this time the full string is stored within the tree,
|
||||
// and not only a pointer to it.
|
||||
tree_str_push (tree, STRING_CTE("Hello"));
|
||||
tree_str_push (tree, STRING_CTE("World"));
|
||||
tree_str_push (tree, STRING_CTE("How"));
|
||||
tree_str_push (tree, STRING_CTE("Are"));
|
||||
// We may also push a const C string into a string_t by calling the emplace function
|
||||
tree_str_emplace (tree, "You");
|
||||
|
||||
// Let's print the tree
|
||||
printf("\nUsing M*LIB string_t, the generated (sorted) tree is ");
|
||||
tree_str_out_str(stdout, tree);
|
||||
printf ("\n");
|
||||
|
||||
// Let's search for the string "How"
|
||||
// We convert it to a temporary string_t, and let's test
|
||||
// if it is found or not by testing if the returned pointer to string_t
|
||||
// is null or not.
|
||||
const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : "";
|
||||
printf("The word 'How' is %spresent\n", present);
|
||||
|
||||
present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : "";
|
||||
printf("The word 'Not' is %spresent\n", present);
|
||||
|
||||
tree_str_clear(tree);
|
||||
}
|
||||
|
||||
|
||||
// Registering the oplist helps writting the macro
|
||||
// as we can only refer to the type in the macro.
|
||||
#define M_OPL_tree_str_t() RBTREE_OPLIST(tree_str, STRING_OPLIST)
|
||||
|
||||
static void macro(void)
|
||||
{
|
||||
// Using macro (shorter but may be unfamiliar syntax for novive with M*LIB)
|
||||
// This will declare the variable 'tree' as a 'tree_str_t' and initialize with
|
||||
// the given initialization list '("Hello"), ("World"), ("How"), ("Are"), ("You")'
|
||||
// The strings are given within '()' so that the constructor performs an emplace
|
||||
// of the value to push in the tree (to initialize a string_t with a const char * type)
|
||||
// instead of a push (which takes a compliant string_t as argument).
|
||||
// An alternative is to use STRING_CTE for the arguments.
|
||||
M_LET( (tree, ("Hello"), ("World"), ("How"), ("Are"), ("You")), tree_str_t) {
|
||||
// In C11, the M_PRINT macro allows the use of a simplified syntax for printing.
|
||||
M_PRINT("\nUsing M*LIB string_t + macro, the generated (sorted) tree is ", (tree, tree_str_t), "\n");
|
||||
|
||||
const char *present = tree_str_get(tree, STRING_CTE("How")) == NULL ? "not " : "";
|
||||
printf("The word 'How' is %spresent\n", present);
|
||||
|
||||
present = tree_str_get(tree, STRING_CTE("Not")) == NULL ? "not " : "";
|
||||
printf("The word 'Not' is %spresent\n", present);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
classic1();
|
||||
classic2();
|
||||
macro();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m-array.h"
|
||||
@@ -7,12 +5,15 @@
|
||||
#include "m-dict.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's define a tuple composed of (offset, value) and register it
|
||||
TUPLE_DEF2(symbol, (offset, long), (value, long))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// Let's define an array of such tuple and register it
|
||||
ARRAY_DEF(array_symbol, symbol_t)
|
||||
#define M_OPL_array_symbol_t() ARRAY_OPLIST(array_symbol, M_OPL_symbol_t())
|
||||
|
||||
// Let's define a dictionnary associating a string_t to such an array and register it
|
||||
DICT_DEF2(sections, string_t, array_symbol_t)
|
||||
#define M_OPL_sections_t() DICT_OPLIST(sections, STRING_OPLIST, M_OPL_array_symbol_t())
|
||||
|
||||
@@ -20,13 +21,21 @@ int main(int argc, const char *argv[])
|
||||
{
|
||||
if (argc < 2) abort();
|
||||
FILE *f = fopen(argv[1], "rt");
|
||||
if (!f) abort();
|
||||
if (!f) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s\n", argv[1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Create & initialize sc as sections_t
|
||||
M_LET(sc, sections_t) {
|
||||
// Read the section from the FILE
|
||||
sections_in_str(sc, f);
|
||||
// Get the section named .text
|
||||
array_symbol_t *a = sections_get(sc, STRING_CTE(".text"));
|
||||
if (a == NULL) {
|
||||
printf("There is no .text section.");
|
||||
} else {
|
||||
// Print its content
|
||||
printf("Section .text is :");
|
||||
array_symbol_out_str(stdout, *a);
|
||||
printf("\n");
|
||||
@@ -34,7 +43,3 @@ int main(int argc, const char *argv[])
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Based on the example of STC https://github.com/tylov/STC */
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-tuple.h"
|
||||
|
||||
// NOTE: After each definition of a container, we register its oplist
|
||||
// It is not mandatory, but it makes the code easier to write and read.
|
||||
|
||||
// Define a basic structure (POD structure) using a tuple to get the default functions
|
||||
TUPLE_DEF2(Point, (x, float), (y, float))
|
||||
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// NOTE: array, list, deque don't have a native find function.
|
||||
// We'll use the algorithm header to create a find function for such containers.
|
||||
|
||||
// Define a set of int & register its oplist
|
||||
DICT_SET_DEF(cset_i, int)
|
||||
#define M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_BASIC_OPLIST)
|
||||
|
||||
// Define an array of Point, register its oplist & include some basic algorithms
|
||||
ARRAY_DEF(cvec_p, Point_t)
|
||||
#define M_OPL_cvec_p_t() ARRAY_OPLIST(cvec_p, M_OPL_Point_t())
|
||||
ALGO_DEF(cvec_p, cvec_p_t)
|
||||
|
||||
// Define a deque of int, including some basic algorithms
|
||||
DEQUE_DEF(cdeq_i, int)
|
||||
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_BASIC_OPLIST)
|
||||
ALGO_DEF(cdeq_i, cdeq_i_t)
|
||||
|
||||
// Define a backward list, including some basic algorithms
|
||||
LIST_DEF(clist_i, int)
|
||||
#define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_BASIC_OPLIST)
|
||||
ALGO_DEF(clist_i, clist_i_t)
|
||||
|
||||
// Define an unordered map of int to int
|
||||
DICT_DEF2(csmap_i, int, int)
|
||||
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define, init & set the different containers.
|
||||
M_LET( (set, 10, 20, 30), cset_i_t)
|
||||
M_LET( (vec, (10, 1), (20, 2), (30, 3) ), cvec_p_t)
|
||||
M_LET( (deq, 10, 20, 30), cdeq_i_t)
|
||||
M_LET( (lst, 10, 20, 30), clist_i_t)
|
||||
M_LET( (map, (20, 2), (10, 1), (30,3) ), csmap_i_t) {
|
||||
|
||||
// add one more element to each container
|
||||
cset_i_push(set, 40);
|
||||
cvec_p_push_back(vec, (Point_t) {{40, 4}} );
|
||||
cdeq_i_push_front(deq, 5);
|
||||
clist_i_push_back(lst, 5);
|
||||
csmap_i_set_at(map, 40, 4);
|
||||
|
||||
M_PRINT("vec= ", (vec, cvec_p_t));
|
||||
|
||||
// Find an element (either native or through the algo header)
|
||||
int *i1 = cset_i_get(set, 20);
|
||||
cvec_p_it_t i2; cvec_p_find(i2, vec, (Point_t) {{20, 2}});
|
||||
cdeq_i_it_t i3; cdeq_i_find(i3, deq, 20);
|
||||
clist_i_it_t i4; clist_i_find(i4, lst, 20);
|
||||
int *i5 = csmap_i_get(map, 20);
|
||||
printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n",
|
||||
*i1,
|
||||
(*cvec_p_ref(i2))->x, (*cvec_p_ref(i2))->y,
|
||||
*cdeq_i_ref(i3),
|
||||
*clist_i_ref(i4),
|
||||
20, *i5);
|
||||
|
||||
// Erase the elements found (through key or through iterators)
|
||||
cset_i_erase(set, *i1);
|
||||
cvec_p_remove(vec, i2);
|
||||
cdeq_i_remove(deq, i3);
|
||||
clist_i_remove(lst, i4);
|
||||
csmap_i_erase(map, *i5);
|
||||
|
||||
// Display everything in one call by using the registered print functions of the different types.
|
||||
M_PRINT("After erasing elements found:\n",
|
||||
"set: ", (set, cset_i_t), "\n",
|
||||
"vec: ", (vec, cvec_p_t), "\n",
|
||||
"deq: ", (deq, cdeq_i_t), "\n",
|
||||
"map: ", (map, csmap_i_t), "\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef MY_HEADER
|
||||
#define MY_HEADER
|
||||
|
||||
// Request M*LIB to not inline functions if not the library source
|
||||
#define M_USE_DECL
|
||||
#include "m-string.h"
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array_str, string_t)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// Request M*LIB to define functions
|
||||
// This include both m-string functions and array_str templated functions
|
||||
// Defining M_USE_EXTERN_DEF override M_USE_EXTERN_DECL definition
|
||||
#define M_USE_DEF
|
||||
#include "exm-header.h"
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "exm-header.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
array_str_t a;
|
||||
array_str_init(a);
|
||||
array_str_emplace_back(a, "Hello");
|
||||
array_str_emplace_back(a, "World");
|
||||
printf("a=");
|
||||
array_str_out_str(stdout, a);
|
||||
printf("\n");
|
||||
array_str_clear(a);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef MY_HEADER
|
||||
#define MY_HEADER
|
||||
|
||||
// Request M*LIB to not always inline functions
|
||||
#define M_USE_FINE_GRAINED_LINKAGE
|
||||
#include "m-string.h"
|
||||
#include "m-array.h"
|
||||
|
||||
// The following functions will not be inlined:
|
||||
#define M_USE_DECL
|
||||
ARRAY_DEF(array_str, string_t)
|
||||
#undef M_USE_DECL
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
// Request M*LIB to define functions for functions defined within M_USE_DECL.
|
||||
#define M_USE_DEF
|
||||
#include "exn-header.h"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "exn-header.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
string_t s;
|
||||
string_init_set_str(s, "a=");
|
||||
string_fputs(stdout, s);
|
||||
string_clear(s);
|
||||
array_str_t a;
|
||||
array_str_init(a);
|
||||
array_str_emplace_back(a, "Hello");
|
||||
array_str_emplace_back(a, "World");
|
||||
//printf("a=");
|
||||
array_str_out_str(stdout, a);
|
||||
printf("\n");
|
||||
array_str_clear(a);
|
||||
//main2();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2019, Patrick Pelissier
|
||||
* 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:
|
||||
@@ -26,14 +26,17 @@
|
||||
#define MSTARLIB_ATOMIC_H
|
||||
|
||||
/* NOTE: Due to the C++ not having recognized stdatomic.h officialy,
|
||||
it is hard to use this header directly with a C++ compiler like
|
||||
g++ or MSVC.
|
||||
(See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932 ).
|
||||
clang has no issue with this header.
|
||||
GCC 4.9 doesn't have a working implementation of 'atomic'
|
||||
it is hard to use this header directly with a C++ compiler.
|
||||
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932
|
||||
clang++ has no issue with this header but if someone includes
|
||||
atomic from C++, there is incompatibility between atomic & stdatomic.
|
||||
Moreover some compilers lack a working stdatomic header.
|
||||
GCC 4.9 doesn't have a working implementation of 'atomic'.
|
||||
APPLE Clang defines __GNUC__ to be only 4 despite having full support
|
||||
for atomic.
|
||||
*/
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
&& !defined(__clang__) && !(defined(__GNUC__) && __GNUC__ < 5)
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
&& !(defined(__GNUC__) && __GNUC__ < 5 && !defined(__APPLE__))
|
||||
|
||||
/* NOTE: This is what the stdatomic.h header shall do in C++ mode. */
|
||||
#include <atomic>
|
||||
@@ -96,14 +99,38 @@ using std::memory_order_release;
|
||||
using std::memory_order_acq_rel;
|
||||
using std::memory_order_seq_cst;
|
||||
|
||||
/* CLANG provides a warning on defining _Atomic as it sees it
|
||||
* as a reserved system macro. It is true. However, the goal of this
|
||||
* header is to provide stdatomic semantic, so it needs to define
|
||||
* _Atomic macro.
|
||||
*
|
||||
* So, this warning has to be ignored.
|
||||
*
|
||||
* It cannot use M_BEGIN_PROTECTED_CODE as this header is normally
|
||||
* independent of m-core.h
|
||||
*/
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
|
||||
#endif
|
||||
|
||||
#define _Atomic(T) std::atomic< T >
|
||||
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|
||||
|| ( defined(__GNUC__) && !defined(__clang__) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && __clang_major__ >= 4)
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic pop")
|
||||
#endif
|
||||
|
||||
/* C11 with working stdatomic
|
||||
STDATOMIC doesn't work with C++ except for clang but is incompatible with atomic.
|
||||
GCC < 4.9 doesn't provide a compliant stdatomic.h
|
||||
CLANG 3.5 has issues with GCC's stdatomic.h and doesn't provide its own
|
||||
ICC < 18 doesn't provide a compliant stdatomic.h
|
||||
*/
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) ) \
|
||||
|| (defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 308) \
|
||||
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
|
||||
|
||||
/* CLANG 3.5 has issues with GCC's stdatomic.h
|
||||
and doesn't provide its own stdatomic.h */
|
||||
#include <stdatomic.h>
|
||||
|
||||
/* MSYS2 has a conflict between cdefs.h which defines a _Atomic macro (if not C11)
|
||||
@@ -118,32 +145,38 @@ using std::memory_order_seq_cst;
|
||||
# undef _Atomic
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* Non working atomic.h, nor working stdatomic.h found.
|
||||
/* Non working C++ atomic header, nor working stdatomic.h found.
|
||||
Write a compatible layer using mutex as slin as possible.
|
||||
Supports only up to 64-bits atomic (sizeof long long to be more precise).
|
||||
The locks are never properly cleared and remain active until
|
||||
the end of the program.
|
||||
We also assume that the call to the atomic_* interface is "clean".
|
||||
We also assume that the call to the atomic_* interface is "macro clean".
|
||||
*/
|
||||
#include "m-mutex.h"
|
||||
#else
|
||||
|
||||
/* The structure is quite large:
|
||||
#include "m-thread.h"
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* _Atomic qualifier for a type (emulation).
|
||||
The structure is quite large:
|
||||
_val : value of the atomic type,
|
||||
_zero : zero value of the atomic type (constant),
|
||||
_previous: temporary value used within the mutex lock,
|
||||
_lock : the mutex lock.
|
||||
Support up to sizeof (long long) type.
|
||||
*/
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
T volatile _val; \
|
||||
T _zero; \
|
||||
T _previous; \
|
||||
m_mutex_t _lock; \
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
T volatile _val; \
|
||||
T _zero; \
|
||||
T _previous; \
|
||||
m_mutex_t _lock; \
|
||||
}
|
||||
|
||||
/* Even if memory order is defined, only the strongest constraint is used */
|
||||
/* Define the supported memory order.
|
||||
Even if memory order is defined, only the strongest constraint is used */
|
||||
typedef enum {
|
||||
memory_order_relaxed,
|
||||
memory_order_consume,
|
||||
@@ -184,76 +217,96 @@ typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
#endif
|
||||
|
||||
/* Detect if stdint.h was included */
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
defined (_SYS_STDINT_H_)
|
||||
/* Define additional atomic types */
|
||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||
typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||
#endif
|
||||
|
||||
/* Unlock the mutex and return the given value */
|
||||
static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
/* (INTERNAL) Unlock the mutex and return the given value */
|
||||
M_INLINE long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
{
|
||||
m_mutex_unlock (*lock);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* This is the heart of the wrapper:
|
||||
/* (INTERNAL) This is the heart of the wrapper:
|
||||
lock the atomic value, read it and returns the value.
|
||||
In order to avoid any compiler extension, we need to transform the
|
||||
atomic type into 'long long' then convert it back to its value.
|
||||
This is because _previous can't be read after the lock, and we can't
|
||||
generate temporary variable within a macro.
|
||||
The trick is computing _val - _zero within the lock, then
|
||||
returns retvalue + _zero after the lock.
|
||||
returns retvalue + _zero after the release of the lock.
|
||||
*/
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
(ptr)->_val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
(ptr)->_val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long)((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
/* Perform an atomic add (EMULATION) */
|
||||
#define atomic_fetch_add(ptr, val) atomic_fetch_op(ptr, val, +=)
|
||||
/* Perform an atomic sub (EMULATION) */
|
||||
#define atomic_fetch_sub(ptr, val) atomic_fetch_op(ptr, val, -=)
|
||||
/* Perform an atomic or (EMULATION) */
|
||||
#define atomic_fetch_or(ptr, val) atomic_fetch_op(ptr, val, |=)
|
||||
/* Perform an atomic xor (EMULATION) */
|
||||
#define atomic_fetch_xor(ptr, val) atomic_fetch_op(ptr, val, ^=)
|
||||
/* Perform an atomic and (EMULATION) */
|
||||
#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=)
|
||||
/* Perform an atomic exchange (EMULATION) */
|
||||
#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =)
|
||||
|
||||
/* Initialize an atomic GLOBAL variable */
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
|
||||
#define atomic_init(ptr, val) \
|
||||
/* Initialize an atomic variable */
|
||||
#define atomic_init(ptr, val) \
|
||||
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
|
||||
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (ptr)->_previous-(ptr)->_zero)+(ptr)->_zero)
|
||||
/* (INTERNAL) Load an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long) ((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
/* (INTERNAL) Store an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
m_mutex_unlock((ptr)->_lock))
|
||||
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
/* Atomic load of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct read of the variable (much faster) */
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
: atomic_load_lock(ptr))
|
||||
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
} else { \
|
||||
long long _offset = (val) - (ptr)->_zero; \
|
||||
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
|
||||
} \
|
||||
/* Atomic store of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct write of the variable (much faster) */
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
} else { \
|
||||
long long _offset = (long long) ((val) - (ptr)->_zero); \
|
||||
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
(ptr)->_val == *(exp) \
|
||||
? ((ptr)->_val = (val), true) \
|
||||
/* Perform a CAS (Compare and swap) operation (EMULATION) */
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
(ptr)->_val == *(exp) \
|
||||
? ((ptr)->_val = (val), true) \
|
||||
: (*(exp) = (ptr)->_val, false)))
|
||||
|
||||
|
||||
@@ -273,7 +326,9 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem1, mem2) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val)
|
||||
|
||||
/* TODO: Missing atomic_flag. Problem: it needs to be lock free! */
|
||||
/* TODO: Missing atomic_flag. Problem: it is supposed to be lock free! */
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
|
||||