Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8902a752f5 | ||
|
|
3445da13f3 | ||
|
|
127530abaa | ||
|
|
ed0f538fb7 | ||
|
|
76ef061dec | ||
|
|
c98786a3b3 | ||
|
|
422f3c2c04 | ||
|
|
5ceb34d980 | ||
|
|
73e3d1d1bd | ||
|
|
044a085fb6 | ||
|
|
5344423ad9 | ||
|
|
76ea989865 | ||
|
|
29c4ba3dcc | ||
|
|
42184f69db | ||
|
|
fb8bf65233 | ||
|
|
1d86e51f4a | ||
|
|
53c35a22d7 | ||
|
|
722737d60c | ||
|
|
f951a947ec | ||
|
|
d9401371a6 | ||
|
|
690fd72c8b | ||
|
|
d318493c6c | ||
|
|
fecece19cb | ||
|
|
ea640482a7 | ||
|
|
3e558af559 | ||
|
|
91a602f774 | ||
|
|
6a5c136c72 | ||
|
|
e50fdc82ef | ||
|
|
ec0a082701 | ||
|
|
7bf3ea3a87 | ||
|
|
15492394ad | ||
|
|
09f40b5695 | ||
|
|
eabfcd1d49 | ||
|
|
00aeafc616 | ||
|
|
f512051807 | ||
|
|
4e8b929da9 | ||
|
|
5841f936e6 | ||
|
|
2ee40339b0 | ||
|
|
0c8eca893d | ||
|
|
b16048a55b | ||
|
|
9dc582c6bc | ||
|
|
1df8bf84fb | ||
|
|
e017a90e5c | ||
|
|
58b317b759 | ||
|
|
3a057fc319 | ||
|
|
703ab6ff9c | ||
|
|
f7f5db61d3 | ||
|
|
32b00eb433 | ||
|
|
796f2619e5 | ||
|
|
268192138a | ||
|
|
0671a2ea41 | ||
|
|
07dce84e51 | ||
|
|
5f4303624f | ||
|
|
19e61467d5 | ||
|
|
1454bcebe4 | ||
|
|
d48f2ff84d | ||
|
|
269636b4d8 | ||
|
|
bf68340106 | ||
|
|
5dba526e29 | ||
|
|
469239adcd | ||
|
|
589abda0c2 | ||
|
|
8f141896ba | ||
|
|
a0cbec4329 | ||
|
|
df66db562d | ||
|
|
1829a70601 | ||
|
|
e9b25f2414 | ||
|
|
c9bb739f24 | ||
|
|
e049b83a9e | ||
|
|
31ac3999a1 | ||
|
|
a0818419ab | ||
|
|
496f885a84 | ||
|
|
d5d9a4bd5c | ||
|
|
ca9571a110 | ||
|
|
4497214b9c | ||
|
|
ccb1658afd | ||
|
|
eaf2783f1a | ||
|
|
5705819814 | ||
|
|
91f5f513c4 | ||
|
|
3dec4e2cbe | ||
|
|
e70766beaa | ||
|
|
d7639f0ae0 | ||
|
|
c63ce84e45 | ||
|
|
a043c379c0 | ||
|
|
92bb380117 | ||
|
|
6bb7a184db | ||
|
|
fa9163be9d | ||
|
|
0bade1563c | ||
|
|
1278d2f8a0 | ||
|
|
53af2aae68 | ||
|
|
17ded6fcc8 | ||
|
|
19ce371533 | ||
|
|
0bd1bcb68e | ||
|
|
b50813713a | ||
|
|
2628536d20 | ||
|
|
ecfa4a9152 | ||
|
|
dafe4bcec5 | ||
|
|
8544a7f289 | ||
|
|
aa18915d61 | ||
|
|
df4bc0a56c | ||
|
|
b6046e5e23 | ||
|
|
b487bfe5ad | ||
|
|
408272c810 | ||
|
|
6a9ee17eca | ||
|
|
05c5a94634 | ||
|
|
b1b0927e9f | ||
|
|
37770365a1 | ||
|
|
82bdcc685a | ||
|
|
26fa733f70 | ||
|
|
cd2fc05573 | ||
|
|
33430d4359 | ||
|
|
dc95b49f05 | ||
|
|
3ec24cfa40 | ||
|
|
12b099dcf8 | ||
|
|
b885d6136c | ||
|
|
b51c4bea2b | ||
|
|
302c5eb300 | ||
|
|
6d2900a2bd | ||
|
|
573e09c56e | ||
|
|
0a39a17d36 | ||
|
|
a913d0947c | ||
|
|
abbd8ad6ce | ||
|
|
a09c9fe1c3 | ||
|
|
219c62ff5d | ||
|
|
272a326375 | ||
|
|
eca79f2c80 | ||
|
|
2feda4059f | ||
|
|
de0ef67cf2 | ||
|
|
95762a058c | ||
|
|
acd8671017 | ||
|
|
a6c1688f23 | ||
|
|
f6ed549ce5 | ||
|
|
8639fdbd98 | ||
|
|
693b09387f | ||
|
|
4052d3794b | ||
|
|
044e9c3bf7 | ||
|
|
45a2a1afb2 | ||
|
|
b44e4e09dd | ||
|
|
5158059ec4 | ||
|
|
7279011f0a | ||
|
|
79369e9b05 | ||
|
|
58a7a7c214 | ||
|
|
e3e94ca238 | ||
|
|
ae81271b2a | ||
|
|
d9c3724cff | ||
|
|
1ff9848384 | ||
|
|
83e7f2a641 | ||
|
|
6580601969 | ||
|
|
ad023bb09d | ||
|
|
b5df21f9c5 | ||
|
|
d2dccbf514 | ||
|
|
a8075cbb05 | ||
|
|
1322afc4c9 | ||
|
|
0f885fb158 | ||
|
|
25a2eb0875 | ||
|
|
6bcd51f10f | ||
|
|
9c1cb9c835 | ||
|
|
19cb329ae6 | ||
|
|
8099e6a94f | ||
|
|
ce6cc080d6 | ||
|
|
a27b0b4014 | ||
|
|
e74f80cc59 | ||
|
|
bafd307247 | ||
|
|
6bed3ac697 | ||
|
|
b8a9073fc9 | ||
|
|
da3e71c676 | ||
|
|
4ea83e129e | ||
|
|
fc34fa80b5 | ||
|
|
4f608ec266 | ||
|
|
ccaa54d2a5 | ||
|
|
095bf7070d | ||
|
|
676b12d5d2 | ||
|
|
f858aa2cb5 | ||
|
|
9d77448a25 | ||
|
|
8babc33b91 | ||
|
|
352d7cf725 | ||
|
|
a6993ab758 | ||
|
|
48260ac2a6 | ||
|
|
e4afb024b9 | ||
|
|
63008af30f | ||
|
|
1828aca65e | ||
|
|
9354e9717d | ||
|
|
100c0f22fe | ||
|
|
ff778528f8 | ||
|
|
8f1a1df617 | ||
|
|
28faf815d7 | ||
|
|
fe3b703d0a | ||
|
|
0aa6a9f0cf | ||
|
|
67832ac918 | ||
|
|
669a3297c7 | ||
|
|
25d4829d7b | ||
|
|
ebab05a789 | ||
|
|
727df5b7bf | ||
|
|
aebe1308fc | ||
|
|
1d163a396e | ||
|
|
7534aa0d61 | ||
|
|
6976d4e23d | ||
|
|
6b7954e141 | ||
|
|
c27d76a83b | ||
|
|
0e3081bfc6 | ||
|
|
d754e9a15f | ||
|
|
4e4e21793c | ||
|
|
c515da9f37 | ||
|
|
961b93bd4c | ||
|
|
39a719c3f0 | ||
|
|
8b643b4878 | ||
|
|
876c394fba | ||
|
|
81439c9437 | ||
|
|
191ef7d09e | ||
|
|
bd4131dd8f | ||
|
|
cfe8293c64 | ||
|
|
ea2715aa75 | ||
|
|
f69cec6820 | ||
|
|
085f371693 | ||
|
|
16a0a5c1a3 | ||
|
|
3953f81884 | ||
|
|
8365888e6e | ||
|
|
c3f6e3c5f0 | ||
|
|
4cafe4dce1 | ||
|
|
9f8b97ae46 | ||
|
|
030bea9c11 | ||
|
|
e33894f1b3 | ||
|
|
66f5e6c67d | ||
|
|
78c6dce068 | ||
|
|
0798480ad5 | ||
|
|
e8322215fd | ||
|
|
42d3042c15 | ||
|
|
b7214ad11d | ||
|
|
08b4bc9052 | ||
|
|
d813171e8a | ||
|
|
d1094999f5 | ||
|
|
c8354aa6ed | ||
|
|
ab3aa33fac | ||
|
|
01f2f376e2 | ||
|
|
535e00366a | ||
|
|
42111ec22a | ||
|
|
ef0e849616 | ||
|
|
9c516c2055 | ||
|
|
db48b985c3 | ||
|
|
888796ca06 | ||
|
|
144ae9c5ed | ||
|
|
6223c93b53 | ||
|
|
30f7656822 | ||
|
|
8209a0c32a | ||
|
|
92e6957320 | ||
|
|
b3c9f6ee47 | ||
|
|
ab8bbad3f4 | ||
|
|
9047376b7f | ||
|
|
dfed8dbc50 | ||
|
|
2d3c25cd85 | ||
|
|
bfa948dc7a | ||
|
|
94b6d1b9fd | ||
|
|
0ddd5ddc6d | ||
|
|
cba93d5bb4 | ||
|
|
d02de75487 | ||
|
|
2f57766249 | ||
|
|
3ff01e37eb | ||
|
|
5683df0f22 | ||
|
|
11dc7afc06 | ||
|
|
9e2ae3f101 | ||
|
|
c35aa9c891 | ||
|
|
2fc31d8c12 | ||
|
|
4f8d0a7156 | ||
|
|
aaf5bbd6a0 | ||
|
|
2f76652f2b | ||
|
|
942cf32519 | ||
|
|
c1c9cb9cd3 | ||
|
|
76bfb48685 | ||
|
|
afff412f7a | ||
|
|
e48dcdeecc | ||
|
|
12fae5c36c | ||
|
|
3f9129c7ed | ||
|
|
b918f61f4f | ||
|
|
93b69d0f8b | ||
|
|
b3440a2edd | ||
|
|
4140df5bfc | ||
|
|
fbab093d52 | ||
|
|
f57a0e0bf8 | ||
|
|
925c06beb8 | ||
|
|
8e2f67b794 | ||
|
|
f176d01e49 | ||
|
|
2b99bbe956 | ||
|
|
700bfc5341 | ||
|
|
4062525821 | ||
|
|
800a1e5c36 | ||
|
|
1838f675a7 | ||
|
|
bf6c1341b3 | ||
|
|
55b745b916 | ||
|
|
5cb0d9214b | ||
|
|
8f99b8e617 | ||
|
|
d2ce71a90a | ||
|
|
8562986eea | ||
|
|
ee89858bf0 | ||
|
|
085d7157c0 | ||
|
|
91f3174a36 | ||
|
|
56f51c59af | ||
|
|
df0c95ca46 | ||
|
|
482ec38e62 | ||
|
|
82743ca72c | ||
|
|
312821454c | ||
|
|
c953e87660 | ||
|
|
8846707c8b | ||
|
|
bf7d4eee55 | ||
|
|
d4dc85f89a | ||
|
|
130c32e7d4 | ||
|
|
2bcaba3bc0 | ||
|
|
443c805c22 | ||
|
|
414c87bb69 | ||
|
|
e9ca506d93 | ||
|
|
8e58f7d637 | ||
|
|
254beaf3c7 | ||
|
|
27735eb224 | ||
|
|
0afc81bd54 | ||
|
|
39e67eebdc | ||
|
|
840226c7fd | ||
|
|
e421851525 | ||
|
|
f70b52c9e4 | ||
|
|
40249ce5bc | ||
|
|
97ff413f01 | ||
|
|
8e4ac99a35 | ||
|
|
4366e8eeab | ||
|
|
4e5e498bb2 | ||
|
|
870a6f4b57 | ||
|
|
a2ae209992 | ||
|
|
43fdd10e77 | ||
|
|
b1183de0f8 | ||
|
|
3a3ef7454c | ||
|
|
5f946b728b | ||
|
|
9cc03ff81b | ||
|
|
89d4db174e | ||
|
|
f5bbc0a7fb | ||
|
|
9da0d1d94b | ||
|
|
fafaaafdbf | ||
|
|
38f4107b19 | ||
|
|
cbefdab4bb | ||
|
|
bcd0c46e8b | ||
|
|
f25bb73e58 | ||
|
|
ea3584e048 | ||
|
|
85473610a4 | ||
|
|
f9f0b307fc | ||
|
|
d17fa4530b | ||
|
|
3806495e2d | ||
|
|
15f58d5738 | ||
|
|
4de7da1c05 | ||
|
|
93229c61f2 | ||
|
|
3f0e8956b8 | ||
|
|
b82670b643 | ||
|
|
64800dbd3f | ||
|
|
2d9d9fbd9f | ||
|
|
f0ba5d17f4 | ||
|
|
e51c988222 | ||
|
|
0be3900beb | ||
|
|
f60ce0320a | ||
|
|
77008b8622 | ||
|
|
a7617002c5 | ||
|
|
bc73616bde | ||
|
|
d6b9b054c2 | ||
|
|
9eed4be97c | ||
|
|
2519927178 | ||
|
|
0fec33b38e | ||
|
|
dc2b6d2b2d | ||
|
|
bc63edc595 | ||
|
|
6241a3093c | ||
|
|
fb53a464d7 | ||
|
|
aba26b75a2 | ||
|
|
775ec6f91b | ||
|
|
95bc7063a0 | ||
|
|
731d3ecf1a | ||
|
|
0d1817e7ca | ||
|
|
1a5b428bfb | ||
|
|
bd49e31f3b | ||
|
|
2dba83e3c5 | ||
|
|
75e9766da9 | ||
|
|
d2f8aa1c0d | ||
|
|
4aa4b7693f | ||
|
|
d50b450927 | ||
|
|
5674cdbfc5 | ||
|
|
3641829198 | ||
|
|
10a759b09e | ||
|
|
b5a3b36c1b | ||
|
|
b0c3839f2b | ||
|
|
3aa3e95e4c | ||
|
|
87f1e53e13 | ||
|
|
d7b45cc220 | ||
|
|
d8142a9764 | ||
|
|
8780f58739 | ||
|
|
e352104df8 | ||
|
|
cbb2b452bb | ||
|
|
6e947c6262 | ||
|
|
18f04da4ec | ||
|
|
3dad6ef65c | ||
|
|
41c4f5fe5c | ||
|
|
cfeedf19f8 | ||
|
|
2ab410bd6a | ||
|
|
aefbc5b2f5 | ||
|
|
abec9c37fa | ||
|
|
442b0e7cea | ||
|
|
0b853c6d52 | ||
|
|
cc7fc66899 | ||
|
|
6b994c2928 | ||
|
|
e6fe36d3cd | ||
|
|
f45ededf8b | ||
|
|
ed27bedcb4 | ||
|
|
eb1a7a0435 | ||
|
|
de00fdc5f7 | ||
|
|
8febe12c5c | ||
|
|
1368b201eb | ||
|
|
4ca166b0b9 | ||
|
|
c13533cf21 | ||
|
|
9fdf0f76e7 | ||
|
|
308f513edc | ||
|
|
900bcc3819 | ||
|
|
b6e0994dfc | ||
|
|
121339d948 | ||
|
|
c5bb84013a | ||
|
|
65b49268d3 | ||
|
|
ecebd62f86 | ||
|
|
6a8c9a703d | ||
|
|
ad05ae9aa5 | ||
|
|
abffe201e5 | ||
|
|
ee2bc27bda | ||
|
|
14b94865b7 | ||
|
|
6e1ceafcc2 | ||
|
|
58746560e9 | ||
|
|
082adca3e6 | ||
|
|
ee1dc2a8e8 | ||
|
|
92e2d835bd | ||
|
|
22aba04b47 | ||
|
|
399c615915 | ||
|
|
cbdba0941a | ||
|
|
90c54a48d0 | ||
|
|
22b18830f7 | ||
|
|
dab085e3a7 | ||
|
|
66fac10a98 | ||
|
|
e5fb5ddde1 | ||
|
|
dcf20fbbd6 | ||
|
|
5d659877fe | ||
|
|
a30dd69aaa | ||
|
|
b1f698bb7b | ||
|
|
2323420a87 | ||
|
|
7e120a3615 | ||
|
|
804db294ca | ||
|
|
d12aa6c263 | ||
|
|
d59e87d2bf | ||
|
|
8f3c0af548 | ||
|
|
1f3013c445 | ||
|
|
f13e99ab1a | ||
|
|
fb8ad84675 | ||
|
|
12608afe10 | ||
|
|
f97e92b4cb | ||
|
|
a74e26e3de | ||
|
|
a30b783692 | ||
|
|
e64a6a22e7 | ||
|
|
76892afa13 | ||
|
|
dcb1eb0d94 | ||
|
|
950ea224ff | ||
|
|
b22a844007 | ||
|
|
502756c731 | ||
|
|
e38dc19ea1 | ||
|
|
2bebb2b4a1 | ||
|
|
5b7be93c1a | ||
|
|
d04270ae3f | ||
|
|
1bef7c1977 | ||
|
|
ae037ff7af | ||
|
|
a4267d60df | ||
|
|
47e32ab2b3 | ||
|
|
5ac08e42d8 | ||
|
|
9c59684b61 | ||
|
|
f26e1e5a12 | ||
|
|
1cde4633e6 | ||
|
|
1393f8e9aa | ||
|
|
bfffa1d245 | ||
|
|
3a6b568ccc | ||
|
|
453a920af8 | ||
|
|
1fd86ffc2e | ||
|
|
96a0639a8a | ||
|
|
c12d0a3f23 | ||
|
|
cac8790405 | ||
|
|
ccd9726e01 | ||
|
|
5516b50b3a | ||
|
|
b5a3e010d8 | ||
|
|
2d7d267252 | ||
|
|
bd5d7aaada | ||
|
|
18b6be8e00 | ||
|
|
958abfef93 | ||
|
|
198be1062b | ||
|
|
0cfee02641 | ||
|
|
48dc38508a | ||
|
|
e763204bf7 | ||
|
|
370baf56ab | ||
|
|
4fd6bcbf99 | ||
|
|
59d1e23dea | ||
|
|
cb173f2f81 | ||
|
|
d047174c2f | ||
|
|
df25159d03 | ||
|
|
99618a687e | ||
|
|
a1b226e185 | ||
|
|
e93df4332a | ||
|
|
5a1f768b03 | ||
|
|
e854bc8fc9 | ||
|
|
9ab958708d | ||
|
|
85ea92d83b | ||
|
|
22a406ac51 | ||
|
|
58eed79413 | ||
|
|
e83dea8212 | ||
|
|
c829827f48 | ||
|
|
b47cf05a59 | ||
|
|
22a93514ff | ||
|
|
154865f0f1 | ||
|
|
71151770fd | ||
|
|
72623ce13e | ||
|
|
94f20d56e9 | ||
|
|
9e8ad9bfd9 | ||
|
|
e51a5be776 | ||
|
|
7d647340c6 | ||
|
|
c6ea3c0616 | ||
|
|
9ab90be6d4 | ||
|
|
10440320d1 | ||
|
|
fc7e93403a | ||
|
|
b0c4418584 | ||
|
|
5f73eb7788 | ||
|
|
a554312573 | ||
|
|
8a1fd391d1 | ||
|
|
95b104ee48 | ||
|
|
c3df69d011 | ||
|
|
73468a3e24 | ||
|
|
f254f98e42 | ||
|
|
d37076dd37 | ||
|
|
5ef9376148 | ||
|
|
d8abda7583 | ||
|
|
892c755389 | ||
|
|
aba2f90c9d | ||
|
|
dc487c7e64 | ||
|
|
18b1bd9518 | ||
|
|
845ab1fef0 | ||
|
|
94bfac3f75 | ||
|
|
bd5c9ce2a7 | ||
|
|
f5934a6274 | ||
|
|
c6f71fddc7 | ||
|
|
74764e2d6f | ||
|
|
9b00a8c54e | ||
|
|
66735e99c3 | ||
|
|
80acbb4343 | ||
|
|
2fb912d43d | ||
|
|
8c8dc6de7c | ||
|
|
677acdd14e | ||
|
|
6caeea98b9 | ||
|
|
c5d37ce028 | ||
|
|
112b405df6 | ||
|
|
47385d58e5 | ||
|
|
c8275c8f63 | ||
|
|
0c1e888a78 | ||
|
|
6a1ff3e080 | ||
|
|
6d41eba5ed | ||
|
|
c0abcc6d60 | ||
|
|
da71c81195 | ||
|
|
8e0d17e85c | ||
|
|
6d98c273c1 | ||
|
|
85f6ff34aa | ||
|
|
759c24be63 | ||
|
|
d85955ef60 | ||
|
|
3a53044198 | ||
|
|
4d5cd9c635 | ||
|
|
57b88160ae | ||
|
|
33ba602aef | ||
|
|
3632388315 | ||
|
|
6ee82e885b | ||
|
|
2f92cee416 | ||
|
|
9269473e10 | ||
|
|
c8611ce708 | ||
|
|
d8fd43e9e9 | ||
|
|
a2e471620d | ||
|
|
ffa3821acf | ||
|
|
5c98d47d8c | ||
|
|
0875eaac03 | ||
|
|
60734bdb2b | ||
|
|
e71b19424b | ||
|
|
daac0169d5 | ||
|
|
baacc0df52 | ||
|
|
c6921536f7 | ||
|
|
4abf0ad2b2 | ||
|
|
379d555d35 | ||
|
|
8c01acb8d2 | ||
|
|
2c2c3c21ba | ||
|
|
50fd27e07b | ||
|
|
3309035814 | ||
|
|
b691758fa9 | ||
|
|
7c9afcec8b | ||
|
|
06ac05526a | ||
|
|
69cef8249a | ||
|
|
473df16a5a | ||
|
|
e1abf0528c | ||
|
|
ef0b335f67 | ||
|
|
1a866a3dc4 | ||
|
|
ed437b9e05 | ||
|
|
eea85872fd | ||
|
|
9d33e4cd5a | ||
|
|
530cc8d2a2 | ||
|
|
9baca84825 | ||
|
|
58538e4822 | ||
|
|
e31a8dc407 | ||
|
|
7875263092 | ||
|
|
de3b8509bf | ||
|
|
a19e1acfff | ||
|
|
e613b5c624 | ||
|
|
ccfddb0685 | ||
|
|
b8cd679679 | ||
|
|
fc26e472ab | ||
|
|
fc8c7349d6 | ||
|
|
a4d9b8df17 | ||
|
|
f26da68aa4 | ||
|
|
144182b540 | ||
|
|
a834ca4921 | ||
|
|
d1fc216836 | ||
|
|
5e57338928 | ||
|
|
f3376b6f0e | ||
|
|
5e001fdd9d | ||
|
|
9fda06276c | ||
|
|
df79c306d9 | ||
|
|
e4955e6851 | ||
|
|
0fec9e7ac4 | ||
|
|
5be8bb435b | ||
|
|
35b915ab10 | ||
|
|
80c57e996d | ||
|
|
511293d580 | ||
|
|
fe2b816447 | ||
|
|
093b7dc1e8 | ||
|
|
811fa57cbc | ||
|
|
359ad20a6a | ||
|
|
ac9989e4ff | ||
|
|
7268551737 | ||
|
|
823b1974bb | ||
|
|
382f636206 | ||
|
|
9a1b4abcf9 | ||
|
|
a0fc57687b | ||
|
|
02897f982f | ||
|
|
07a5d0ed0a | ||
|
|
017995ade6 | ||
|
|
9711b2280c | ||
|
|
619331916f | ||
|
|
d7909f7312 | ||
|
|
22674f2b46 | ||
|
|
845736c489 | ||
|
|
501f9db465 | ||
|
|
8dd440a582 | ||
|
|
dd7f090b4b | ||
|
|
dc14a2677b | ||
|
|
8b1ed7f0ae | ||
|
|
19b01b404d | ||
|
|
ec780d2d4d | ||
|
|
07790f6711 | ||
|
|
f72d2b6c67 | ||
|
|
e35d631012 | ||
|
|
3499a08207 | ||
|
|
0ac23e512e | ||
|
|
1852fabcd2 | ||
|
|
7b6bfac7cb | ||
|
|
e72aa5fb79 | ||
|
|
f4b02b92cc | ||
|
|
39edcc560f | ||
|
|
50669a320c | ||
|
|
d22c0b05ef | ||
|
|
689be30803 | ||
|
|
b393a83d38 | ||
|
|
1a1339da6b | ||
|
|
9926b51da0 | ||
|
|
761447dea3 | ||
|
|
829c20ba8a | ||
|
|
9ac734e191 | ||
|
|
5420fc6c51 |
No files matched your search
@@ -10,7 +10,9 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: CPU Information
|
||||
run: lscpu || sysctl -a|grep cpu || echo "CPU information not available"
|
||||
- name: make check C99
|
||||
run: make clean && make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11
|
||||
@@ -24,11 +26,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: update package list
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
run: sudo apt-get install gcc-multilib g++-multilib
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- name: make check C99 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
@@ -46,7 +50,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- name: Clone TCC
|
||||
shell: bash
|
||||
run: git clone https://repo.or.cz/tinycc.git
|
||||
@@ -58,13 +64,22 @@ jobs:
|
||||
run: make depend
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check -j4 || make CC="/tmp/tcc/bin/tcc -std=c99" check -j2 || make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_linux_sanitize:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make sanitize
|
||||
working-directory: ./tests
|
||||
run: make sanitize -j 2
|
||||
|
||||
build_windows_mingw:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: mingw32-make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
@@ -75,7 +90,7 @@ jobs:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
@@ -88,7 +103,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
@@ -98,9 +113,44 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: make check
|
||||
shell: cmd
|
||||
working-directory: ./tests
|
||||
run: Make-check-cl.bat clang-cl
|
||||
|
||||
# The host should always be linux
|
||||
build_freebsd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
timeout-minutes: 60
|
||||
with:
|
||||
usesh: true
|
||||
run: |
|
||||
freebsd-version
|
||||
cd tests
|
||||
make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror" && make clean && make check -j 2 CC="cc -std=c11 -Wno-unknown-warning-option -Werror" LDFLAGS="-lstdthreads" && make clean
|
||||
|
||||
# The host should always be linux
|
||||
build_aarch64:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build on aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2.5.0
|
||||
name: Run commands on aarch64
|
||||
id: make
|
||||
timeout-minutes: 60
|
||||
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
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
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.
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
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.
|
||||
@@ -50,4 +50,4 @@ jobs:
|
||||
run: make exe
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
@@ -38,8 +38,13 @@ depend
|
||||
other/
|
||||
a*.dat
|
||||
config
|
||||
config.*
|
||||
*.log
|
||||
.vscode
|
||||
.vs
|
||||
tmp-serial.*
|
||||
*~
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
*.synt
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2021, Patrick Pelissier
|
||||
Copyright (c) 2017-2023, Patrick Pelissier
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2023, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,14 +34,14 @@ DESTDIR=
|
||||
|
||||
# Package name & version.
|
||||
PACKAGE=m_lib-$(VERSION)
|
||||
VERSION=0.6.0
|
||||
VERSION=0.7.2
|
||||
|
||||
# Define the contain of the distribution tarball
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
|
||||
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-generic.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/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp
|
||||
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh
|
||||
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c
|
||||
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 tests/test-mtry.c tests/tgen-mmap.c tests/tgen-try.c tests/tgen-tuple.c tests/test-mgeneric.c
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
@@ -68,8 +68,8 @@ 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2023, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,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-emilib bench-hopscotchmap bench-mlib-thread bench-liblfds bench-concurrentqueue bench-boost bench-mempool bench-string bench-plain bench-rigtorp-mpmc-queue bench-cmc
|
||||
.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
|
||||
|
||||
@@ -39,7 +39,7 @@ pgo:
|
||||
|
||||
#########################################################################
|
||||
|
||||
container: bench-mlib bench-mlib-mempool bench-stl bench-qt bench-glib bench-klib bench-libdynamic bench-cmc bench-sparsepp bench-densehashmap bench-collectionc bench-tommyds bench-flathashmap bench-emilib bench-hopscotchmap bench-uthash bench-qlibc bench-libsrt bench-nedtries bench-rigtorp-hashmap bench-ctl
|
||||
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 bench-rigtorp-mpmc-queue
|
||||
@@ -118,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
|
||||
@@ -162,12 +162,12 @@ bench-cmc0:
|
||||
@./bench-cmc.exe 30
|
||||
@./bench-cmc.exe 40
|
||||
|
||||
# LIBDYNAMIC shall point to the the directory containing the file libdynamic.pc
|
||||
# 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
|
||||
@@ -239,6 +239,17 @@ bench-emilib0:
|
||||
@./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
|
||||
@@ -276,7 +287,7 @@ 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}/include/libsrt" bench-libsrt.c common.c -o bench-libsrt.exe $${LIBSRT}/lib/libsrt.a
|
||||
$(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 50
|
||||
|
||||
@@ -311,8 +322,11 @@ bench-xxhash0:
|
||||
bench-boost:
|
||||
@if test -n "$${BOOST}" ; then $(MAKE) bench-boost0 ; else echo "Nothing to be done for BOOST." ; fi
|
||||
bench-boost0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -DMULTI_THREAD_MEASURE -o bench-boost.exe -lpthread
|
||||
@./bench-boost.exe 60
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -DMULTI_THREAD_MEASURE -o bench-boost-thread.exe -lpthread
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${BOOST}" bench-boost.cpp common.c -o bench-boost.exe -lpthread
|
||||
@./bench-boost.exe 42
|
||||
@./bench-boost.exe 41
|
||||
@./bench-boost-thread.exe 60
|
||||
|
||||
# NEDTRIES shall point to the header location.
|
||||
bench-nedtries:
|
||||
@@ -351,6 +365,52 @@ bench-ctl0:
|
||||
@./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
|
||||
|
||||
# VERSTABLE shall point to the source directory of VERSTABLE (where the headers are)
|
||||
bench-verstable:
|
||||
@if test -n "$${VERSTABLE}" ; then $(MAKE) bench-verstable0 ; else echo "Nothing to be done for VERSTABLE." ; fi
|
||||
|
||||
bench-verstable0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${VERSTABLE}/ bench-verstable.c common.c -o bench-verstable.exe
|
||||
@./bench-verstable.exe 40
|
||||
@./bench-verstable.exe 41
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
@@ -389,12 +449,12 @@ bench-maxdict:
|
||||
############################################################################
|
||||
|
||||
# BSTRLIB shall point to the BSTRLIB sources
|
||||
# LIBSRT shall point to the LIBSRT install directory
|
||||
# LIBSRT shall point to the LIBSRT sources
|
||||
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}/include/libsrt $${LIBSRT}/lib/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:
|
||||
@@ -404,6 +464,9 @@ 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
|
||||
@@ -411,6 +474,7 @@ bench-string-step5:
|
||||
@./bench-string-2.exe 2000000 1
|
||||
@./bench-string-2.exe 2000000 2
|
||||
@./bench-string-2.exe 2000000 4
|
||||
@./bench-string-2.exe 2000000 5
|
||||
|
||||
bench-string-pgo:
|
||||
$(MAKE) bench-string XCFLAGS="-fprofile-generate=pgo"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -3,11 +3,111 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "m-thread.h"
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
boost::unordered_flat_map<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
boost::unordered_flat_map<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
boost::unordered_flat_map<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
boost::unordered_flat_map<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
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; }
|
||||
};
|
||||
|
||||
inline std::size_t hash_value(const char_array_s &k) {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
boost::unordered_flat_map<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
boost::unordered_flat_map<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
boost::unordered_flat_map<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
boost::unordered_flat_map<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
boost::lockfree::queue<unsigned int, boost::lockfree::capacity<4*64>> g_buff;
|
||||
boost::lockfree::queue<unsigned long long, boost::lockfree::capacity<4*64>> g_final;
|
||||
@@ -86,11 +186,15 @@ static void test_queue(size_t n)
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42, "dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0},
|
||||
{ 60, "Queue MPMC", 1000000, 0, test_queue, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("BOOST-LOCKFREE", numberof(table), table, argc, argv);
|
||||
test("BOOST", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
@@ -125,14 +125,15 @@ pair_ulong_copy(pair_ulong *self) {
|
||||
#define T pair_ulong
|
||||
#include <ctl/unordered_map.h>
|
||||
|
||||
// It seems broken: it doesn't output the expected result.
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
umap_pair_ulong dict = umap_pair_ulong_init(pair_ulong_hash, pair_ulong_equal);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_insert(&dict, (pair_ulong) { rand_get(), rand_get() });
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
#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"
|
||||
@@ -55,12 +55,8 @@ static void test_deque(size_t n)
|
||||
}
|
||||
unsigned int s = 0;
|
||||
deque_uint_it_t it1, it2;
|
||||
deque_uint_it(it1, a1);
|
||||
deque_uint_it(it2, a2);
|
||||
while (!deque_uint_end_p(it1)) {
|
||||
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 );
|
||||
deque_uint_next(it1);
|
||||
deque_uint_next(it2);
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
@@ -876,8 +872,8 @@ bench_vector_string_init(size_t n)
|
||||
{
|
||||
vector_string_init(vstring);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
M_LET( (s, "%zu", i, i, i, i), string_t) {
|
||||
{
|
||||
M_LET( (s, "%zu", i), string_t) {
|
||||
vector_string_push_back(vstring, s);
|
||||
}
|
||||
}
|
||||
@@ -901,8 +897,8 @@ static void
|
||||
bench_vector_string_bin_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
@@ -920,8 +916,8 @@ bench_vector_string_bin_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -929,8 +925,8 @@ static void
|
||||
bench_vector_string_json_run(size_t n)
|
||||
{
|
||||
if (vector_string_size(vstring) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring));
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
@@ -948,8 +944,8 @@ bench_vector_string_json_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_string_size(vstring2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different (%zu vs %zu)!\n", n, vector_string_size(vstring2));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -957,8 +953,8 @@ static void
|
||||
bench_vector_string_clear(void)
|
||||
{
|
||||
if (!vector_string_equal_p(vstring, vstring2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
|
||||
abort();
|
||||
}
|
||||
vector_string_clear(vstring);
|
||||
vector_string_clear(vstring2);
|
||||
@@ -986,8 +982,8 @@ static void
|
||||
bench_vector_ulong_bin_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.dat", "wb");
|
||||
@@ -1005,8 +1001,8 @@ bench_vector_ulong_bin_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,8 +1010,8 @@ static void
|
||||
bench_vector_ulong_json_run(size_t n)
|
||||
{
|
||||
if (vector_ulong_size(vulong) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
FILE *f = fopen("tmp-serial.json", "wt");
|
||||
@@ -1033,8 +1029,8 @@ bench_vector_ulong_json_run(size_t n)
|
||||
fclose(f);
|
||||
|
||||
if (vector_ulong_size(vulong2) != n) {
|
||||
printf("Size are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Size are different!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,8 +1038,8 @@ static void
|
||||
bench_vector_ulong_clear(void)
|
||||
{
|
||||
if (!vector_ulong_equal_p(vulong, vulong2)) {
|
||||
printf("Array are different!\n");
|
||||
abort();
|
||||
fprintf(stderr, "ERROR: Array are different after deserialization!\n");
|
||||
abort();
|
||||
}
|
||||
vector_ulong_clear(vulong);
|
||||
vector_ulong_clear(vulong2);
|
||||
@@ -1085,6 +1081,6 @@ const config_func_t table[] = {
|
||||
|
||||
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,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,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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"
|
||||
@@ -43,6 +46,10 @@ extern "C" {
|
||||
#include "bstraux.h"
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
#include "pottery/string/string.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* BENCH
|
||||
* 2000000
|
||||
@@ -104,27 +111,28 @@ size_t bench_stl(unsigned n)
|
||||
|
||||
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
|
||||
string_replace_all_str(str, "1234", "WELL");
|
||||
string_replace_all_str(str, "56789", "DONE");
|
||||
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;
|
||||
@@ -217,6 +225,57 @@ size_t bench_sds(unsigned n)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
|
||||
size_t pottery_find_cstr(string_t *b, size_t index, const char *pattern)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
void pottery_replace_all_str(string_t *str, const char *s, const char *d)
|
||||
{
|
||||
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++) {
|
||||
string_init(&tab[i]);
|
||||
string_append_format(&tab[i], "%u", rand_get());
|
||||
}
|
||||
// P2
|
||||
string_t str;
|
||||
string_init(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_append_string(&str, &tab[permutation_tab[i]]);
|
||||
}
|
||||
// P3
|
||||
|
||||
pottery_replace_all_str(&str, "1234", "WELL");
|
||||
pottery_replace_all_str(&str, "56789", "DONE");
|
||||
size_t length = string_length(&str);
|
||||
|
||||
// Clean
|
||||
string_clear(&str);
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
string_clear(&tab[i]);
|
||||
}
|
||||
free(tab);
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
@@ -247,6 +306,12 @@ int main(int argc, const char *argv[])
|
||||
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);
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Update of integrating M*LIB, LIBSRT, SDS & GLIB
|
||||
Copyright (c) 2018-2021 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
|
||||
@@ -83,6 +85,10 @@ extern "C" {
|
||||
#include "gmodule.h"
|
||||
#endif
|
||||
|
||||
#if defined(BENCH_CAN_USE_POTTERY)
|
||||
#include "pottery/string/string.h"
|
||||
#endif
|
||||
|
||||
/* Time of a test */
|
||||
#define TEST_SECONDS (5)
|
||||
|
||||
@@ -433,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;
|
||||
}
|
||||
@@ -445,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;
|
||||
}
|
||||
@@ -457,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
|
||||
@@ -774,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 {
|
||||
@@ -999,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-core.h"
|
||||
#include "common.h"
|
||||
|
||||
#define NAME umap_ulong
|
||||
#define KEY_TY unsigned long
|
||||
#define VAL_TY unsigned long
|
||||
#include "verstable.h"
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
umap_ulong dict;
|
||||
umap_ulong_init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
umap_ulong_insert(&dict, key, value);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_ulong_itr it = umap_ulong_get(&dict, rand_get());
|
||||
if (!umap_ulong_is_end(it) )
|
||||
s += it.data->val;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
umap_ulong_cleanup(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#ifndef CHAR_ARRAY_SIZE
|
||||
#define CHAR_ARRAY_SIZE 256
|
||||
#endif
|
||||
typedef char char_array_t[CHAR_ARRAY_SIZE];
|
||||
typedef struct { char_array_t a; } char_encap;// Cannot use char_array_t directly
|
||||
static bool char_equal_p (const char_encap a, const char_encap b) { return strcmp(a.a,b.a)==0; }
|
||||
static size_t char_hash(const char_encap a) { return m_core_hash (a.a, strlen(a.a)); }
|
||||
|
||||
#define NAME umap_char_array
|
||||
#define KEY_TY char_encap
|
||||
#define VAL_TY char_encap
|
||||
#define HASH_FN char_hash
|
||||
#define CMPR_FN char_equal_p
|
||||
#include "verstable.h"
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
umap_char_array dict;
|
||||
umap_char_array_init(&dict);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_encap s1, s2;
|
||||
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
umap_char_array_insert(&dict, s1, s2);
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_encap s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
umap_char_array_itr it = umap_char_array_get(&dict, s1);
|
||||
if (!umap_char_array_is_end(it) )
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
umap_char_array_cleanup(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CTL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -147,7 +147,7 @@ select_config(int func, size_t n, const config_func_t functions[])
|
||||
fprintf(stderr, " %d: %s\n", functions[i].num, functions[i].funcname);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--grapĥ]\n"
|
||||
"USAGE: FUNC_NUMBER [--from number --to number (--grow number | --step number)] [--graph]\n"
|
||||
"[--repeat number] [--best|--average|--best-within] [--quiet]\n");
|
||||
exit(-1);
|
||||
}
|
||||
@@ -235,7 +235,7 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
|
||||
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);
|
||||
@@ -271,6 +271,8 @@ test(const char library[], size_t n, const config_func_t functions[], int argc,
|
||||
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)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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-2021, 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:
|
||||
|
||||
@@ -73,3 +73,12 @@ V0.5.*: * M_INVERT is renamed into M_REVERSE to be more coherent with the REVERS
|
||||
* 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
|
||||
@@ -1,5 +1,272 @@
|
||||
*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?
|
||||
==> self shall be the destination?
|
||||
|
||||
- How to initialize the specialization field of the container? provide custom initialization functions? It seems to be the hard point.
|
||||
* INIT: Force a default to NULL ?
|
||||
* INIT_SET: Force the same value than the src? We may want another pool!
|
||||
* INIT_MOVE: Force the same value than the src. Mandatory
|
||||
* MOVE: Assume the same value. Mandatory
|
||||
* SET: Use the already define pool
|
||||
* INIT_WITH: Force a default to NULL?
|
||||
==> init_emplace ?
|
||||
-- How can we handle containers that allocate on initialization? It cannot, so this solution seems broken
|
||||
==> Modify constructor prototype to add allocators (except for MOVE/INIT_MOVE)
|
||||
* INIT(dest) ==> INIT(dest, context)
|
||||
* INIT(dest, src) ==> INIT_SET(dest, context, src)
|
||||
* INIT_WITH(dest, ...) ==> INIT_WITH(dest, context, ...)
|
||||
* INIT emplace(dest [custom]) ==> INIT_emplace(dest, context, [custom])
|
||||
==> How to pass context? Inherited from master container? A CONTEXT may be present in the parent container but the child may not accept CONTEXT... Same than the Heap Allocator is not the same between different types... The allocator of the parent may be different from the one of the child... ==> Force context to be the same ?
|
||||
==> If a type A uses CONTEXT, all containers constructed from A shall use CONTEXT too
|
||||
-- Need to use an oplist for context or force basic type?
|
||||
|
||||
* 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:
|
||||
|
||||
@@ -34,12 +301,15 @@ unsigned get_small_hash(int64_t x) {
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
* TODO #25 : Support of error code model for error handling. :ENHANCEMENT:
|
||||
Can also (should?) use SIMD to test for several hash entries at the same times
|
||||
In which case a complete new implementation will be needed
|
||||
|
||||
* 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".
|
||||
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)
|
||||
@@ -98,19 +368,20 @@ RETCODE/RETCODE
|
||||
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?
|
||||
- What about M_LET / M_EACH? Maybe only supports those.
|
||||
|
||||
|
||||
* TODO #24 : New: Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
* 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: Strict MOVE semantic to clarify :ENHANCEMENT:
|
||||
** State
|
||||
|
||||
Some type may need to have a force MOVE semantic (for example, they can store
|
||||
pointer to themselves). Currently the INIT_MOVE & MOVE operators are more
|
||||
@@ -125,7 +396,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
|
||||
@@ -144,8 +415,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: New: 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
|
||||
@@ -161,21 +446,18 @@ except that we can scan 64 entries at a time).
|
||||
Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
|
||||
implementation.
|
||||
|
||||
|
||||
* TODO #19: New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
* 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 : New: Ressource handler :ENHANCEMENT:
|
||||
|
||||
A global 'ressouce handler' which shall associated a unique handle to a ressource.
|
||||
The handle shall be unique for the ressource and shall not be reused.
|
||||
@@ -202,11 +484,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: New: 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.
|
||||
@@ -229,31 +510,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?)
|
||||
- How the code can be factorized with RETCODE needs?
|
||||
|
||||
|
||||
* 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:
|
||||
|
||||
@@ -287,8 +544,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: New: Atomic shared pointer :ENHANCEMENT:
|
||||
* TODO #12 : New: Atomic shared pointer :ENHANCEMENT:
|
||||
|
||||
Add an extension to the SHARED_PTR API:
|
||||
|
||||
@@ -362,9 +620,7 @@ 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: New: 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
|
||||
@@ -410,7 +666,6 @@ It needs before lock-free list: http://www.cse.yorku.ca/~ruppert/papers/lfll.pdf
|
||||
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:
|
||||
@@ -448,6 +703,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: 102 KiB After Width: | Height: | Size: 128 KiB |
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2023, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -21,8 +21,9 @@
|
||||
# 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 -g
|
||||
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
|
||||
@@ -30,18 +31,33 @@ RM=rm -f
|
||||
.SUFFIXES: .c .exe
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` `cat config.curl` $(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
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
|
||||
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
|
||||
printf "#include <curl/curl.h>\nint main(void){curl_global_init(CURL_GLOBAL_DEFAULT);}" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c `curl-config --cflags --libs` -o config-test.exe 2> /dev/null && echo "-DHAVE_CURL=1 `curl-config --cflags --libs`" > config.curl || echo "-DHAVE_CURL=0 " > config.curl
|
||||
printf "#include <stdio.h>\nint main(void){printf(\"Ok\"); return 0;}\n" > config-test.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c -ffunction-sections -fdata-sections -Wl,--gc-sections 2> /dev/null && echo "-ffunction-sections -fdata-sections -Wl,--gc-sections" > config.link || echo "" > config.link
|
||||
$(RM) config-test.c config-test.exe
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config
|
||||
|
||||
|
||||
$(RM) *.exe *.s *~ *.o ./a.dat config config.link config.curl
|
||||
@@ -4,16 +4,16 @@
|
||||
|
||||
/* Define a dynamic array of int */
|
||||
ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this dynamic array globally */
|
||||
/* 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 */
|
||||
/* 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, M_BOOL_OPLIST)
|
||||
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 */
|
||||
/* 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 */
|
||||
@@ -41,10 +41,10 @@ int main(void)
|
||||
#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) {
|
||||
@@ -56,13 +56,13 @@ int main(void)
|
||||
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;
|
||||
}
|
||||
@@ -3,18 +3,18 @@
|
||||
#include "m-algo.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define a dictionnary (or hash_map or undordered_map)
|
||||
/* 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_DEFAULT_OPLIST)
|
||||
#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 a string starts with the given pattern */
|
||||
/* 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))
|
||||
|
||||
@@ -23,14 +23,13 @@ ARRAY_DEF(vector_int, int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int s;
|
||||
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 dictionanry
|
||||
M_LET( (m, (STRING_CTE("foo"), 1), (STRING_CTE("bar"), 42), (STRING_CTE("bluez"), 7), (STRING_CTE("stop"), 789) ), tmp, dict_t) {
|
||||
|
||||
/* Extract all elements of 'm' that starts with 'b' */
|
||||
// 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);
|
||||
|
||||
@@ -7,28 +7,31 @@ ARRAY_DEF(vector_int, int)
|
||||
/* Register the oplist of this array of int globally */
|
||||
#define M_OPL_vector_int_t() ARRAY_OPLIST(vector_int)
|
||||
|
||||
/* Set s (string_t) to the integer i */
|
||||
#define str_ui(s, i) string_printf(s, "%d", i)
|
||||
|
||||
/* Concat two strings by insertion a '-' within them */
|
||||
#define str_cat(s1, s2) (string_cat_str(s1, "-"), string_cat(s1, s2))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let s be a string_t and initilize it.
|
||||
// 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, product;
|
||||
// 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 */
|
||||
ALGO_REDUCE( (s, string_t), v, vector_int_t, str_cat, str_ui);
|
||||
/* 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"
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t allocated_size = 0;
|
||||
|
||||
static void* my_alloc(size_t s)
|
||||
{
|
||||
printf("Alloc called s=%lu!\n", s);
|
||||
allocated_size += s;
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
static void my_free(void *ptr, size_t s)
|
||||
{
|
||||
printf("Free called s=%lu!\n", s);
|
||||
allocated_size -= s;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static void *last_alloc;
|
||||
|
||||
static void* my_array_alloc(size_t s, void *org, size_t n)
|
||||
{
|
||||
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
|
||||
last_alloc = realloc(org, s*n);
|
||||
return last_alloc;
|
||||
}
|
||||
|
||||
static void my_array_free(void *ptr)
|
||||
{
|
||||
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
|
||||
if (ptr != last_alloc) {
|
||||
printf("Somthing went wrong.\n");
|
||||
exit(4);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Allocate for single object
|
||||
# define M_MEMORY_ALLOC(type) my_alloc (sizeof (type))
|
||||
# define M_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
|
||||
|
||||
// Allocate for array of objects
|
||||
# define M_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
|
||||
# define M_MEMORY_FREE(ptr) my_array_free(ptr)
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
LIST_DEF(list_int, int)
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
printf("List demo\n");
|
||||
|
||||
list_int_t list;
|
||||
list_int_init(list);
|
||||
|
||||
list_int_push_back(list, 34);
|
||||
list_int_push_back(list, 34);
|
||||
|
||||
if (allocated_size == 0) {
|
||||
printf("Nothing was allocated... Very strange...\n");
|
||||
exit(1);
|
||||
}
|
||||
list_int_clear(list);
|
||||
|
||||
if (allocated_size != 0) {
|
||||
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
|
||||
exit(2);
|
||||
}
|
||||
printf("Global custom allocator for list works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
printf("Array demo\n");
|
||||
|
||||
array_int_t array;
|
||||
array_int_init(array);
|
||||
|
||||
array_int_push_back(array, 34);
|
||||
array_int_push_back(array, 34);
|
||||
|
||||
array_int_clear(array);
|
||||
|
||||
printf("Global custom allocator for array works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
test_array();
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "m-list.h"
|
||||
#include "m-array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t allocated_size = 0;
|
||||
|
||||
static void* my_alloc(size_t s)
|
||||
{
|
||||
printf("Alloc called s=%lu!\n", s);
|
||||
allocated_size += s;
|
||||
return malloc(s);
|
||||
}
|
||||
|
||||
static void my_free(void *ptr, size_t s)
|
||||
{
|
||||
printf("Free called s=%lu!\n", s);
|
||||
allocated_size -= s;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// Allocate for single object
|
||||
# define MY_MEMORY_ALLOC(type) my_alloc (sizeof (type))
|
||||
# define MY_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Override only for this container the memory allocation function
|
||||
LIST_DEF(list_int, int, M_OPEXTEND(M_BASIC_OPLIST, NEW(MY_MEMORY_ALLOC), DEL(MY_MEMORY_DEL)))
|
||||
|
||||
static void test_list(void)
|
||||
{
|
||||
printf("List demo\n");
|
||||
|
||||
list_int_t list;
|
||||
list_int_init(list);
|
||||
|
||||
list_int_push_back(list, 34);
|
||||
list_int_push_back(list, 34);
|
||||
|
||||
if (allocated_size == 0) {
|
||||
printf("Nothing was allocated... Very strange...\n");
|
||||
exit(1);
|
||||
}
|
||||
list_int_clear(list);
|
||||
|
||||
if (allocated_size != 0) {
|
||||
printf("Nothing was freed (%lu)... Very strange...\n", allocated_size);
|
||||
exit(2);
|
||||
}
|
||||
printf("Global custom allocator for list works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
static void *last_alloc;
|
||||
|
||||
static void* my_array_alloc(size_t s, void *org, size_t n)
|
||||
{
|
||||
printf("Array Alloc called org=%p of n=%zu elements of size s=%lu!\n", org, n, s);
|
||||
last_alloc = realloc(org, s*n);
|
||||
return last_alloc;
|
||||
}
|
||||
|
||||
static void my_array_free(void *ptr)
|
||||
{
|
||||
printf("Array Free called ptr=%p last_alloc=%p!\n", ptr, last_alloc);
|
||||
if (ptr != last_alloc) {
|
||||
printf("Somthing went wrong.\n");
|
||||
exit(4);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// Allocate for array of objects
|
||||
# define MY_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
|
||||
# define MY_MEMORY_FREE(ptr) my_array_free(ptr)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Override only for this container the memory allocation function
|
||||
ARRAY_DEF(array_int, int, M_OPEXTEND(M_BASIC_OPLIST, REALLOC(MY_MEMORY_REALLOC), FREE(MY_MEMORY_FREE)))
|
||||
|
||||
static void test_array(void)
|
||||
{
|
||||
printf("Array demo\n");
|
||||
|
||||
array_int_t array;
|
||||
array_int_init(array);
|
||||
|
||||
array_int_push_back(array, 34);
|
||||
array_int_push_back(array, 34);
|
||||
|
||||
array_int_clear(array);
|
||||
|
||||
printf("Global custom allocator for array works!\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_list();
|
||||
test_array();
|
||||
exit(0);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -96,6 +96,7 @@ static void data_node_clear(data_node *obj)
|
||||
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,
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_id, 5, int, string_t)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
#define M_OPL_map_employee_id_t() BPTREE_OPLIST2(map_employee_id, M_BASIC_OPLIST, STRING_OPLIST)
|
||||
|
||||
// Define a map string -> int named map_employee_name
|
||||
// The number 5 is the number of elements in a node of the B+TREE
|
||||
BPTREE_DEF2(map_employee_name, 5, string_t, int)
|
||||
// Register the oplist of this map globally.
|
||||
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_map_employee_name_t() BPTREE_OPLIST2(map_employee_name, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -25,7 +25,9 @@ int main(void)
|
||||
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));
|
||||
|
||||
@@ -57,9 +59,12 @@ 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")));
|
||||
// Print using emplace (we give a const char [] isntead of a const string_t, avoiding macro STRING_CTE)
|
||||
printf("\nElisabeth has id = %d\n", *map_employee_name_get_emplace(Employees_r, "Elisabeth"));
|
||||
} /* Employees_r is cleared beyond this point */
|
||||
|
||||
// But employee is not since we don't use M_LET
|
||||
map_employee_id_clear(Employees);
|
||||
return 0;
|
||||
}
|
||||
@@ -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,160 @@
|
||||
#if HAVE_CURL
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include "m-dict.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-string.h"
|
||||
#include "m-list.h"
|
||||
#include "m-serial-json.h"
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
// Define container types
|
||||
// First a generic map string to string
|
||||
DICT_DEF2(map_str, string_t, string_t)
|
||||
#define M_OPL_map_str_t() DICT_OPLIST(map_str, STRING_OPLIST, STRING_OPLIST)
|
||||
|
||||
// This structure matches the JSON structure returns by the used WEB server
|
||||
// for the GET command.
|
||||
// It can be whatever you want provided it matches what is expected by the WEB server
|
||||
TUPLE_DEF2(web_data,
|
||||
(args, map_str_t),
|
||||
(headers, map_str_t),
|
||||
(origin, string_t),
|
||||
(url, string_t))
|
||||
#define M_OPL_web_data_t() TUPLE_OPLIST(web_data, M_OPL_map_str_t(), M_OPL_map_str_t(), STRING_T, STRING_T)
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
static size_t
|
||||
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
(void) size; // Parameter not used
|
||||
char *src = buffer;
|
||||
string_ptr str = userp;
|
||||
for(size_t i = 0; i < nmemb; i++) {
|
||||
string_push_back(str, src[i]);
|
||||
}
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static bool get_data(web_data_t data, const char url[])
|
||||
{
|
||||
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||
CURLcode res;
|
||||
string_t str;
|
||||
CURL *handle = curl_easy_init();
|
||||
if (handle) {
|
||||
string_init(str);
|
||||
// Perform an http GET request and fill in str with the JSON answer
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, str);
|
||||
res = curl_easy_perform(handle);
|
||||
curl_easy_cleanup(handle);
|
||||
if (res == CURLE_OK) {
|
||||
// Parse the string and fill in the object
|
||||
m_serial_str_json_read_t serial;
|
||||
m_serial_str_json_read_init(serial, string_get_cstr(str));
|
||||
r = web_data_in_serial(data, serial);
|
||||
m_serial_str_json_read_clear(serial);
|
||||
}
|
||||
string_clear(str);
|
||||
}
|
||||
return r == M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
static size_t
|
||||
ignore_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
(void) buffer; // Parameter not used
|
||||
(void) size; // Parameter not used
|
||||
(void) userp; // Parameter not used
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static bool post_data(web_data_t data, const char url[], bool display_answer)
|
||||
{
|
||||
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||
CURLcode res = 0;
|
||||
string_t str;
|
||||
CURL *handle = curl_easy_init();
|
||||
if (handle) {
|
||||
string_init(str);
|
||||
// Get a JSON string
|
||||
m_serial_str_json_write_t serial;
|
||||
m_serial_str_json_write_init(serial, str);
|
||||
r = web_data_out_serial(serial, data);
|
||||
m_serial_str_json_write_clear(serial);
|
||||
if (r == M_SERIAL_OK_DONE) {
|
||||
// Post JSON string
|
||||
struct curl_slist *headers=NULL;
|
||||
headers = curl_slist_append(headers, "Content-Type: text/json");
|
||||
if (headers != NULL) {
|
||||
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, string_get_cstr(str));
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
|
||||
if (display_answer == false) {
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ignore_data);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
|
||||
}
|
||||
res = curl_easy_perform(handle);
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
}
|
||||
curl_easy_cleanup(handle);
|
||||
string_clear(str);
|
||||
}
|
||||
return (r == M_SERIAL_OK_DONE) && (res == CURLE_OK);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
// Remote server URL
|
||||
#define URL_GET "https://httpbin.org/get"
|
||||
#define URL_POST "https://httpbin.org/post"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURLcode ret = curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
if (ret != CURLE_OK) abort();
|
||||
|
||||
web_data_t data;
|
||||
web_data_init(data);
|
||||
|
||||
// Test http GET
|
||||
bool b = get_data(data, URL_GET);
|
||||
if (b) {
|
||||
// We success receiving the JSON object and fill in the C object web_data with it.
|
||||
// Let's display the object content:
|
||||
printf("SUCCESS. Receive data =\n");
|
||||
web_data_out_str(stdout, data);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("ERROR: Cannot GET data or get data are not in expected format\n");
|
||||
}
|
||||
|
||||
// Test http POST
|
||||
web_data_emplace_origin(data, "This is the origin");
|
||||
web_data_emplace_url(data, "This is the URL");
|
||||
//web_data_set_origin(data, STRING_CTE("This is the origin"));
|
||||
//web_data_set_url(data, STRING_CTE("This is the URL"));
|
||||
b = post_data(data, URL_POST, false);
|
||||
if (b) {
|
||||
printf("SUCCESS: Post\n");
|
||||
} else {
|
||||
printf("ERROR post\n");
|
||||
}
|
||||
|
||||
web_data_clear(data);
|
||||
|
||||
curl_global_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -1,5 +1,10 @@
|
||||
#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; };
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
// Define a dictionnary of string --> int
|
||||
// named 'dict_str'
|
||||
DICT_DEF2(dict_str, string_t, STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||
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)) {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include "m-dict.h"
|
||||
|
||||
/*
|
||||
* Provide OOR methods for OA Hashmap.
|
||||
* See documentation for definition of OOR
|
||||
* OOR values are represented as:
|
||||
* empty (0) is INT_MIN
|
||||
* deleted (1) is INT_MIN + 1
|
||||
* So valid range for integers are [INT_MIN+2, INT_MAX]
|
||||
*/
|
||||
static inline bool oor_equal_p(int k, char n)
|
||||
{
|
||||
return k == INT_MIN + n;
|
||||
}
|
||||
|
||||
static inline int oor_set(char n)
|
||||
{
|
||||
return INT_MIN + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a custom hash function (optional for OA)
|
||||
*/
|
||||
static inline size_t hash(int n)
|
||||
{
|
||||
return (size_t) n; // Identity hash!
|
||||
}
|
||||
|
||||
/* Define an OA dictionnay which performs a hashmap between an int to an int */
|
||||
DICT_OA_DEF2(dict_oa,
|
||||
int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)),
|
||||
int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_oa_t d;
|
||||
dict_oa_init(d);
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
dict_oa_set_at(d, i*i, 4*i);
|
||||
}
|
||||
dict_oa_set_at(d, 3, -17);
|
||||
|
||||
printf("DICT[3] = %d\n", *dict_oa_get(d, 3));
|
||||
|
||||
dict_oa_it_t it;
|
||||
printf("DICT=");
|
||||
for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) {
|
||||
printf("%d:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
dict_oa_clear(d);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include "m-dict.h"
|
||||
|
||||
/*
|
||||
* Provide OOR methods for OA Hashmap.
|
||||
* See documentation for definition of OOR
|
||||
* OOR values are represented as:
|
||||
* empty (0) is "EMPTY"
|
||||
* deleted (1) is "DELETED"
|
||||
*/
|
||||
static const char empty_str[] = "EMPTY";
|
||||
static const char deleted_str[] = "DELETED";
|
||||
static const char *const oor_table[] = { empty_str, deleted_str };
|
||||
|
||||
static inline bool oor_equal_p(const char *k, int n)
|
||||
{
|
||||
return k == oor_table[n];
|
||||
}
|
||||
|
||||
static inline const char *oor_set(int n)
|
||||
{
|
||||
return oor_table[n];
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide a custom hash function (optional for OA)
|
||||
*/
|
||||
static inline size_t hash(const char *k)
|
||||
{
|
||||
size_t r = 17;
|
||||
while (*k) {
|
||||
r = *k * 33 + r;
|
||||
k++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Define an OA dictionnay which performs a hashmap between a CSTR to an int */
|
||||
DICT_OA_DEF2(dict_oa,
|
||||
const char *, M_OPEXTEND(M_CSTR_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set)), HASH(hash)),
|
||||
int, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dict_oa_t d;
|
||||
dict_oa_init(d);
|
||||
|
||||
dict_oa_set_at(d, "THIS", -17);
|
||||
dict_oa_set_at(d, "IS", -170);
|
||||
dict_oa_set_at(d, "AN", 7);
|
||||
dict_oa_set_at(d, "EXAMPLE", 77);
|
||||
|
||||
printf("DICT[\"AN\"] = %d\n", *dict_oa_get(d, "AN"));
|
||||
|
||||
dict_oa_it_t it;
|
||||
printf("DICT=");
|
||||
for(dict_oa_it(it, d); !dict_oa_end_p(it); dict_oa_next(it)) {
|
||||
printf("%s:%d, ", dict_oa_cref(it)->key, dict_oa_cref(it)->value);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
dict_oa_clear(d);
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -25,8 +25,8 @@
|
||||
/* Define the needed data structure : */
|
||||
|
||||
// Define a dictionnary of constant string --> integer and register it.
|
||||
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_DEFAULT_OPLIST)
|
||||
DICT_DEF2(dict_mph, const char *, M_CSTR_OPLIST, uint32_t, M_BASIC_OPLIST)
|
||||
#define M_OPL_dict_mph_t() DICT_OPLIST(dict_mph, M_CSTR_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// Define an array of integer to store the value and register it.
|
||||
ARRAY_DEF(array_value, uint32_t) // Start from 1. 0 is 'None'
|
||||
|
||||
@@ -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_cget_n(p->value));
|
||||
}
|
||||
if (my_integer_z_p(p->value)) {
|
||||
printf ("It is a mpz_t, value =");
|
||||
mpz_out_str(stdout, 10, *my_integer_cget_z(p->value));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* All variables are automatically cleared beyond this point */
|
||||
}
|
||||
|
||||
#else
|
||||
// Nothing to do
|
||||
int main(void) { return 0; }
|
||||
#endif
|
||||
@@ -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),
|
||||
|
||||
@@ -3,7 +3,14 @@
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
|
||||
// Let's create an array of string_t and register it globaly
|
||||
/* 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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "m-rbtree.h"
|
||||
|
||||
// Let's define one utility function.
|
||||
void *xmalloc(size_t n);
|
||||
void *xmalloc(size_t n)
|
||||
static void *xmalloc(size_t n)
|
||||
{
|
||||
void *p = malloc (n);
|
||||
if (!p) abort();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
/* Definition of an associative map string_t --> size_t */
|
||||
DICT_DEF2(dict_str, string_t, size_t)
|
||||
#define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_DEFAULT_OPLIST)
|
||||
#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)
|
||||
@@ -26,13 +26,14 @@ int main(void)
|
||||
|
||||
// Count the words.
|
||||
M_LET(map, dict_str_t) {
|
||||
// Count the words:
|
||||
// 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
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "m-try.h"
|
||||
#include "m-array.h"
|
||||
|
||||
// Define & register an array of int
|
||||
ARRAY_DEF(array, int)
|
||||
#define M_OPL_array_t() ARRAY_OPLIST(array, M_BASIC_OPLIST)
|
||||
|
||||
// This shall be defined once per program to define the global variables needed
|
||||
// to handle the exceptions.
|
||||
M_TRY_DEF_ONCE()
|
||||
|
||||
static void f(void)
|
||||
{
|
||||
M_TRY(f_exception) {
|
||||
// Let's define a variable and do stuff:
|
||||
// Using M_LET allows the register of destructors for the exception handler.
|
||||
M_LET(a, array_t) {
|
||||
array_push_back(a, 5);
|
||||
array_push_back(a, 4);
|
||||
array_push_back(a, 3);
|
||||
array_push_back(a, 2);
|
||||
array_push_back(a, 1);
|
||||
// Throw a M_ERROR_MEMORY exception
|
||||
M_THROW(M_ERROR_MEMORY);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
} M_CATCH(f_exception, M_ERROR_MEMORY) {
|
||||
// Exception handler than catches the M_ERROR_MEMORY errors.
|
||||
// Here the destructor of variable a has been called to free memory
|
||||
printf("Memory exception %d received in f function, thrown by %s:%d\n",
|
||||
f_exception->error_code, f_exception->filename, f_exception->line);
|
||||
}
|
||||
}
|
||||
|
||||
static void g(void)
|
||||
{
|
||||
M_TRY(f_exception) {
|
||||
// Let's define a variable and do stuff:
|
||||
// Using M_LET allows the register of destructors for the exception handler.
|
||||
M_LET(a, array_t) {
|
||||
array_push_back(a, 5);
|
||||
array_push_back(a, 4);
|
||||
array_push_back(a, 3);
|
||||
array_push_back(a, 2);
|
||||
array_push_back(a, 1);
|
||||
// Throw an unkown exception
|
||||
M_THROW(42);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
} M_CATCH(f_exception, M_ERROR_MEMORY) {
|
||||
printf("Memory exception %d received in f function, thrown by %s:%d\n",
|
||||
f_exception->error_code, f_exception->filename, f_exception->line);
|
||||
printf("This should never be printed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Let's do a global exception handler
|
||||
M_TRY(main_exception) {
|
||||
f();
|
||||
g();
|
||||
} M_CATCH(main_exception, 0) {
|
||||
// Exception handler than catches all errors.
|
||||
// Here the destructor of variable a has been called to free memory
|
||||
printf("Exception %d received in main function, thrown by %s:%d\n",
|
||||
main_exception->error_code, main_exception->filename, main_exception->line);
|
||||
}
|
||||
printf("You should run it under valgrind to check that all memory allocations are freed.\n");
|
||||
exit(0);
|
||||
}
|
||||
@@ -11,7 +11,7 @@ TUPLE_DEF2(employee,
|
||||
(age, int),
|
||||
(idnum, int))
|
||||
/* Register globaly the employee_t oplist */
|
||||
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define 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)
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "m-tuple.h"
|
||||
#include "m-tree.h"
|
||||
#include "m-worker.h"
|
||||
#include "m-string.h"
|
||||
#include "m-atomic.h"
|
||||
|
||||
|
||||
/* Define the comparison function for atomic_uint type
|
||||
to sort the atomic unsigned int with the biggest value first. */
|
||||
static inline int atomic_uint_cmp(const atomic_uint *a, const atomic_uint *b)
|
||||
{
|
||||
unsigned ai = atomic_load(a), bi = atomic_load(b);
|
||||
return ai > bi ? -1 : ai < bi;
|
||||
}
|
||||
|
||||
/* Define the oplist for atomic_uint and register it globally.
|
||||
This oplist extends the basic oplist by:
|
||||
* disabling HASH for atomic as the default hash method won't work.
|
||||
* providing the methods for CMP, INIT_SET and SET operators (with their API adaptator) */
|
||||
#define M_OPL_atomic_uint() M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(API_6(atomic_uint_cmp)), INIT_SET(API_2(atomic_store)), SET(API_2(atomic_store)))
|
||||
|
||||
|
||||
/* Define a directory as a tree where each node contains:
|
||||
* the number of lines of the files in this directory,
|
||||
* and the name of the directory/
|
||||
Since we want to sort with the number of lines only, we extend the oplist of a string by disabling the compare method.
|
||||
So first, let's define the node as a tuple of such elements:
|
||||
*/
|
||||
M_TUPLE_DEF2( dir, (nlines, atomic_uint), (name, m_string_t, M_OPEXTEND(M_STRING_OPLIST, CMP(0))))
|
||||
/* Register globally the oplist of this tuple */
|
||||
#define M_OPL_dir_t() M_TUPLE_OPLIST(dir, M_OPL_atomic_uint(), M_STRING_OPLIST)
|
||||
|
||||
/* Define a hierarchical tree of directory.
|
||||
Note that it will use the globally registered oplist associated to dir_t to use it */
|
||||
M_TREE_DEF(tree, dir_t)
|
||||
|
||||
|
||||
/* Maximum number of characters read by file */
|
||||
#define MAX_READ_BUFFER 8192
|
||||
|
||||
/* Maximum number of directory to scan */
|
||||
#define MAX_DIRECTORY 100000
|
||||
|
||||
|
||||
/* Define the pool of worker threads */
|
||||
m_worker_t workers;
|
||||
|
||||
/* Global synchronous block for all threads */
|
||||
m_worker_sync_t workers_block;
|
||||
|
||||
/* Add a specialization of the spawn function for the scan_file function.
|
||||
This functions takes as input an iterator of a tree (treated as a POD data),
|
||||
and a file name */
|
||||
M_WORKER_SPAWN_DEF2(scan_file, (parent, tree_it_t, M_POD_OPLIST), (filename, m_string_t) )
|
||||
|
||||
|
||||
/* Add either the root node or a child to parent in function of the existence of parent */
|
||||
static tree_it_t
|
||||
add_directory(tree_it_t parent, const m_string_t dirname)
|
||||
{
|
||||
if (tree_end_p(parent)) {
|
||||
return tree_emplace_root( tree_tree(parent), 0, dirname);
|
||||
} else {
|
||||
return tree_emplace_child(parent, 0, dirname);
|
||||
}
|
||||
}
|
||||
|
||||
/* count the number of end of line character in the buffer */
|
||||
static unsigned
|
||||
count_eol(size_t num, const char buffer[num])
|
||||
{
|
||||
unsigned count = 0;
|
||||
for(size_t i = 0; i < num; i++) {
|
||||
count += buffer[i] == '\n';
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Test if a filename suffix ends with a C++ or C suffix */
|
||||
static bool
|
||||
is_a_c_file(const m_string_t filename)
|
||||
{
|
||||
return (m_string_end_with_str_p(filename, ".c")
|
||||
|| m_string_end_with_str_p(filename, ".h")
|
||||
|| m_string_end_with_str_p(filename, ".cpp")
|
||||
|| m_string_end_with_str_p(filename, ".hpp"));
|
||||
}
|
||||
|
||||
/* Scan the file and count its number of lines */
|
||||
static void
|
||||
scan_file(tree_it_t parent, m_string_t filename)
|
||||
{
|
||||
FILE *f = fopen(m_string_get_cstr(filename), "rt");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", m_string_get_cstr(filename) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read the FILE per bulk of MAX_READ_BUFFER */
|
||||
char buffer[MAX_READ_BUFFER];
|
||||
unsigned count = 0;
|
||||
size_t num;
|
||||
do {
|
||||
num = fread (buffer, 1, MAX_READ_BUFFER, f);
|
||||
count += count_eol(num, buffer);
|
||||
} while (num == MAX_READ_BUFFER);
|
||||
fclose(f);
|
||||
|
||||
/* Adding the number of lines to the parent directory */
|
||||
dir_t *d = tree_ref(parent);
|
||||
/* atomic add because the scan of files is done in parallel */
|
||||
atomic_fetch_add( &(*d)->nlines, count );
|
||||
}
|
||||
|
||||
/* Scan the directories recursively for all files */
|
||||
static void
|
||||
scan_directories(tree_it_t parent, const m_string_t dirname)
|
||||
{
|
||||
tree_it_t it = add_directory(parent, dirname);
|
||||
|
||||
m_string_t filename;
|
||||
m_string_init(filename);
|
||||
DIR *dir = opendir(m_string_get_cstr(dirname));
|
||||
if (dir == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", m_string_get_cstr(dirname) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Scan all entries in the directory
|
||||
struct dirent *entry = readdir(dir);
|
||||
while (entry) {
|
||||
// Ignore hidden entries (including '.' and '..')
|
||||
if (entry->d_name[0] != '.') {
|
||||
// Construct the path to the filename by concatenating dirname, "/" and d_name
|
||||
m_string_sets(filename, dirname, "/", entry->d_name);
|
||||
// Get the property of this filename
|
||||
struct stat buf;
|
||||
int err = stat(m_string_get_cstr(filename), &buf);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot stat %s\n", m_string_get_cstr(filename));
|
||||
exit(2);
|
||||
}
|
||||
// Further scanning in function of the kind of entry
|
||||
if (S_ISDIR(buf.st_mode)) {
|
||||
scan_directories(it, filename);
|
||||
} else if (is_a_c_file(filename)) {
|
||||
// Spawn a scan of file to available workers or run it ourselves
|
||||
m_worker_spawn_scan_file(workers_block, scan_file, it, filename);
|
||||
}
|
||||
}
|
||||
// Next entry in the directory
|
||||
entry = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
m_string_clear(filename);
|
||||
}
|
||||
|
||||
/* Consolidate all lines number to the parent directory */
|
||||
static void
|
||||
consolidate_directories(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the children, then the parent
|
||||
for(tree_it_t it = tree_it_post(directories) ; !tree_end_p(it) ; tree_next_post(&it) ) {
|
||||
dir_t *parent = tree_up_ref(it);
|
||||
dir_t *myself = tree_ref(it);
|
||||
if (parent != NULL) {
|
||||
// Add the child number of lines to the parent
|
||||
atomic_fetch_add_explicit(&(*parent)->nlines, (*myself)->nlines, memory_order_relaxed);
|
||||
}
|
||||
// Sort the data of the children by the number of lines
|
||||
tree_sort_child(it);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the consolidated results on stdout */
|
||||
static void
|
||||
print_result(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the parent, then the children
|
||||
for(tree_it_t it = tree_it(directories) ; !tree_end_p(it) ; tree_next(&it) ) {
|
||||
int i, depth = tree_depth(it);
|
||||
for(i = 0; i < depth; i++) printf("+");
|
||||
for( ; i < 8; i++) printf(" ");
|
||||
const dir_t *d = tree_cref(it);
|
||||
printf("%6u %s\n", (unsigned) (*d)->nlines, m_string_get_cstr( (*d)->name ) );
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
tree_t directories;
|
||||
m_string_t str;
|
||||
|
||||
printf("Count the number of C/C++ lines of code\n");
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "ERROR. Usage is '%s <directory>'.\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Initialize the worker threads */
|
||||
m_worker_init(workers);
|
||||
|
||||
/* Init the tree, reserve for at least the number of max directory
|
||||
and prevent any further increase of allocation:
|
||||
this is to ensure that other threads can deref a dir safely */
|
||||
tree_init(directories);
|
||||
tree_reserve(directories, MAX_DIRECTORY);
|
||||
tree_lock(directories, true);
|
||||
m_string_init_set_cstr(str, argv[1]);
|
||||
tree_it_t it = tree_it_end(directories);
|
||||
|
||||
/* Main processing */
|
||||
m_worker_start(workers_block, workers);
|
||||
scan_directories(it, str);
|
||||
worker_sync(workers_block);
|
||||
consolidate_directories(directories);
|
||||
print_result(directories);
|
||||
|
||||
/* Clear everything & quit */
|
||||
m_string_clear(str);
|
||||
tree_clear(directories);
|
||||
m_worker_clear(workers);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "m-list.h"
|
||||
#include "m-generic.h"
|
||||
|
||||
LIST_DEF(list_uint, unsigned int)
|
||||
// Register for M_LET & M_EACH
|
||||
#define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST)
|
||||
// Register for Generic:
|
||||
#define M_GENERIC_ORG_1() (USER)
|
||||
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_list_uint_t()
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET(list, list_uint_t) {
|
||||
// We can push in the list. It will call the registered method.
|
||||
push(list, 42);
|
||||
push(list, 17);
|
||||
// We can iterate over the list
|
||||
for each(item, list) {
|
||||
M_PRINT("ITEM=", *item, "\n");
|
||||
}
|
||||
// We can print directly the list. It will use the registered method
|
||||
M_PRINT("List = ", list, "\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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,6 +2,8 @@
|
||||
#include "m-tuple.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Basic example to show JSON serialization */
|
||||
|
||||
// Let's define a 'person' composed of several fields.
|
||||
TUPLE_DEF2(person,
|
||||
(surname, string_t),
|
||||
@@ -9,7 +11,7 @@ TUPLE_DEF2(person,
|
||||
(present, bool)
|
||||
)
|
||||
// Register the oplist of this tuple globaly
|
||||
#define M_OPL_person_t() TUPLE_OPLIST(person, M_DEFAULT_OPLIST, STRING_OPLIST, M_DEFAULT_OPLIST )
|
||||
#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)
|
||||
@@ -48,6 +50,7 @@ int main(void)
|
||||
M_LET(base, base_t) {
|
||||
// Read the JSON file and fill-in base
|
||||
read(base, "ex11-json01.json");
|
||||
base_emplace_back(base, STRING_CTE("John"), 40, false);
|
||||
// Print the contents of base:
|
||||
printf ("List of presents:\n");
|
||||
for M_EACH(el, base, base_t) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
|
||||
// Define a basic structure (POD structure) using a tuple to get the default functions
|
||||
TUPLE_DEF2(Point, (x, float), (y, float))
|
||||
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#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_DEFAULT_OPLIST)
|
||||
#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)
|
||||
@@ -28,17 +28,17 @@ ALGO_DEF(cvec_p, cvec_p_t)
|
||||
|
||||
// Define a deque of int, including some basic algorithms
|
||||
DEQUE_DEF(cdeq_i, int)
|
||||
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_DEFAULT_OPLIST)
|
||||
#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_DEFAULT_OPLIST)
|
||||
#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_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
@@ -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 - ALGO module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -28,10 +28,10 @@
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define different kind of basic algorithms named 'name' over the container
|
||||
which oplist is 'contOp', as static inline functions.
|
||||
which oplist is 'cont_oplist'.
|
||||
USAGE:
|
||||
ALGO_DEF(algogName, containerOplist|type if oplist has been registered) */
|
||||
#define ALGO_DEF(name, cont_oplist) \
|
||||
#define M_ALGO_DEF(name, cont_oplist) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_ALG0_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -39,41 +39,45 @@
|
||||
|
||||
/* Map a function (or a macro) to all elements of a container.
|
||||
USAGE:
|
||||
ALGO_FOR_EACH(container, containerOplist, function[, extra arguments of function]) */
|
||||
#define ALGO_FOR_EACH(container, cont_oplist, ...) \
|
||||
ALGO_FOR_EACH(container, containerOplist|type_if_registered_oplist, function[, extra arguments of function]) */
|
||||
#define M_ALGO_FOR_EACH(container, cont_oplist, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_ALG0_FOR_EACH(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__), \
|
||||
M_ALG0_FOR_EACH_ARG(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__ ))
|
||||
(M_ALG0_FOR_EACH, M_ALG0_FOR_EACH_ARG) \
|
||||
(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Map a function (or a macro) to all elements of a container
|
||||
into another container.
|
||||
and store it into another container.
|
||||
USAGE:
|
||||
ALGO_TRANSFORM(contDst, contDOplist, contSrc, contSrcOplist,
|
||||
ALGO_TRANSFORM(contDst, contDOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist,
|
||||
function[, extra arguments of function]) */
|
||||
#define ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
|
||||
#define M_ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_ALG0_TRANSFORM(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__), \
|
||||
M_ALG0_TRANSFORM_ARG(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__ ))
|
||||
(M_ALG0_TRANSFORM, M_ALG0_TRANSFORM_ARG) \
|
||||
(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Extract a subset of a container to copy into another container.
|
||||
USAGE:
|
||||
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist
|
||||
ALGO_EXTRACT(contDst, contDstOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist
|
||||
[, function [, extra arguments of function]]) */
|
||||
#define ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
#define M_ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_ALG0_EXTRACT(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(M_ALG0_EXTRACT_FUNC(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
M_ALG0_EXTRACT_ARG(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__ )))
|
||||
(M_ALG0_EXTRACT, \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__)(M_ALG0_EXTRACT_FUNC, M_ALG0_EXTRACT_ARG)) \
|
||||
(contD, contDop, contS, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Perform a Reduce operation over a container.
|
||||
USAGE:
|
||||
ALGO_REDUCE(dstVar, container, contOplist, reduceFunc
|
||||
[, mapFunc[, extraParameters of map function]]) */
|
||||
#define ALGO_REDUCE(dest, cont, contOp, ...) \
|
||||
ALGO_REDUCE(dstVar, container, contOplist|type_if_registered_oplist, reduceFunc
|
||||
[, mapFunc[, extraParameters of map function]])
|
||||
or
|
||||
ALGO_REDUCE( (dstVar, dstOplist|type_if_registered_oplist), container, contOplist|type_if_registered_oplist, reduceFunc
|
||||
[, mapFunc[, extraParameters of map function]])
|
||||
if the destination variable is not of the same type than the elements of the containers.
|
||||
*/
|
||||
#define M_ALGO_REDUCE(dest, cont, contOp, ...) \
|
||||
M_IF(M_PARENTHESIS_P(dest)) \
|
||||
(M_ALG0_REDUCE_DISPATCH(M_PAIR_1 dest, M_GLOBAL_OPLIST(M_PAIR_2 dest), M_GLOBAL_TYPE(M_PAIR_2 dest),cont, M_GLOBAL_OPLIST(contOp), __VA_ARGS__), \
|
||||
M_ALG0_REDUCE_DISPATCH(dest, M_GET_OPLIST M_GLOBAL_OPLIST(contOp), M_GET_SUBTYPE M_GLOBAL_OPLIST(contOp), cont, contOp, __VA_ARGS__)) \
|
||||
@@ -82,13 +86,15 @@
|
||||
/* Insert into the container 'contDst' at position 'position' all the values
|
||||
of container 'contSrc'.
|
||||
USAGE:
|
||||
ALGO_INSERT_AT(containerDst, containerDstOPLIST|containerDstType, containerDstIterator, containerSrc, containerSrcOPLIST|containerSrcType)
|
||||
ALGO_INSERT_AT(containerDst, containerDstOPLIST|type_if_registered_oplist, containerDstIterator, containerSrc, containerSrcOPLIST|type_if_registered_oplist)
|
||||
*/
|
||||
#define ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
|
||||
#define M_ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
|
||||
M_ALG0_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(contSrcOp) )
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/*****************************************************************************/
|
||||
/******************************** INTERNAL ***********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Try to expand the algorithms */
|
||||
#define M_ALG0_DEF_P1(name, cont_oplist) \
|
||||
@@ -115,36 +121,41 @@
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 10, container_t, cont_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 11, type_t, type_oplist) \
|
||||
\
|
||||
M_ALG0_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_FUNCOBJ(M_ALG0_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
|
||||
M_ALG0_DEF_CALLBACK(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_FUNCOBJ(M_ALG0_DEF_FUNCOBJ(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, type_oplist)( \
|
||||
M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_DEF_FIND(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
, /* NO EQUAL */) \
|
||||
\
|
||||
M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, if, M_C(name, _test_cb_ct), M_C(name, _eq_cb_ct), M_APPLY, M_APPLY) \
|
||||
M_IF_FUNCOBJ(M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, fo, M_C(name, _test_obj_t), M_C(name, _eq_obj_t), M_C(name, _test_obj_call), M_C(name, _eq_obj_call))) \
|
||||
M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
|
||||
if, M_F(name,_test_cb_ct), M_F(name,_eq_cb_ct), M_APPLY, M_APPLY) \
|
||||
M_IF_FUNCOBJ(M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
|
||||
fo, M_F(name,_test_obj_t), M_F(name,_eq_obj_t), M_F(name, _test_obj_call), M_F(name, _eq_obj_call))) \
|
||||
\
|
||||
M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_DEF_MAP(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _, M_C(name, _test_cb_ct), M_APPLY) \
|
||||
M_IF_FUNCOBJ(M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, _fo_, M_C(name, _test_obj_t), M_C(name, _test_obj_call)) ) \
|
||||
M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
|
||||
_, M_F(name,_test_cb_ct), M_APPLY) \
|
||||
M_IF_FUNCOBJ(M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
|
||||
_fo_, M_F(name,_test_obj_t), M_F(name,_test_obj_call)) ) \
|
||||
\
|
||||
/* If there is a IT_REF method, we consider the container as modifiable through iterator */ \
|
||||
M_IF_METHOD(IT_REF, cont_oplist)( \
|
||||
M_ALG0_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_DEF_VECTOR(name, container_t, cont_oplist, type_t, type_oplist, it_t)\
|
||||
\
|
||||
M_IF_METHOD(CMP, type_oplist)( \
|
||||
M_ALG0_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
|
||||
M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
|
||||
M_ALG0_DEF_MINMAX(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
|
||||
M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
|
||||
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
|
||||
M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t)\
|
||||
, /* No IT_REMOVE method */) \
|
||||
, /* No CMP method */) \
|
||||
\
|
||||
M_IF_FUNCOBJ(M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, _sort_fo, M_ALG0_SORT_CALL_OBJ_P4, M_ALG0_SORT_PARAM_OBJ_P4, M_ALG0_SORT_ARG_OBJ_P4) ) \
|
||||
M_IF_FUNCOBJ(M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
|
||||
_sort_fo, M_ALG0_SORT_CALL_OBJ_P4, M_ALG0_SORT_PARAM_OBJ_P4, M_ALG0_SORT_ARG_OBJ_P4) ) \
|
||||
, /* No IT_REF method */) \
|
||||
\
|
||||
M_IF_METHOD(EXT_ALGO, type_oplist)( \
|
||||
@@ -154,36 +165,36 @@
|
||||
|
||||
/* Define the types of the callbacks associated to the algorithms.
|
||||
* Types remain internal */
|
||||
#define M_ALG0_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_CALLBACK(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
typedef bool (*M_C(name, _test_cb_ct))(type_t const); \
|
||||
typedef bool (*M_C(name, _eq_cb_ct))(type_t const, type_t const); \
|
||||
typedef int (*M_C(name, _cmp_cb_ct))(type_t const, type_t const); \
|
||||
typedef void (*M_C(name, _transform_cb_ct))(type_t *, type_t const); \
|
||||
typedef void (*M_C(name, _apply_cb_ct))(type_t); \
|
||||
typedef bool (*M_F(name, _test_cb_ct))(type_t const); \
|
||||
typedef bool (*M_F(name, _eq_cb_ct))(type_t const, type_t const); \
|
||||
typedef int (*M_F(name, _cmp_cb_ct))(type_t const, type_t const); \
|
||||
typedef void (*M_F(name, _transform_cb_ct))(type_t *, type_t const); \
|
||||
typedef void (*M_F(name, _apply_cb_ct))(type_t); \
|
||||
|
||||
|
||||
/* Define the function objects associated to the algorithms.
|
||||
* Created Function objects are part of the public interface */
|
||||
#define M_ALG0_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_FUNCOBJ(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
FUNC_OBJ_ITF_DEF(M_C(name, _test_obj), bool, type_t const) \
|
||||
FUNC_OBJ_ITF_DEF(M_C(name, _eq_obj), bool, type_t const, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_C(name, _cmp_obj), int, type_t const, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_C(name, _transform_obj), void, type_t *, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_C(name, _apply_obj), void, type_t * ) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _test_obj), bool, type_t const) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _eq_obj), bool, type_t const, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _cmp_obj), int, type_t const, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _transform_obj), void, type_t *, type_t const ) \
|
||||
FUNC_OBJ_ITF_DEF(M_F(name, _apply_obj), void, type_t * ) \
|
||||
|
||||
|
||||
/* Define the sort functions with the CMP operator using the order selected */
|
||||
#define M_ALG0_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
|
||||
#define M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
|
||||
\
|
||||
/* Define the encapsulation function that perform the selected order */ \
|
||||
static inline int M_C3(name,sort_name,_cmp)(type_t const*a,type_t const*b) \
|
||||
M_INLINE int M_C3(name,sort_name,_cmp)(type_t const*a,type_t const*b) \
|
||||
{ \
|
||||
return order M_CALL_CMP(type_oplist, *a, *b); \
|
||||
} \
|
||||
\
|
||||
M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, M_ALG0_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
|
||||
M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, M_ALG0_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
|
||||
|
||||
// Call the comparaison function of the type oplist (Using CMP operator)
|
||||
#define M_ALG0_SORT_CALL_CMP_P4(name, sort_name, ref1, ref2) \
|
||||
@@ -192,9 +203,9 @@
|
||||
|
||||
// Call the created function object
|
||||
#define M_ALG0_SORT_CALL_OBJ_P4(name, sort_name, ref1, ref2) \
|
||||
M_C(name, _cmp_obj_call)(funcobj, *ref1, *ref2)
|
||||
M_F(name, _cmp_obj_call)(funcobj, *ref1, *ref2)
|
||||
// Adding a parameter named 'funcobj' to the algorithm functions
|
||||
#define M_ALG0_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_C(name, _cmp_obj_t) funcobj
|
||||
#define M_ALG0_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_F(name, _cmp_obj_t) funcobj
|
||||
#define M_ALG0_SORT_ARG_OBJ_P4 M_DEFERRED_COMMA funcobj
|
||||
|
||||
|
||||
@@ -211,10 +222,10 @@
|
||||
It is needed to add another argument to the function.
|
||||
- cmp_arg: Name of such argument.
|
||||
*/
|
||||
#define M_ALG0_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, cmp_func, cmp_param, cmp_arg) \
|
||||
#define M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, cmp_func, cmp_param, cmp_arg) \
|
||||
\
|
||||
/* Test if the container is sorted */ \
|
||||
static inline bool \
|
||||
M_INLINE bool \
|
||||
M_C3(name,sort_name,_p)(const container_t l cmp_param(name)) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
@@ -242,7 +253,7 @@
|
||||
/* - a selection sort */ \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(SORT, cont_oplist), M_EMPTY_P(cmp_arg)))( \
|
||||
/******** OPTIMIZED SORT FOR CONTAINER *********/ \
|
||||
static inline void M_C(name,sort_name)(container_t l) \
|
||||
M_INLINE void M_F(name,sort_name)(container_t l) \
|
||||
{ \
|
||||
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
|
||||
} \
|
||||
@@ -254,7 +265,7 @@
|
||||
\
|
||||
/* Split the container 'l' into near even size l1 and l2 * \
|
||||
using odd/even splitting */ \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(name,sort_name,_split)(container_t l1, container_t l2, container_t l) \
|
||||
{ \
|
||||
it_t it; \
|
||||
@@ -269,7 +280,7 @@
|
||||
} \
|
||||
\
|
||||
/* Merge in empty 'l' the sorted container 'l1' and 'l2' */ \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(name,sort_name,_merge)(container_t l, container_t l1, container_t l2 cmp_param(name)) \
|
||||
{ \
|
||||
/* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \
|
||||
@@ -309,8 +320,8 @@
|
||||
} \
|
||||
\
|
||||
/* Sort the container 'l' */ \
|
||||
static inline void \
|
||||
M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
M_INLINE void \
|
||||
M_F(name,sort_name)(container_t l cmp_param(name)) \
|
||||
{ \
|
||||
container_t l1; \
|
||||
container_t l2; \
|
||||
@@ -342,8 +353,8 @@
|
||||
M_CALL_INIT(cont_oplist, l1); \
|
||||
M_CALL_INIT(cont_oplist, l2); \
|
||||
M_C3(name,sort_name,_split)(l1, l2, l); \
|
||||
M_C(name,sort_name)(l1 cmp_arg); \
|
||||
M_C(name,sort_name)(l2 cmp_arg); \
|
||||
M_F(name,sort_name)(l1 cmp_arg); \
|
||||
M_F(name,sort_name)(l2 cmp_arg); \
|
||||
M_C3(name,sort_name,_merge)(l, l1, l2 cmp_arg); \
|
||||
/* l1 & l2 shall be empty now */ \
|
||||
M_CALL_CLEAR(cont_oplist, l2); \
|
||||
@@ -352,7 +363,7 @@
|
||||
, \
|
||||
M_IF_METHOD(IT_PREVIOUS, cont_oplist)( \
|
||||
/******** GENERIC INSERTION SORT *********/ \
|
||||
static inline void M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
M_INLINE void M_F(name,sort_name)(container_t l cmp_param(name)) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
@@ -389,7 +400,7 @@
|
||||
\
|
||||
, \
|
||||
/********** GENERIC SELECTION SORT ************/ \
|
||||
static inline void M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
M_INLINE void M_F(name,sort_name)(container_t l cmp_param(name)) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
@@ -422,7 +433,7 @@
|
||||
) /* IF SORT METHOD */ \
|
||||
/* Compute the union of two ***sorted*** containers */ \
|
||||
M_IF_METHOD(IT_INSERT, cont_oplist)( \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(name,sort_name,_union)(container_t dst, const container_t src cmp_param(name)) \
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
@@ -467,7 +478,7 @@
|
||||
\
|
||||
/* Compute the intersection of two ***sorted*** containers */ \
|
||||
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(name,sort_name,_intersect)(container_t dst, const container_t src cmp_param(name)) \
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
@@ -503,11 +514,11 @@
|
||||
TODO: Define _find_sorted that find in a sorted random access container
|
||||
(binary search)
|
||||
*/
|
||||
#define M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_FIND(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
/* It supposes that the container is not sorted */ \
|
||||
/* Find the next occurence from it (included) of data */ \
|
||||
static inline void \
|
||||
M_C(name, _find_again) (it_t it, type_t const data) \
|
||||
/* Find the next occurrence from it (included) of data */ \
|
||||
M_INLINE void \
|
||||
M_F(name, _find_again) (it_t it, type_t const data) \
|
||||
{ \
|
||||
for ( /*nothing*/ ; !M_CALL_IT_END_P(cont_oplist, it) ; \
|
||||
M_CALL_IT_NEXT(cont_oplist, it)) { \
|
||||
@@ -516,30 +527,30 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Find the first occurence of data */ \
|
||||
static inline void \
|
||||
M_C(name, _find) (it_t it, container_t const l, type_t const data) \
|
||||
/* Find the first occurrence of data */ \
|
||||
M_INLINE void \
|
||||
M_F(name, _find) (it_t it, container_t const l, type_t const data) \
|
||||
{ \
|
||||
M_CALL_IT_FIRST(cont_oplist, it, l); \
|
||||
M_C(name, _find_again)(it, data); \
|
||||
M_F(name, _find_again)(it, data); \
|
||||
} \
|
||||
\
|
||||
/* Test if data is within the container */ \
|
||||
static inline bool \
|
||||
M_C(name, _contain_p) (container_t const l, type_t const data) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _contain_p) (container_t const l, type_t const data) \
|
||||
{ \
|
||||
it_t it; \
|
||||
M_C(name,_find)(it, l, data); \
|
||||
M_F(name,_find)(it, l, data); \
|
||||
return !M_CALL_IT_END_P(cont_oplist, it); \
|
||||
} \
|
||||
\
|
||||
/* Find the last occurence of data in the container */ \
|
||||
/* Find the last occurrence of data in the container */ \
|
||||
/* For the definition of _find_last, if the methods \
|
||||
PREVIOUS & IT_LAST are defined, then search backwards */ \
|
||||
M_IF_METHOD2(PREVIOUS, IT_LAST, cont_oplist) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _find_last) (it_t it, container_t const l, type_t const data) \
|
||||
M_INLINE void \
|
||||
M_F(name, _find_last) (it_t it, container_t const l, type_t const data) \
|
||||
{ \
|
||||
for (M_CALL_IT_LAST(cont_oplist, it, l); \
|
||||
!M_CALL_IT_END_P(cont_oplist, it) ; \
|
||||
@@ -550,9 +561,9 @@
|
||||
} \
|
||||
} \
|
||||
, \
|
||||
/* Otherwise search forward, but don't stop on the first occurence */ \
|
||||
static inline void \
|
||||
M_C(name, _find_last) (it_t it, container_t const l, type_t const data) \
|
||||
/* Otherwise search forward, but don't stop on the first occurrence */ \
|
||||
M_INLINE void \
|
||||
M_F(name, _find_last) (it_t it, container_t const l, type_t const data) \
|
||||
{ \
|
||||
M_CALL_IT_END(cont_oplist, it, l); \
|
||||
it_t it2; \
|
||||
@@ -566,9 +577,9 @@
|
||||
} \
|
||||
) /* End of alternative of _find_last */ \
|
||||
\
|
||||
/* Count the number of occurence of data in the container */ \
|
||||
static inline size_t \
|
||||
M_C(name, _count) (container_t const l, type_t const data) \
|
||||
/* Count the number of occurrence of data in the container */ \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _count) (container_t const l, type_t const data) \
|
||||
{ \
|
||||
it_t it; \
|
||||
size_t count = 0; \
|
||||
@@ -583,8 +594,8 @@
|
||||
\
|
||||
\
|
||||
/* Find the next mismatch between the containers */ \
|
||||
static inline void \
|
||||
M_C(name, _mismatch_again) (it_t it1, it_t it2) \
|
||||
M_INLINE void \
|
||||
M_F(name, _mismatch_again) (it_t it1, it_t it2) \
|
||||
{ \
|
||||
for (/* nothing */ ; !M_CALL_IT_END_P(cont_oplist, it1) && \
|
||||
!M_CALL_IT_END_P(cont_oplist, it2); \
|
||||
@@ -597,12 +608,12 @@
|
||||
} \
|
||||
\
|
||||
/* Find the first mismatch between the containers */ \
|
||||
static inline void \
|
||||
M_C(name, _mismatch) (it_t it1, it_t it2, container_t const l1, container_t const l2 ) \
|
||||
M_INLINE void \
|
||||
M_F(name, _mismatch) (it_t it1, it_t it2, container_t const l1, container_t const l2 ) \
|
||||
{ \
|
||||
M_CALL_IT_FIRST(cont_oplist, it1, l1); \
|
||||
M_CALL_IT_FIRST(cont_oplist, it2, l2); \
|
||||
M_C(name, _mismatch_again)(it1, it2); \
|
||||
M_F(name, _mismatch_again)(it1, it2); \
|
||||
} \
|
||||
|
||||
|
||||
@@ -611,10 +622,10 @@
|
||||
TODO: Define _find_sorted that find in a sorted random access container
|
||||
(binary search)
|
||||
*/
|
||||
#define M_ALG0_FIND_IF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, test_t, eq_t, call_test, call_eq) \
|
||||
#define M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, test_t, eq_t, call_test, call_eq) \
|
||||
\
|
||||
/* Find the next occurence that matches the condition */ \
|
||||
static inline void \
|
||||
/* Find the next occurrence that matches the condition */ \
|
||||
M_INLINE void \
|
||||
M_C3(name, _find_again_, suffix) (it_t it, test_t func) \
|
||||
{ \
|
||||
for (/*nothing */ ; !M_CALL_IT_END_P(cont_oplist, it) ; \
|
||||
@@ -624,16 +635,16 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Find the first occurence that matches the condition */ \
|
||||
static inline void \
|
||||
/* Find the first occurrence that matches the condition */ \
|
||||
M_INLINE void \
|
||||
M_C3(name, _find_, suffix) (it_t it, container_t l, test_t func) \
|
||||
{ \
|
||||
M_CALL_IT_FIRST(cont_oplist, it, l); \
|
||||
M_C3(name, _find_again_, suffix)(it, func); \
|
||||
} \
|
||||
\
|
||||
/* Count the number of occurence that matches the condition */ \
|
||||
static inline size_t \
|
||||
/* Count the number of occurrence that matches the condition */ \
|
||||
M_INLINE size_t \
|
||||
M_C3(name, _count_, suffix) (container_t const l, test_t func) \
|
||||
{ \
|
||||
it_t it; \
|
||||
@@ -649,7 +660,7 @@
|
||||
} \
|
||||
\
|
||||
/* Find the next mismatch between the containers according to the condition */ \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(name, _mismatch_again_, suffix) (it_t it1, it_t it2, eq_t func) \
|
||||
{ \
|
||||
for (/*nothing */ ; !M_CALL_IT_END_P(cont_oplist, it1) && \
|
||||
@@ -663,7 +674,7 @@
|
||||
} \
|
||||
\
|
||||
/* Find the first mismatch between the containers according to the condition */ \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(name, _mismatch_, suffix) (it_t it1, it_t it2, container_t const l1, \
|
||||
container_t l2, eq_t func) \
|
||||
{ \
|
||||
@@ -674,21 +685,21 @@
|
||||
|
||||
|
||||
/* Define the FILL algorithms */
|
||||
#define M_ALG0_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
/* Fill all the container with value (overwritten) */ \
|
||||
static inline void \
|
||||
M_C(name, _fill) (container_t l, type_t const value) \
|
||||
M_INLINE void \
|
||||
M_F(name, _fill) (container_t l, type_t const value) \
|
||||
{ \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
M_CALL_SET(type_oplist, *item, value); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Fill the container with exactly 'n' occurence of 'value' */ \
|
||||
/* Fill the container with exactly 'n' occurrence of 'value' */ \
|
||||
M_IF_METHOD(PUSH, cont_oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _fill_n) (container_t l, size_t n, type_t const value) \
|
||||
M_INLINE void \
|
||||
M_F(name, _fill_n) (container_t l, size_t n, type_t const value) \
|
||||
{ \
|
||||
M_CALL_RESET(cont_oplist, l); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
@@ -699,8 +710,8 @@
|
||||
\
|
||||
/* Fill the container with FOR('value'; 'value'+'inc') */ \
|
||||
M_IF_METHOD(ADD, type_oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _fill_a) (container_t l, type_t const value, type_t const inc) \
|
||||
M_INLINE void \
|
||||
M_F(name, _fill_a) (container_t l, type_t const value, type_t const inc) \
|
||||
{ \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT_SET(type_oplist, tmp, value); \
|
||||
@@ -713,8 +724,8 @@
|
||||
\
|
||||
/* Fill the container with n occurences of FOR('value'; 'value'+'inc') */ \
|
||||
M_IF_METHOD(PUSH, cont_oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _fill_an) (container_t l, size_t n, type_t const value, type_t const inc) \
|
||||
M_INLINE void \
|
||||
M_F(name, _fill_an) (container_t l, size_t n, type_t const value, type_t const inc) \
|
||||
{ \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT_SET(type_oplist, tmp, value); \
|
||||
@@ -730,11 +741,11 @@
|
||||
|
||||
|
||||
/* Define MAP algorithms */
|
||||
#define M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_MAP(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
/* Apply func for all elements of the container */ \
|
||||
static inline void \
|
||||
M_C(name, _for_each) (container_t l, M_C(name, _apply_cb_ct) func) \
|
||||
M_INLINE void \
|
||||
M_F(name, _for_each) (container_t l, M_F(name, _apply_cb_ct) func) \
|
||||
{ \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
func(*item); \
|
||||
@@ -745,10 +756,10 @@
|
||||
M_IF_METHOD(PUSH_MOVE, cont_oplist)( \
|
||||
\
|
||||
/* Apply func for all elements of the container src and push the result in dst */ \
|
||||
static inline void \
|
||||
M_C(name, _transform) (container_t dst, \
|
||||
M_INLINE void \
|
||||
M_F(name, _transform) (container_t dst, \
|
||||
container_t src, \
|
||||
M_C(name, _transform_cb_ct) func) \
|
||||
M_F(name, _transform_cb_ct) func) \
|
||||
{ \
|
||||
M_ASSERT(dst != src); \
|
||||
M_CALL_RESET(cont_oplist, dst); \
|
||||
@@ -764,9 +775,9 @@
|
||||
\
|
||||
/* Reduce all elements of the container in dst in function of func */ \
|
||||
M_IF_METHOD(SET, type_oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _reduce) (type_t *dest, container_t const l, \
|
||||
M_C(name, _transform_cb_ct) func) \
|
||||
M_INLINE void \
|
||||
M_F(name, _reduce) (type_t *dest, container_t const l, \
|
||||
M_F(name, _transform_cb_ct) func) \
|
||||
{ \
|
||||
bool initDone = false; \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
@@ -782,11 +793,11 @@
|
||||
\
|
||||
/* Reduce all transformed elements of the container in dst in function of func */ \
|
||||
M_IF_METHOD(INIT, type_oplist)( \
|
||||
static inline \
|
||||
void M_C(name, _map_reduce) (type_t *dest, \
|
||||
M_INLINE \
|
||||
void M_F(name, _map_reduce) (type_t *dest, \
|
||||
const container_t l, \
|
||||
M_C(name, _transform_cb_ct) redFunc, \
|
||||
M_C(name, _transform_cb_ct) mapFunc) \
|
||||
M_F(name, _transform_cb_ct) redFunc, \
|
||||
M_F(name, _transform_cb_ct) mapFunc) \
|
||||
{ \
|
||||
bool initDone = false; \
|
||||
type_t tmp; \
|
||||
@@ -806,9 +817,9 @@
|
||||
|
||||
|
||||
/* Define ALL_OF algorithms */
|
||||
#define M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
|
||||
#define M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
|
||||
\
|
||||
static inline bool \
|
||||
M_INLINE bool \
|
||||
M_C4(name, _any_of, suffix, p) (container_t const l, \
|
||||
func_t func ) \
|
||||
{ \
|
||||
@@ -819,7 +830,7 @@
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_INLINE bool \
|
||||
M_C4(name, _all_of, suffix, p) (container_t const l, \
|
||||
func_t func ) \
|
||||
{ \
|
||||
@@ -830,7 +841,7 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_INLINE bool \
|
||||
M_C4(name, _none_of, suffix, p) (container_t l, \
|
||||
func_t func ) \
|
||||
{ \
|
||||
@@ -843,10 +854,10 @@
|
||||
|
||||
|
||||
/* Define MIN / MAX algorithms */
|
||||
#define M_ALG0_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_MINMAX(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline type_t * \
|
||||
M_C(name, _min) (const container_t l) \
|
||||
M_INLINE type_t * \
|
||||
M_F(name, _min) (const container_t l) \
|
||||
{ \
|
||||
type_t *min = NULL; \
|
||||
for M_EACH(cref, l, cont_oplist) { \
|
||||
@@ -858,8 +869,8 @@
|
||||
return min; \
|
||||
} \
|
||||
\
|
||||
static inline type_t * \
|
||||
M_C(name, _max) (const container_t l) \
|
||||
M_INLINE type_t * \
|
||||
M_F(name, _max) (const container_t l) \
|
||||
{ \
|
||||
type_t *max = NULL; \
|
||||
for M_EACH(cref, l, cont_oplist) { \
|
||||
@@ -871,8 +882,8 @@
|
||||
return max; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _minmax) (type_t **min_p, type_t **max_p, \
|
||||
M_INLINE void \
|
||||
M_F(name, _minmax) (type_t **min_p, type_t **max_p, \
|
||||
const container_t l) \
|
||||
{ \
|
||||
type_t *min = NULL; \
|
||||
@@ -891,15 +902,15 @@
|
||||
*max_p = max; \
|
||||
} \
|
||||
|
||||
|
||||
#define M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
/* Define functions based on remove method */
|
||||
#define M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _uniq)(container_t l) \
|
||||
M_INLINE void \
|
||||
M_F(name, _uniq)(container_t l) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
M_ASSERT(M_C(name, _sort_p)(l)); \
|
||||
M_ASSERT(M_F(name, _sort_p)(l)); \
|
||||
M_CALL_IT_FIRST(cont_oplist, it1, l); \
|
||||
M_CALL_IT_SET(cont_oplist, it2, it1); \
|
||||
M_CALL_IT_NEXT(cont_oplist, it2); \
|
||||
@@ -916,8 +927,8 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove_val)(container_t l, type_t const val) \
|
||||
M_INLINE void \
|
||||
M_F(name, _remove_val)(container_t l, type_t const val) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
M_CALL_IT_FIRST(cont_oplist, it1, l); \
|
||||
@@ -931,8 +942,8 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove_if)(container_t l, M_C(name, _test_cb_ct) func) \
|
||||
M_INLINE void \
|
||||
M_F(name, _remove_if)(container_t l, M_F(name, _test_cb_ct) func) \
|
||||
{ \
|
||||
it_t it1; \
|
||||
M_CALL_IT_FIRST(cont_oplist, it1, l); \
|
||||
@@ -946,11 +957,11 @@
|
||||
} \
|
||||
} \
|
||||
|
||||
|
||||
#define M_ALG0_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
/* Define vector algorithms */
|
||||
#define M_ALG0_DEF_VECTOR(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
M_IF_METHOD(ADD, type_oplist)( \
|
||||
static inline void M_C(name, _add) (container_t dst, const container_t src) \
|
||||
M_INLINE void M_F(name, _add) (container_t dst, const container_t src) \
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
it_t itDst; \
|
||||
@@ -961,14 +972,14 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_ADD(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
, /* NO_ADD METHOD */ ) \
|
||||
\
|
||||
M_IF_METHOD(SUB, type_oplist)( \
|
||||
static inline void M_C(name, _sub) (container_t dst, const container_t src) \
|
||||
M_INLINE void M_F(name, _sub) (container_t dst, const container_t src) \
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
it_t itDst; \
|
||||
@@ -979,14 +990,14 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_SUB(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
, /* NO_SUB METHOD */ ) \
|
||||
\
|
||||
M_IF_METHOD(MUL, type_oplist)( \
|
||||
static inline void M_C(name, _mul) (container_t dst, const container_t src) \
|
||||
M_INLINE void M_F(name, _mul) (container_t dst, const container_t src) \
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
it_t itDst; \
|
||||
@@ -997,14 +1008,14 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_MUL(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
, /* NO_MUL METHOD */ ) \
|
||||
\
|
||||
M_IF_METHOD(DIV, type_oplist)( \
|
||||
static inline void M_C(name, _div) (container_t dst, const container_t src) \
|
||||
M_INLINE void M_F(name, _div) (container_t dst, const container_t src) \
|
||||
{ \
|
||||
it_t itSrc; \
|
||||
it_t itDst; \
|
||||
@@ -1015,7 +1026,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc), \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
|
||||
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
|
||||
type_t const *srcItem = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
M_CALL_DIV(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -1030,6 +1041,7 @@
|
||||
// fast _uniq for array
|
||||
// _flatten (takes a set of containers and returns a new container containing all flatten objects)
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#define M_ALG0_FOR_EACH(container, cont_oplist, func) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
@@ -1044,6 +1056,8 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#define M_ALG0_TRANSFORM(contD, contDop, contS, contSop, func) do { \
|
||||
M_CALL_RESET(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
@@ -1067,8 +1081,11 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define M_ALG0_EXTRACT(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist) do { \
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#define M_ALG0_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist) \
|
||||
M_ALG0_EXTRACT_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist))
|
||||
#define M_ALG0_EXTRACT_P1(contDst, contDstOplist, contSrc, contSrcOplist) do{ \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
@@ -1080,8 +1097,9 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
#define M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, contSrc, contSrcOplist, condFunc) \
|
||||
M_ALG0_EXTRACT_FUNC_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), condFunc)
|
||||
#define M_ALG0_EXTRACT_FUNC_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
|
||||
condFunc) do { \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
@@ -1096,8 +1114,11 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define M_ALG0_EXTRACT_ARG(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
#define M_ALG0_EXTRACT_ARG(contDst, contDstOplist, contSrc, contSrcOplist, \
|
||||
condFunc, ...) \
|
||||
M_ALG0_EXTRACT_ARG_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), \
|
||||
condFunc, __VA_ARGS__)
|
||||
#define M_ALG0_EXTRACT_ARG_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
|
||||
condFunc, ...) do { \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
@@ -1113,6 +1134,8 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#define M_ALG0_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(M_ALG0_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
@@ -1188,6 +1211,8 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#define M_ALG0_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) do { \
|
||||
M_GET_IT_TYPE contSrcOp _itSrc; \
|
||||
M_GET_IT_TYPE contDstOp _itDst; \
|
||||
@@ -1200,4 +1225,16 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ALGO_DEF M_ALGO_DEF
|
||||
#define ALGO_FOR_EACH M_ALGO_FOR_EACH
|
||||
#define ALGO_TRANSFORM M_ALGO_TRANSFORM
|
||||
#define ALGO_EXTRACT M_ALGO_EXTRACT
|
||||
#define ALGO_REDUCE M_ALGO_REDUCE
|
||||
#define ALGO_INSERT_AT M_ALGO_INSERT_AT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -154,7 +154,7 @@ using std::memory_order_seq_cst;
|
||||
*/
|
||||
#else
|
||||
|
||||
#include "m-mutex.h"
|
||||
#include "m-thread.h"
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
@@ -226,7 +226,7 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||
#endif
|
||||
|
||||
/* (INTERNAL) Unlock the mutex and return the given value */
|
||||
static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
M_INLINE long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
{
|
||||
m_mutex_unlock (*lock);
|
||||
return val;
|
||||
@@ -332,4 +332,11 @@ M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
// C17 deprecated ATOMIC_VAR_INIT
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L
|
||||
# define M_ATOMIC_VAR_INIT(x) (x)
|
||||
#else
|
||||
# define M_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -34,7 +34,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Minimum number of nodes per group of nodes */
|
||||
#define M_CMEMP00L_MIN_NODE_PER_GROUP 16
|
||||
|
||||
#define C_MEMPOOL_DEF(name, type_t) \
|
||||
#define M_C_MEMPOOL_DEF(name, type_t) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
|
||||
M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
|
||||
@@ -46,55 +46,55 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Classic internal Singly List without allocation */
|
||||
#define M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _slist_node_s) { \
|
||||
struct M_C(name, _slist_node_s) *next; \
|
||||
typedef struct M_F(name, _slist_node_s) { \
|
||||
struct M_F(name, _slist_node_s) *next; \
|
||||
type_t data; \
|
||||
} M_C(name, _slist_node_ct); \
|
||||
} M_F(name, _slist_node_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _slist_node_s) *M_C(name, _slist_ct)[1]; \
|
||||
typedef struct M_F(name, _slist_node_s) *M_F(name, _slist_ct)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_init)(M_C(name, _slist_ct) list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _slist_init)(M_F(name, _slist_ct) list) \
|
||||
{ \
|
||||
*list = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_push)(M_C(name, _slist_ct) list, \
|
||||
M_C(name, _slist_node_ct) *node) \
|
||||
M_INLINE void \
|
||||
M_F(name, _slist_push)(M_F(name, _slist_ct) list, \
|
||||
M_F(name, _slist_node_ct) *node) \
|
||||
{ \
|
||||
node->next = *list; \
|
||||
*list = node; \
|
||||
} \
|
||||
\
|
||||
static inline M_C(name, _slist_node_ct) * \
|
||||
M_C(name, _slist_pop)(M_C(name, _slist_ct) list) \
|
||||
M_INLINE M_F(name, _slist_node_ct) * \
|
||||
M_F(name, _slist_pop)(M_F(name, _slist_ct) list) \
|
||||
{ \
|
||||
M_ASSERT (*list != NULL); \
|
||||
M_C(name, _slist_node_ct) *node = *list; \
|
||||
M_F(name, _slist_node_ct) *node = *list; \
|
||||
*list = node->next; \
|
||||
M_IF_DEBUG(node->next = NULL;) \
|
||||
return node; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _slist_empty_p)(M_C(name, _slist_ct) list) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _slist_empty_p)(M_F(name, _slist_ct) list) \
|
||||
{ \
|
||||
return *list == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_move)(M_C(name, _slist_ct) list, \
|
||||
M_C(name, _slist_ct) src) \
|
||||
M_INLINE void \
|
||||
M_F(name, _slist_move)(M_F(name, _slist_ct) list, \
|
||||
M_F(name, _slist_ct) src) \
|
||||
{ \
|
||||
*list = *src; \
|
||||
*src = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_clear)(M_C(name, _slist_ct) list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _slist_clear)(M_F(name, _slist_ct) list) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *it = *list, *next; \
|
||||
M_F(name, _slist_node_ct) *it = *list, *next; \
|
||||
while (it) { \
|
||||
next = it->next; \
|
||||
M_MEMORY_DEL(it); \
|
||||
@@ -125,41 +125,41 @@ M_BEGIN_PROTECTED_CODE
|
||||
to reduce memory consumption too (non compatible with C++ ...) */
|
||||
#define M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lf_node_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(struct M_C(name, _lf_node_s) *) next; \
|
||||
typedef struct M_F(name, _lf_node_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(struct M_F(name, _lf_node_s) *) next; \
|
||||
m_gc_atomic_ticket_ct cpt; \
|
||||
M_C(name, _slist_ct) list; \
|
||||
} M_C(name, _lf_node_t); \
|
||||
M_F(name, _slist_ct) list; \
|
||||
} M_F(name, _lf_node_t); \
|
||||
\
|
||||
typedef struct M_C(name, _lflist_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) head; \
|
||||
typedef struct M_F(name, _lflist_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) head; \
|
||||
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) tail; \
|
||||
M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) tail; \
|
||||
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
M_C(name, _lf_node_t) nil; \
|
||||
} M_C(name, _lflist_ct)[1]; \
|
||||
M_F(name, _lf_node_t) nil; \
|
||||
} M_F(name, _lflist_ct)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_init)(M_C(name, _lflist_ct) list, \
|
||||
M_C(name, _lf_node_t) *node) \
|
||||
M_INLINE void \
|
||||
M_F(name, _lflist_init)(M_F(name, _lflist_ct) list, \
|
||||
M_F(name, _lf_node_t) *node) \
|
||||
{ \
|
||||
atomic_init(&list->head, node); \
|
||||
atomic_init(&list->tail, node); \
|
||||
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _lflist_empty_p)(M_C(name, _lflist_ct) list) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _lflist_empty_p)(M_F(name, _lflist_ct) list) \
|
||||
{ \
|
||||
return atomic_load(&list->tail) == atomic_load(&list->head); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_push)(M_C(name, _lflist_ct) list, \
|
||||
M_C(name, _lf_node_t) *node, m_core_backoff_ct bkoff) \
|
||||
M_INLINE void \
|
||||
M_F(name, _lflist_push)(M_F(name, _lflist_ct) list, \
|
||||
M_F(name, _lf_node_t) *node, m_core_backoff_ct bkoff) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
M_F(name, _lf_node_t) *tail; \
|
||||
M_F(name, _lf_node_t) *next; \
|
||||
\
|
||||
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
|
||||
m_core_backoff_reset(bkoff); \
|
||||
@@ -190,12 +190,12 @@ M_BEGIN_PROTECTED_CODE
|
||||
memory_order_relaxed); \
|
||||
} \
|
||||
\
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _lflist_pop)(M_C(name, _lflist_ct) list, m_core_backoff_ct bkoff) \
|
||||
M_INLINE M_F(name, _lf_node_t) * \
|
||||
M_F(name, _lflist_pop)(M_F(name, _lflist_ct) list, m_core_backoff_ct bkoff) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *head; \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
M_F(name, _lf_node_t) *head; \
|
||||
M_F(name, _lf_node_t) *tail; \
|
||||
M_F(name, _lf_node_t) *next; \
|
||||
\
|
||||
/* Reinitialize backoff */ \
|
||||
m_core_backoff_reset(bkoff); \
|
||||
@@ -236,18 +236,18 @@ M_BEGIN_PROTECTED_CODE
|
||||
provided that the node we return is older than the one we should return, \
|
||||
Therefore, we return the previous dummy head. \
|
||||
As such, it is not the original MSqueue algorithm. */ \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \
|
||||
return head; \
|
||||
} \
|
||||
\
|
||||
/* Dequeue a node if the node is old enough */ \
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _lflist_pop_if)(M_C(name, _lflist_ct) list, \
|
||||
M_INLINE M_F(name, _lf_node_t) * \
|
||||
M_F(name, _lflist_pop_if)(M_F(name, _lflist_ct) list, \
|
||||
m_gc_ticket_ct age, m_core_backoff_ct bkoff) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *head; \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
M_F(name, _lf_node_t) *head; \
|
||||
M_F(name, _lf_node_t) *tail; \
|
||||
M_F(name, _lf_node_t) *next; \
|
||||
\
|
||||
m_core_backoff_reset(bkoff); \
|
||||
while (true) { \
|
||||
@@ -277,28 +277,28 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \
|
||||
return head; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_clear)(M_C(name, _lflist_ct) list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _lflist_clear)(M_F(name, _lflist_ct) list) \
|
||||
{ \
|
||||
m_core_backoff_ct bkoff; \
|
||||
m_core_backoff_init(bkoff); \
|
||||
while (true) { \
|
||||
M_C(name, _lf_node_t) *node = M_C(name, _lflist_pop)(list, bkoff); \
|
||||
M_F(name, _lf_node_t) *node = M_F(name, _lflist_pop)(list, bkoff); \
|
||||
if (node == NULL) break; \
|
||||
M_C(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
|
||||
M_F(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
|
||||
memory_order_relaxed); \
|
||||
M_C(name, _slist_clear)(node->list); \
|
||||
M_F(name, _slist_clear)(node->list); \
|
||||
M_MEMORY_DEL(node); \
|
||||
node = next; \
|
||||
} \
|
||||
/* Dummy node to free too */ \
|
||||
M_C(name, _lf_node_t) *dummy; \
|
||||
M_F(name, _lf_node_t) *dummy; \
|
||||
dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \
|
||||
M_C(name, _slist_clear)(dummy->list); \
|
||||
M_F(name, _slist_clear)(dummy->list); \
|
||||
M_MEMORY_DEL(dummy); \
|
||||
} \
|
||||
|
||||
@@ -306,26 +306,26 @@ M_BEGIN_PROTECTED_CODE
|
||||
As such it is a non Lock-Free path. */
|
||||
#define M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
\
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _alloc_node)(unsigned int initial) \
|
||||
M_INLINE M_F(name, _lf_node_t) * \
|
||||
M_F(name, _alloc_node)(unsigned int initial) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) * node; \
|
||||
node = M_MEMORY_ALLOC(M_C(name, _lf_node_t)); \
|
||||
if (M_UNLIKELY(node == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
|
||||
M_F(name, _lf_node_t) * node; \
|
||||
node = M_MEMORY_ALLOC(M_F(name, _lf_node_t)); \
|
||||
if (M_UNLIKELY_NOMEM (node == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \
|
||||
return NULL; \
|
||||
} \
|
||||
atomic_init(&node->next, (M_C(name, _lf_node_t) *) 0); \
|
||||
atomic_init(&node->next, (M_F(name, _lf_node_t) *) 0); \
|
||||
atomic_init(&node->cpt, 0UL); \
|
||||
M_C(name, _slist_init)(node->list); \
|
||||
M_F(name, _slist_init)(node->list); \
|
||||
for(unsigned i = 0; i < initial; i++) { \
|
||||
M_C(name, _slist_node_ct) *n; \
|
||||
n = M_MEMORY_ALLOC(M_C(name, _slist_node_ct)); \
|
||||
if (M_UNLIKELY(n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
|
||||
M_F(name, _slist_node_ct) *n; \
|
||||
n = M_MEMORY_ALLOC(M_F(name, _slist_node_ct)); \
|
||||
if (M_UNLIKELY_NOMEM (n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_C(name, _slist_push)(node->list, n); \
|
||||
M_F(name, _slist_push)(node->list, n); \
|
||||
} \
|
||||
return node; \
|
||||
} \
|
||||
@@ -388,99 +388,99 @@ M_BEGIN_PROTECTED_CODE
|
||||
*/
|
||||
#define M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lfmp_thread_s) { \
|
||||
M_C(name, _slist_ct) free; \
|
||||
M_C(name, _slist_ct) to_be_reclaimed; \
|
||||
M_CACHELINE_ALIGN(align1, M_C(name, _slist_ct), M_C(name, _slist_ct)); \
|
||||
} M_C(name, _lfmp_thread_ct); \
|
||||
typedef struct M_F(name, _lfmp_thread_s) { \
|
||||
M_F(name, _slist_ct) free; \
|
||||
M_F(name, _slist_ct) to_be_reclaimed; \
|
||||
M_CACHELINE_ALIGN(align1, M_F(name, _slist_ct), M_F(name, _slist_ct)); \
|
||||
} M_F(name, _lfmp_thread_ct); \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lfmp_thread_init)(M_C(name, _lfmp_thread_ct) *t) \
|
||||
M_INLINE void \
|
||||
M_F(name, _lfmp_thread_init)(M_F(name, _lfmp_thread_ct) *t) \
|
||||
{ \
|
||||
M_C(name, _slist_init)(t->free); \
|
||||
M_C(name, _slist_init)(t->to_be_reclaimed); \
|
||||
M_F(name, _slist_init)(t->free); \
|
||||
M_F(name, _slist_init)(t->to_be_reclaimed); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lfmp_thread_clear)(M_C(name, _lfmp_thread_ct) *t) \
|
||||
M_INLINE void \
|
||||
M_F(name, _lfmp_thread_clear)(M_F(name, _lfmp_thread_ct) *t) \
|
||||
{ \
|
||||
M_ASSERT(M_C(name, _slist_empty_p)(t->to_be_reclaimed)); \
|
||||
M_C(name, _slist_clear)(t->free); \
|
||||
M_C(name, _slist_clear)(t->to_be_reclaimed); \
|
||||
M_ASSERT(M_F(name, _slist_empty_p)(t->to_be_reclaimed)); \
|
||||
M_F(name, _slist_clear)(t->free); \
|
||||
M_F(name, _slist_clear)(t->to_be_reclaimed); \
|
||||
} \
|
||||
|
||||
/* NOTE: once a node is deleted, its data are kept readable until the future GC */
|
||||
#define M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
typedef struct M_F(name, _s) { \
|
||||
unsigned initial; \
|
||||
M_C(name, _lfmp_thread_ct) *thread_data; \
|
||||
M_C(name, _lflist_ct) free; \
|
||||
M_C(name, _lflist_ct) to_be_reclaimed; \
|
||||
M_C(name, _lflist_ct) empty; \
|
||||
m_gM_CMEMP00L_list_ct mempool_node; \
|
||||
M_F(name, _lfmp_thread_ct) *thread_data; \
|
||||
M_F(name, _lflist_ct) free; \
|
||||
M_F(name, _lflist_ct) to_be_reclaimed; \
|
||||
M_F(name, _lflist_ct) empty; \
|
||||
m_cmemp00l_list_ct mempool_node; \
|
||||
struct m_gc_s *gc_mem; \
|
||||
} M_C(name, _t)[1]; \
|
||||
} M_F(name, _t)[1]; \
|
||||
\
|
||||
/* Garbage collect of the nodes of the mempool on sleep */ \
|
||||
static inline void \
|
||||
M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data, \
|
||||
M_INLINE void \
|
||||
M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_cmemp00l_list_ct *data, \
|
||||
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) \
|
||||
{ \
|
||||
/* Get back the mempool from the node */ \
|
||||
struct M_C(name, _s) *mempool = \
|
||||
M_TYPE_FROM_FIELD(struct M_C(name, _s), data, m_gM_CMEMP00L_list_ct, mempool_node); \
|
||||
struct M_F(name, _s) *mempool = \
|
||||
M_TYPE_FROM_FIELD(struct M_F(name, _s), data, m_cmemp00l_list_ct, mempool_node); \
|
||||
\
|
||||
/* Move the local nodes of the mempool to be reclaimed to the thread into the global pool */ \
|
||||
if (!M_C(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
if (!M_F(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \
|
||||
M_F(name, _lf_node_t) *node; \
|
||||
/* Get a new empty group of nodes */ \
|
||||
node = M_C(name, _lflist_pop)(mempool->empty, gc_mem->thread_data[id].bkoff); \
|
||||
node = M_F(name, _lflist_pop)(mempool->empty, gc_mem->thread_data[id].bkoff); \
|
||||
if (M_UNLIKELY (node == NULL)) { \
|
||||
/* Fail to get an empty group of node. \
|
||||
Alloc a new one from the system */ \
|
||||
node = M_C(name, _alloc_node)(0); \
|
||||
node = M_F(name, _alloc_node)(0); \
|
||||
M_ASSERT(node != NULL); \
|
||||
} \
|
||||
M_ASSERT(M_C(name, _slist_empty_p)(node->list)); \
|
||||
M_C(name, _slist_move)(node->list, mempool->thread_data[id].to_be_reclaimed); \
|
||||
M_ASSERT(M_F(name, _slist_empty_p)(node->list)); \
|
||||
M_F(name, _slist_move)(node->list, mempool->thread_data[id].to_be_reclaimed); \
|
||||
atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed); \
|
||||
M_C(name, _lflist_push)(mempool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); \
|
||||
M_F(name, _lflist_push)(mempool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); \
|
||||
} \
|
||||
\
|
||||
/* Perform a GC of the freelist of nodes */ \
|
||||
while (true) { \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
node = M_C(name, _lflist_pop_if)(mempool->to_be_reclaimed, \
|
||||
M_F(name, _lf_node_t) *node; \
|
||||
node = M_F(name, _lflist_pop_if)(mempool->to_be_reclaimed, \
|
||||
min_ticket, gc_mem->thread_data[id].bkoff); \
|
||||
if (node == NULL) break; \
|
||||
M_C(name, _lflist_push)(mempool->free, node, gc_mem->thread_data[id].bkoff); \
|
||||
M_F(name, _lflist_push)(mempool->free, node, gc_mem->thread_data[id].bkoff); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) mem, m_gc_t gc_mem, \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(M_F(name, _t) mem, m_gc_t gc_mem, \
|
||||
unsigned init_node_count, unsigned init_group_count) \
|
||||
{ \
|
||||
const size_t max_thread = gc_mem->max_thread; \
|
||||
/* Initialize the thread data of the mempool */ \
|
||||
mem->thread_data = M_MEMORY_REALLOC(M_C(name, _lfmp_thread_ct), NULL, max_thread); \
|
||||
if (mem->thread_data == NULL) { \
|
||||
M_MEMORY_FULL(max_thread * sizeof(M_C(name, _lfmp_thread_ct))); \
|
||||
mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, max_thread); \
|
||||
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \
|
||||
M_MEMORY_FULL(max_thread * sizeof(M_F(name, _lfmp_thread_ct))); \
|
||||
return; \
|
||||
} \
|
||||
for(unsigned i = 0; i < max_thread;i++) { \
|
||||
M_C(name, _lfmp_thread_init)(&mem->thread_data[i]); \
|
||||
M_F(name, _lfmp_thread_init)(&mem->thread_data[i]); \
|
||||
} \
|
||||
/* Preallocate some group of nodes for the mempool */ \
|
||||
mem->initial = M_MAX(M_CMEMP00L_MIN_NODE_PER_GROUP, init_node_count); \
|
||||
M_C(name, _lflist_init)(mem->free, M_C(name, _alloc_node)(init_node_count)); \
|
||||
M_C(name, _lflist_init)(mem->to_be_reclaimed, M_C(name, _alloc_node)(init_node_count)); \
|
||||
M_C(name, _lflist_init)(mem->empty, M_C(name, _alloc_node)(0)); \
|
||||
M_F(name, _lflist_init)(mem->free, M_F(name, _alloc_node)(init_node_count)); \
|
||||
M_F(name, _lflist_init)(mem->to_be_reclaimed, M_F(name, _alloc_node)(init_node_count)); \
|
||||
M_F(name, _lflist_init)(mem->empty, M_F(name, _alloc_node)(0)); \
|
||||
for(unsigned i = 1; i < init_group_count; i++) { \
|
||||
M_C(name, _lflist_push)(mem->free, M_C(name, _alloc_node)(init_node_count), \
|
||||
M_F(name, _lflist_push)(mem->free, M_F(name, _alloc_node)(init_node_count), \
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
M_C(name, _lflist_push)(mem->empty, M_C(name, _alloc_node)(0), \
|
||||
M_F(name, _lflist_push)(mem->empty, M_F(name, _alloc_node)(0), \
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
} \
|
||||
/* Register the mempool in the GC */ \
|
||||
@@ -490,56 +490,56 @@ M_BEGIN_PROTECTED_CODE
|
||||
mem->gc_mem = gc_mem; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) mem) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(M_F(name, _t) mem) \
|
||||
{ \
|
||||
const unsigned max_thread = mem->gc_mem->max_thread; \
|
||||
for(unsigned i = 0; i < max_thread;i++) { \
|
||||
M_C(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
|
||||
M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
|
||||
} \
|
||||
M_MEMORY_FREE(mem->thread_data); \
|
||||
mem->thread_data = NULL; \
|
||||
M_C(name, _lflist_clear)(mem->empty); \
|
||||
M_C(name, _lflist_clear)(mem->free); \
|
||||
M_ASSERT(M_C(name, _lflist_empty_p)(mem->to_be_reclaimed)); \
|
||||
M_C(name, _lflist_clear)(mem->to_be_reclaimed); \
|
||||
M_F(name, _lflist_clear)(mem->empty); \
|
||||
M_F(name, _lflist_clear)(mem->free); \
|
||||
M_ASSERT(M_F(name, _lflist_empty_p)(mem->to_be_reclaimed)); \
|
||||
M_F(name, _lflist_clear)(mem->to_be_reclaimed); \
|
||||
/* TODO: Unregister from the GC? */ \
|
||||
} \
|
||||
\
|
||||
static inline type_t * \
|
||||
M_C(name, _new)(M_C(name, _t) mem, m_gc_tid_t id) \
|
||||
M_INLINE type_t * \
|
||||
M_F(name, _new)(M_F(name, _t) mem, m_gc_tid_t id) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *snode; \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
M_F(name, _slist_node_ct) *snode; \
|
||||
M_F(name, _lf_node_t) *node; \
|
||||
while (true) { \
|
||||
/* Fast & likely path where we access the thread pool of nodes */ \
|
||||
if (M_LIKELY(!M_C(name, _slist_empty_p)(mem->thread_data[id].free))) { \
|
||||
snode = M_C(name, _slist_pop)(mem->thread_data[id].free); \
|
||||
if (M_LIKELY(!M_F(name, _slist_empty_p)(mem->thread_data[id].free))) { \
|
||||
snode = M_F(name, _slist_pop)(mem->thread_data[id].free); \
|
||||
return &snode->data; \
|
||||
} \
|
||||
/* Request a group node to the freelist of groups */ \
|
||||
node = M_C(name, _lflist_pop)(mem->free, mem->gc_mem->thread_data[id].bkoff); \
|
||||
node = M_F(name, _lflist_pop)(mem->free, mem->gc_mem->thread_data[id].bkoff); \
|
||||
if (M_UNLIKELY (node == NULL)) { \
|
||||
/* Request a new group to the system. Non Lock Free path */ \
|
||||
M_ASSERT(mem->initial > 0); \
|
||||
node = M_C(name, _alloc_node)(mem->initial); \
|
||||
node = M_F(name, _alloc_node)(mem->initial); \
|
||||
M_ASSERT(node != NULL); \
|
||||
M_ASSERT(!M_C(name, _slist_empty_p)(node->list)); \
|
||||
M_ASSERT(!M_F(name, _slist_empty_p)(node->list)); \
|
||||
} \
|
||||
M_C(name, _slist_move)(mem->thread_data[id].free, node->list); \
|
||||
M_F(name, _slist_move)(mem->thread_data[id].free, node->list); \
|
||||
/* Push back the empty group */ \
|
||||
M_ASSERT (M_C(name, _slist_empty_p)(node->list)); \
|
||||
M_C(name, _lflist_push)(mem->empty, node, mem->gc_mem->thread_data[id].bkoff); \
|
||||
M_ASSERT (M_F(name, _slist_empty_p)(node->list)); \
|
||||
M_F(name, _lflist_push)(mem->empty, node, mem->gc_mem->thread_data[id].bkoff); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _del)(M_C(name, _t) mem, type_t *d, m_gc_tid_t id) \
|
||||
M_INLINE void \
|
||||
M_F(name, _del)(M_F(name, _t) mem, type_t *d, m_gc_tid_t id) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *snode; \
|
||||
M_F(name, _slist_node_ct) *snode; \
|
||||
M_ASSERT( d != NULL); \
|
||||
snode = M_TYPE_FROM_FIELD(M_C(name, _slist_node_ct), d, type_t, data); \
|
||||
M_C(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \
|
||||
snode = M_TYPE_FROM_FIELD(M_F(name, _slist_node_ct), d, type_t, data); \
|
||||
M_F(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \
|
||||
} \
|
||||
|
||||
|
||||
@@ -555,13 +555,13 @@ typedef atomic_ulong m_gc_atomic_ticket_ct;
|
||||
|
||||
/* Define the Linked List of mempools that are registered in the GC */
|
||||
struct m_gc_s;
|
||||
typedef struct m_gM_CMEMP00L_list_s {
|
||||
struct m_gM_CMEMP00L_list_s *next;
|
||||
typedef struct m_cmemp00l_list_s {
|
||||
struct m_cmemp00l_list_s *next;
|
||||
void (*gc_on_sleep)(struct m_gc_s *gc_mem,
|
||||
struct m_gM_CMEMP00L_list_s *data, m_gc_tid_t id,
|
||||
struct m_cmemp00l_list_s *data, m_gc_tid_t id,
|
||||
m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket);
|
||||
void *data;
|
||||
} m_gM_CMEMP00L_list_ct;
|
||||
} m_cmemp00l_list_ct;
|
||||
|
||||
/* Define the Garbage collector thread data */
|
||||
typedef struct m_gc_lfmp_thread_s {
|
||||
@@ -574,21 +574,21 @@ typedef struct m_gc_lfmp_thread_s {
|
||||
typedef struct m_gc_s {
|
||||
m_gc_atomic_ticket_ct ticket;
|
||||
m_gc_tid_t max_thread;
|
||||
genint_t thread_alloc;
|
||||
m_genint_t thread_alloc;
|
||||
m_gc_lfmp_thread_ct *thread_data;
|
||||
m_gM_CMEMP00L_list_ct *mempool_list;
|
||||
m_cmemp00l_list_ct *mempool_list;
|
||||
} m_gc_t[1];
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_gc_init(m_gc_t gc_mem, size_t max_thread)
|
||||
{
|
||||
M_ASSERT(gc_mem != NULL);
|
||||
M_ASSERT(max_thread > 0 && max_thread < INT_MAX);
|
||||
|
||||
atomic_init(&gc_mem->ticket, 0UL);
|
||||
genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
|
||||
m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
|
||||
gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, max_thread);
|
||||
if (gc_mem->thread_data == NULL) {
|
||||
if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) {
|
||||
M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct));
|
||||
return;
|
||||
}
|
||||
@@ -600,7 +600,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread)
|
||||
gc_mem->mempool_list = NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_gc_clear(m_gc_t gc_mem)
|
||||
{
|
||||
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
|
||||
@@ -610,29 +610,29 @@ m_gc_clear(m_gc_t gc_mem)
|
||||
}
|
||||
M_MEMORY_FREE(gc_mem->thread_data);
|
||||
gc_mem->thread_data = NULL;
|
||||
genint_clear(gc_mem->thread_alloc);
|
||||
m_genint_clear(gc_mem->thread_alloc);
|
||||
}
|
||||
|
||||
static inline m_gc_tid_t
|
||||
M_INLINE m_gc_tid_t
|
||||
m_gc_attach_thread(m_gc_t gc_mem)
|
||||
{
|
||||
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
|
||||
|
||||
unsigned id = genint_pop(gc_mem->thread_alloc);
|
||||
unsigned id = m_genint_pop(gc_mem->thread_alloc);
|
||||
return M_ASSIGN_CAST(m_gc_tid_t, id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
{
|
||||
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
|
||||
M_ASSERT(id < gc_mem->max_thread);
|
||||
M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX);
|
||||
|
||||
genint_push(gc_mem->thread_alloc, id);
|
||||
m_genint_push(gc_mem->thread_alloc, id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
{
|
||||
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
|
||||
@@ -643,7 +643,7 @@ m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
atomic_store(&gc_mem->thread_data[id].ticket, t);
|
||||
}
|
||||
|
||||
static inline m_gc_ticket_ct
|
||||
M_INLINE m_gc_ticket_ct
|
||||
m_cmemp00l_gc_min_ticket(m_gc_t gc_mem)
|
||||
{
|
||||
m_gc_ticket_ct min = atomic_load(&gc_mem->thread_data[0].ticket);
|
||||
@@ -654,7 +654,7 @@ m_cmemp00l_gc_min_ticket(m_gc_t gc_mem)
|
||||
return min;
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
{
|
||||
/* Increase life time of the thread */
|
||||
@@ -662,7 +662,7 @@ m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
atomic_store(&gc_mem->thread_data[id].ticket, t+1);
|
||||
const m_gc_ticket_ct min_ticket = m_cmemp00l_gc_min_ticket(gc_mem);
|
||||
/* Iterate over all registered mempools */
|
||||
m_gM_CMEMP00L_list_ct *it = gc_mem->mempool_list;
|
||||
m_cmemp00l_list_ct *it = gc_mem->mempool_list;
|
||||
|
||||
while (it) {
|
||||
/* Perform a garbage collect of the mempool */
|
||||
@@ -690,13 +690,13 @@ typedef struct m_vlapool_lfmp_thread_s {
|
||||
M_CACHELINE_ALIGN(align1, m_vlapool_slist_ct);
|
||||
} m_vlapool_lfmp_thread_ct;
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_vlapool_lfmp_thread_init(m_vlapool_lfmp_thread_ct *t)
|
||||
{
|
||||
m_vlapool_slist_init(t->to_be_reclaimed);
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_vlapool_lfmp_thread_clear(m_vlapool_lfmp_thread_ct *t)
|
||||
{
|
||||
M_ASSERT(m_vlapool_slist_empty_p(t->to_be_reclaimed));
|
||||
@@ -707,18 +707,18 @@ typedef struct m_vlapool_s {
|
||||
m_vlapool_lflist_ct to_be_reclaimed;
|
||||
m_vlapool_lflist_ct empty;
|
||||
m_vlapool_lfmp_thread_ct *thread_data;
|
||||
m_gM_CMEMP00L_list_ct mvla_node;
|
||||
m_cmemp00l_list_ct mvla_node;
|
||||
struct m_gc_s *gc_mem;
|
||||
} m_vlapool_t[1];
|
||||
|
||||
/* Garbage collect of the nodes of the vla mempool on sleep */
|
||||
static inline void
|
||||
m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data,
|
||||
M_INLINE void
|
||||
m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_cmemp00l_list_ct *data,
|
||||
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket)
|
||||
{
|
||||
/* Get back the mempool from the node */
|
||||
struct m_vlapool_s *vlapool =
|
||||
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_gM_CMEMP00L_list_ct, mvla_node);
|
||||
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_cmemp00l_list_ct, mvla_node);
|
||||
|
||||
/* Move the local nodes of the vlapool to be reclaimed to the thread into the global pool */
|
||||
if (!m_vlapool_slist_empty_p(vlapool->thread_data[id].to_be_reclaimed)) {
|
||||
@@ -751,14 +751,14 @@ m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_gM_CMEMP00L_list_ct *data,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
|
||||
{
|
||||
const size_t max_thread = gc_mem->max_thread;
|
||||
|
||||
/* Initialize the thread data of the vlapool */
|
||||
mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, max_thread);
|
||||
if (mem->thread_data == NULL) {
|
||||
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) {
|
||||
M_MEMORY_FULL(max_thread * sizeof(m_vlapool_lfmp_thread_ct));
|
||||
return;
|
||||
}
|
||||
@@ -777,7 +777,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
|
||||
mem->gc_mem = gc_mem;
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_vlapool_clear(m_vlapool_t mem)
|
||||
{
|
||||
const unsigned max_thread = mem->gc_mem->max_thread;
|
||||
@@ -792,7 +792,7 @@ m_vlapool_clear(m_vlapool_t mem)
|
||||
/* TODO: Unregister from the GC? */
|
||||
}
|
||||
|
||||
static inline void *
|
||||
M_INLINE void *
|
||||
m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size)
|
||||
{
|
||||
M_ASSERT(mem != NULL && mem->gc_mem != NULL);
|
||||
@@ -811,7 +811,7 @@ m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size)
|
||||
return (ptr == NULL) ? NULL : M_ASSIGN_CAST(void *, ptr + offsetof(struct m_vlapool_slist_node_s, data));
|
||||
}
|
||||
|
||||
static inline void
|
||||
M_INLINE void
|
||||
m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
|
||||
{
|
||||
M_ASSERT(mem != NULL && mem->gc_mem != NULL);
|
||||
@@ -828,4 +828,8 @@ m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define C_MEMPOOL_DEF M_C_MEMPOOL_DEF
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Function Object module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -32,8 +32,8 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
FUNC_OBJ_ITF_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_FUNC_OBJ_ITF_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object interface of name 'name'
|
||||
@@ -41,7 +41,7 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF_AS(name, name_t, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
#define M_FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_ITF_NO_PARAM_DEF, M_FUNC0BJ_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -65,8 +65,8 @@
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF(name, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
FUNC_OBJ_INS_DEF_AS(name, M_C(name,_t), base_name, param_list, __VA_ARGS__)
|
||||
#define M_FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_FUNC_OBJ_INS_DEF_AS(name, M_F(name,_t), base_name, param_list, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object instance of name 'name' based on the interface 'base_name'
|
||||
@@ -76,7 +76,7 @@
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
#define M_FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_INS_NO_ATTR_DEF, M_FUNC0BJ_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -86,19 +86,19 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
#define M_FUNC_OBJ_INS_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(M_FUNC0BJ_INS_NO_ATTR_OPLIST, M_FUNC0BJ_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************** INTERNAL ************************************/
|
||||
/********************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/******************************** INTERNAL ***********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/* To be used by M_IF_FUNCOBJ macro defined in m-core.
|
||||
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliabely.
|
||||
*/
|
||||
#define M_FUNCOBJ_IS_NOT_DEFINED 0
|
||||
#define M_FUNC0BJ_IS_NOT_DEFINED 0
|
||||
|
||||
/* Design Constraints:
|
||||
* callback SHALL be the first member of the structures in all the definitions.
|
||||
@@ -111,9 +111,9 @@
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
#define M_FUNC0BJ_INS_NO_ATTR_OPLIST(name) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT(M_C(name,_init)) \
|
||||
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
INIT(M_F(name,_init)) \
|
||||
)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
@@ -127,40 +127,42 @@
|
||||
/* Define the oplist of the instance */
|
||||
#define M_FUNC0BJ_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
INIT_WITH(M_C(name, _init_with)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
INIT_WITH(M_F(name, _init_with)), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_F(name,_init)),), \
|
||||
PROPERTIES(( LET_AS_INIT_WITH(1) )) \
|
||||
)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
/* Specialization of the definition a function object interface of name 'name'
|
||||
* with a function like "retcode (void)" that doesn't have any input parameters.
|
||||
* Define the following types to be used by instance:
|
||||
* - M_C(name, _retcode_ct): internal type of the return code
|
||||
* - M_C(name, _callback_ct): internal type of the callback.
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
* - M_F(name, _retcode_ct): internal type of the return code
|
||||
* - M_F(name, _callback_ct): internal type of the callback.
|
||||
* - M_F(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define M_FUNC0BJ_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
struct M_F(name, _s); \
|
||||
\
|
||||
/* Internal type for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
typedef retcode M_F(name, _retcode_ct); \
|
||||
/* No parameters to the callback */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *); \
|
||||
typedef retcode(*M_F(name, _callback_ct))(struct M_F(name, _s) *); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _callback_ct) callback; \
|
||||
} *interface_t; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
typedef interface_t M_F(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj) \
|
||||
M_INLINE retcode \
|
||||
M_F(name, _call)(interface_t funcobj) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj); \
|
||||
@@ -171,32 +173,32 @@
|
||||
* with a function like retcode, type of param1, type of param 2, ...
|
||||
* with mandatory input parameters.
|
||||
* Define the following types to be used by instance:
|
||||
* - M_C(name, _retcode_ct): internal type of the return code
|
||||
* - M_C(name, _callback_ct): internal type of the callback.
|
||||
* - M_F(name, _retcode_ct): internal type of the return code
|
||||
* - M_F(name, _callback_ct): internal type of the callback.
|
||||
* - M_C4(name, _param_, num, _ct) for each parameter defined
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
* - M_F(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define M_FUNC0BJ_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
struct M_F(name, _s); \
|
||||
\
|
||||
/* Internal types for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
typedef retcode M_F(name, _retcode_ct); \
|
||||
/* Define types for all parameters */ \
|
||||
M_MAP3(M_FUNC0BJ_BASE_TYPE, name, __VA_ARGS__) \
|
||||
/* Define callback type with all parameters */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *, __VA_ARGS__); \
|
||||
typedef retcode(*M_F(name, _callback_ct))(struct M_F(name, _s) *, __VA_ARGS__); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _callback_ct) callback; \
|
||||
} *interface_t; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
typedef interface_t M_F(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj \
|
||||
M_INLINE retcode \
|
||||
M_F(name, _call)(interface_t funcobj \
|
||||
M_MAP3(M_FUNC0BJ_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
/* If the retcode is 'void', don't return the value of the callback */ \
|
||||
@@ -205,52 +207,54 @@
|
||||
}
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
/* Specialization of the definition a function object instance of name 'name'
|
||||
* with no member attribute.
|
||||
*/
|
||||
#define M_FUNC0BJ_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
typedef instance_t M_F(name, _ct); \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_INLINE M_C(base_name, _retcode_ct) \
|
||||
M_F(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(M_FUNC0BJ_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
struct M_F(name, _s) *self = (struct M_F(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_with)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
obj->callback = M_F(name, _callback); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
(void) obj; /* nothing to do */ \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
M_INLINE struct M_C(base_name, _s) * \
|
||||
M_F(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
obj->callback = M_F(name, _callback); \
|
||||
} \
|
||||
|
||||
|
||||
@@ -266,7 +270,7 @@
|
||||
M_MAP_C(M_FUNC0BJ_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
|
||||
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
|
||||
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
|
||||
or (x, type, M_BASIC_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define M_FUNC0BJ_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_FUNC0BJ_INJECT_OPLIST_B duo_or_trio
|
||||
@@ -290,7 +294,7 @@
|
||||
|
||||
/* Expand the Function Object with members */
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
typedef struct M_F(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
@@ -298,48 +302,50 @@
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
typedef instance_t M_F(name, _ct); \
|
||||
\
|
||||
M_FUNC0BJ_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_INLINE M_C(base_name, _retcode_ct) \
|
||||
M_F(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(M_FUNC0BJ_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)(void*)_self; \
|
||||
/* Let's go through an uintptr_t to avoid [broken] aliasing detection by compiler */ \
|
||||
uintptr_t __self = (uintptr_t) _self; \
|
||||
struct M_F(name, _s) *self = (struct M_F(name, _s) *)(void*)__self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj M_MAP(M_FUNC0BJ_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_with)(instance_t obj M_MAP(M_FUNC0BJ_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
obj->callback = M_F(name, _callback); \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
M_INLINE struct M_C(base_name, _s) * \
|
||||
M_F(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(M_FUNC0BJ_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
obj->callback = M_F(name, _callback); \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
} \
|
||||
, /* END OF INIT METHOD */ ) \
|
||||
@@ -396,4 +402,14 @@
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define FUNC_OBJ_ITF_DEF M_FUNC_OBJ_ITF_DEF
|
||||
#define FUNC_OBJ_ITF_DEF_AS M_FUNC_OBJ_ITF_DEF_AS
|
||||
#define FUNC_OBJ_INS_DEF M_FUNC_OBJ_INS_DEF
|
||||
#define FUNC_OBJ_INS_DEF_AS M_FUNC_OBJ_INS_DEF_AS
|
||||
#define FUNC_OBJ_INS_OPLIST M_FUNC_OBJ_INS_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* M*LIB - Generic module
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MSTARLIB_GENERIC_H
|
||||
#define MSTARLIB_GENERIC_H
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Define the generic macro-functions */
|
||||
// TODO: m_ prefix?
|
||||
#define init(x) M_G3N_CALL_1(INIT, x)
|
||||
#define init_set(x, y) M_G3N_CALL_2(INIT_SET, x, TYPE, x, TYPE, y)
|
||||
#define init_move(x, y) M_G3N_CALL_2(INIT_MOVE, x, TYPE, x, TYPE, y)
|
||||
#define move(x, y) M_G3N_CALL_2(MOVE, x, TYPE, x, TYPE, y)
|
||||
#define set(x, y) M_G3N_CALL_2(SET, x, TYPE, x , TYPE, y)
|
||||
#define clear(x) M_G3N_CALL_1(CLEAR, x)
|
||||
#define swap(x, y) M_G3N_CALL_2(SWAP, x, TYPE, x , TYPE, y)
|
||||
#define hash(x) M_G3N_CALL_1(HASH, x)
|
||||
#define equal(x, y) M_G3N_CALL_2(EQUAL, x, TYPE, x , TYPE, y)
|
||||
#define cmp(x, y) M_G3N_CALL_2(CMP, x, TYPE, x , TYPE, y)
|
||||
#define sort(x) M_G3N_CALL_1(SORT, x)
|
||||
#define splice_back(d, s, i) M_G3N_CALL_3(SPLICE_BACK, d, TYPE, d, TYPE, s, IT_TYPE, i)
|
||||
#define splice_at(d, id, s, is) M_G3N_CALL_4(SPLICE_BACK, d, TYPE, d, IT_TYPE, id, TYPE, s, IT_TYPE, is)
|
||||
#define it_type(x) m_typeof(M_G3N_TYPE_1(IT_TYPE, x))
|
||||
#define sub_type(x) m_typeof(M_G3N_TYPE_1(SUBTYPE, x))
|
||||
#define key_type(x) m_typeof(M_G3N_TYPE_1(KEY_TYPE, x))
|
||||
#define value_type(x) m_typeof(M_G3N_TYPE_1(VALUE_TYPE, x))
|
||||
#define it_first(x, y) M_G3N_CALL_2(IT_FIRST, y, IT_TYPE, x, TYPE, y)
|
||||
#define it_last(x, y) M_G3N_CALL_i2(IT_LAST, y, IT_TYPE, x, TYPE, y)
|
||||
#define it_end(x, y) M_G3N_CALL_i2(IT_END, y, IT_TYPE, x, TYPE, y)
|
||||
#define it_set(d, s) M_G3N_CALL_2i(IT_SET, d, IT_TYPE, d, IT_TYPE, s)
|
||||
#define it_end_p(i) M_G3N_CALL_1i(IT_END_P, i)
|
||||
#define it_last_p(i) M_G3N_CALL_1i(IT_LAST_P, i)
|
||||
#define it_next(i) M_G3N_CALL_1i(IT_NEXT, i)
|
||||
#define it_previous(i) M_G3N_CALL_1i(IT_PREVIOUS, i)
|
||||
#define it_ref(i) M_G3N_CALL_1i(IT_REF, i)
|
||||
#define it_cref(i) M_G3N_CALL_1i(IT_CREF, i)
|
||||
#define it_equal(x, y) M_G3N_CALL_2i(IT_EQUAL, x, IT_TYPE, x, IT_TYPE, y)
|
||||
#define it_insert(c, i, o) M_G2N_CALL_3(IT_INSERT, c, TYPE, c, IT_TYPE, i, SUBTYPE, o)
|
||||
#define it_remove(c, i) M_G3N_CALL_2(IT_REMOVE, c, TYPE, c, IT_TYPE, i)
|
||||
#define empty_p(x) M_G3N_CALL_1(EMPTY_P, x)
|
||||
#define add(x, y) M_G3N_CALL_2(ADD, x, TYPE, x, TYPE, y)
|
||||
#define sub(x, y) M_G3N_CALL_2(SUB, x, TYPE, x, TYPE, y)
|
||||
#define mul(x, y) M_G3N_CALL_2(MUL, x, TYPE, x, TYPE, y)
|
||||
#define div(x, y) M_G3N_CALL_2(DIV, x, TYPE, x, TYPE, y)
|
||||
#define reset(x) M_G3N_CALL_1(RESET, x)
|
||||
#define get(x, y) M_G3N_CALL_2(GET_KEY, x, TYPE, x, KEY_TYPE, y)
|
||||
#define set_at(x, y, z) M_G3N_CALL_3(SET_KEY, x, TYPE, x, KEY_TYPE, y, VALUE_TYPE, z)
|
||||
#define safe_get(x, y) M_G3N_CALL_2(SAFE_GET_KEY, x, TYPE, x, KEY_TYPE, y)
|
||||
#define erase(x, y) M_G3N_CALL_2(ERASE, x, TYPE, x, KEY_TYPE, y)
|
||||
#define get_size(x) M_G3N_CALL_1(GET_SIZE, x)
|
||||
#define push(x, y) M_G3N_CALL_2(PUSH, x, TYPE, x, SUBTYPE, y)
|
||||
#define pop(x, y) M_G3N_CALL_2(POP, y, SUBTYPE_PTR, x, TYPE, y)
|
||||
#define push_move(x, y) M_G3N_CALL_2(PUSH_MOVE, x, TYPE, x, SUBTYPE_PTR, y)
|
||||
#define pop_move(x, y) M_G3N_CALL_2(POP_MOVE, y, SUBTYPE_PTR, x, TYPE, y)
|
||||
#define reverse(x) M_G3N_CALL_1(REVERSE, x)
|
||||
#define get_str(s, c, b) M_G3N_CALL_3(GET_STR, c, string_t, s, TYPE, c, bool, b)
|
||||
#define parse_str(c, s, e) M_G3N_CALL_3(PARSE_STR, c, TYPE, c, m_g3n_cstring, s, m_g3n_cstring_end, e)
|
||||
#define out_str(x, y) M_G3N_CALL_2(OUT_STR, y, m_g3n_file, x, TYPE, y)
|
||||
#define in_str(x, y) M_G3N_CALL_2(IN_STR, x, TYPE, x, m_g3n_file, y)
|
||||
#define out_serial(x, y) M_G3N_CALL_2(OUT_SERIAL, y, m_serial_write_t, x, TYPE, y)
|
||||
#define in_serial(x, y) M_G3N_CALL_2(IN_SERIAL, x, TYPE, x, m_serial_read_t, y)
|
||||
|
||||
// for each(item, container)
|
||||
#define each(item, container) \
|
||||
M_G3N_EACHI(item, container, M_C(m_local_it_, __LINE__), M_C(local_pass_, __LINE__))
|
||||
|
||||
/* User code has to register oplists like this:
|
||||
#define M_GENERIC_ORG_2() (USER)
|
||||
#define M_GENERIC_ORG_USER_COMP_1() (CORE)
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_6() FLT1
|
||||
#define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_7() STR1
|
||||
*/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Definition of the typeof keyword
|
||||
In C23, we can use the standard keyword.
|
||||
Otherwise we use some extensions of the compilers. */
|
||||
#ifdef _MSC_VER
|
||||
#define m_typeof(x) decltype(x)
|
||||
#elif defined(__GNUC__)
|
||||
#define m_typeof(x) __typeof__(x)
|
||||
#else
|
||||
#define m_typeof(x) typeof(x)
|
||||
#endif
|
||||
|
||||
/* Warnings disabled for CLANG in C mode:
|
||||
Due to the genericity of the _Generic generation,
|
||||
we cannot avoid generating both T and const T in the generic association. */
|
||||
#if defined(__clang__) && __clang_major__ >= 15
|
||||
#define M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wunreachable-code-generic-assoc\"")
|
||||
|
||||
#define M_G3N_END_PROTECTED_CODE \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
#else
|
||||
|
||||
#define M_G3N_BEGIN_PROTECTED_CODE
|
||||
#define M_G3N_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
// Instead of using expensive M_SEQ(1,50), precompute it:
|
||||
#define M_G3N_SEQ_INT \
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, \
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
|
||||
|
||||
/* Generate a sequence of the oplist that have been registered.
|
||||
|
||||
3 levels of indirection are needed:
|
||||
* One level is the organisation.
|
||||
* One level is the component of the organisation.
|
||||
* One level is the oplist within the component of the organisation
|
||||
Return the list of unevaluated oplist that are registered across all organizations, all components.
|
||||
M*LIB Organisation (MLIB) is the default organisation and is always registered
|
||||
Usage Domain: Nb organizations * Nb components * Nb oplist <= M_MAX_NB_ARGUMENT
|
||||
*/
|
||||
#define M_G3N_REGISTERED_ITEMS() \
|
||||
M_CROSS_MAP( M_G3N_IS_PRESENT3, ( comp M_CROSS_MAP(M_G3N_IS_PRESENT2, (MLIB M_MAP(M_G3N_IS_PRESENT, M_G3N_SEQ_INT)), ( M_G3N_SEQ_INT ) ) ), ( M_G3N_SEQ_INT ) )
|
||||
|
||||
#define M_G3N_IS_PRESENT(num) \
|
||||
M_IF(M_PARENTHESIS_P(M_C(M_GENERIC_ORG_, num)() ))(M_DEFERRED_COMMA M_ID M_C(M_GENERIC_ORG_, num)(), )
|
||||
|
||||
#define M_G3N_IS_PRESENT2(el1, num) \
|
||||
M_IF(M_PARENTHESIS_P(M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()))(M_DEFERRED_COMMA M_APPLY(M_C3, el1, _COMP_, M_ID M_C4(M_GENERIC_ORG_, el1, _COMP_, num)()), )
|
||||
|
||||
#define M_G3N_IS_PRESENT3(el1, num) \
|
||||
M_IF(M_OPLIST_P(M_C4(M_GENERIC_ORG_, el1, _OPLIST_, num)()))(M_DEFERRED_COMMA M_C4(M_GENERIC_ORG_, el1, _OPLIST_, num), )
|
||||
|
||||
|
||||
// Dummy unused structure. Just to fill in default case of the _Generic
|
||||
struct m_g3neric_dummy_s;
|
||||
|
||||
// Synonymous for some basic pointers doesn't work well with preprocessing code
|
||||
typedef FILE *m_g3n_file;
|
||||
typedef const char *m_g3n_cstring;
|
||||
typedef const char **m_g3n_cstring_end;
|
||||
|
||||
// If x is of typex, return y else return (typey){O}
|
||||
#define M_AS_LINKED_TYPE(typex, x, typey, y) _Generic(((void)0,(x)), typex: (y), default: (typey) {0})
|
||||
|
||||
// Return IT_TYPE of oplist promoted to a type suitable for a _Generic statement
|
||||
// i.e. transform array type into corresponding pointer type
|
||||
#define M_G3N_GEN_IT_TYPE(oplist) m_typeof( ((void)0, (M_GET_IT_TYPE oplist()){0}))
|
||||
#define M_G3N_GEN_TYPE(oplist) M_GET_GENTYPE oplist()
|
||||
|
||||
// Translate type' into the container type if type == TYPE, IT_TYPE into its iterator
|
||||
// KEY_TYPE, VALUE_TYPE, SUBTYPE into the associated type in the oplist,
|
||||
// or keep 'type' otherwise
|
||||
// Handle also specially SUBTYPE_PTR
|
||||
#define M_G3N_TYPE(type, oplist) M_G3N_TYPE_B(type, oplist())
|
||||
#define M_G3N_TYPE_B(type, oplist) M_GET_METHOD(type, type, SUBTYPE_PTR(M_GET_SUBTYPE oplist *), M_OPFLAT oplist)
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'x'
|
||||
// which takes one argument.
|
||||
#define M_G3N_CALL_1(op, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (x)), \
|
||||
M_MAP2(M_G3N_CALL_1_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_1_func(x, oplist) \
|
||||
M_G3N_CALL_1_func_test(M_G3N_GEN_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
|
||||
#define M_G3N_CALL_1_func_test(gentype, op, x, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_1_func_expand, M_EAT)(gentype, op, x, oplist)
|
||||
#define M_G3N_CALL_1_func_expand(gentype, op, x, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_TYPE(gentype, x)), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, x, gentype, x)),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 2 arguments of the given type
|
||||
#define M_G3N_CALL_2(op, svar, type1, var1, type2, var2) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_2_func, (op, svar, type1, var1, type2, var2) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_2_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_2_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
|
||||
#define M_G3N_CALL_2_func_test(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_2_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, oplist)
|
||||
#define M_G3N_CALL_2_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 3 arguments of the given type
|
||||
#define M_G3N_CALL_3(op, svar, type1, var1, type2, var2, type3, var3) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_3_func, (op, svar, type1, var1, type2, var2, type3, var3) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_3_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_3_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
|
||||
#define M_G3N_CALL_3_func_test(gentype, op, svar, type1, var1, type2, var2, type3, var3, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_3_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, M_G3N_TYPE(type3, oplist), var3, oplist)
|
||||
#define M_G3N_CALL_3_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 4 arguments of the given type
|
||||
#define M_G3N_CALL_4(op, svar, type1, var1, type2, var2, type3, var3, type4, var4) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_4_func, (op, svar, type1, var1, type2, var2, type3, var3, type4, var4) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_4_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_4_func_test, M_G3N_GEN_TYPE(oplist), M_ID x, oplist)
|
||||
#define M_G3N_CALL_4_func_test(gentype, op, svar, type1, var1, type2, var2, type3, var3, type4, var4, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_CALL_4_func_expand, M_EAT)(gentype, op, svar, M_G3N_TYPE(type1, oplist), var1, M_G3N_TYPE(type2, oplist), var2, M_G3N_TYPE(type3, oplist), var3, M_G3N_TYPE(type4, oplist), var4, oplist)
|
||||
#define M_G3N_CALL_4_func_expand(gentype, op, svar, type1, var1, type2, var2, oplist) \
|
||||
gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(gentype, svar, type1, var1), M_AS_LINKED_TYPE(gentype, svar, type2, var2) ), \
|
||||
const gentype: M_C(M_CALL_, op)(oplist(), M_AS_LINKED_TYPE(const gentype, svar, type1, var1), M_AS_LINKED_TYPE(const gentype, svar, type2, var2) ),
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'x'
|
||||
// which takes one argument, it_type
|
||||
#define M_G3N_CALL_1i(op, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (x)), \
|
||||
M_MAP2(M_G3N_CALL_1i_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_1i_func(x, oplist) \
|
||||
M_G3N_CALL_1_func_test(M_G3N_GEN_IT_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
|
||||
|
||||
// Call the OPERATOR call of the oplist registered to the variable 'svar'
|
||||
// which takes 2 arguments of the given it_type
|
||||
#define M_G3N_CALL_2i(op, svar, type1, var1, type2, var2) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (svar)), \
|
||||
M_MAP2(M_G3N_CALL_2i_func, (op, svar, type1, var1, type2, var2) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_CALL_2i_func(x, oplist) \
|
||||
M_APPLY(M_G3N_CALL_2_func_test, M_G3N_GEN_IT_TYPE(oplist), M_ID x, oplist)
|
||||
|
||||
// Create a variable of type OPERATOR call of the oplist registered to the variable 'x'
|
||||
#define M_G3N_TYPE_1(op, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic( ((void)0, (x)), \
|
||||
M_MAP2(M_G3N_TYPE_1_func, (op, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void)0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
#define M_G3N_TYPE_1_func(x, oplist) \
|
||||
M_G3N_TYPE_1_func_test(M_G3N_GEN_TYPE(oplist), M_PAIR_1 x, M_PAIR_2 x, oplist)
|
||||
#define M_G3N_TYPE_1_func_test(gentype, op, x, oplist) \
|
||||
M_IF_METHOD(op, oplist())(M_G3N_TYPE_1_func_expand, M_EAT)(gentype, op, x, oplist)
|
||||
#define M_G3N_TYPE_1_func_expand(gentype, op, x, oplist) \
|
||||
gentype: (M_G3N_TYPE(op, oplist)){0}, \
|
||||
const gentype: (M_G3N_TYPE(op, oplist)){0},
|
||||
|
||||
|
||||
// for each item in the container
|
||||
// Same as M_EACH except it uses the generic macros
|
||||
#define M_G3N_EACHI(item, container, l_it, l_pass) \
|
||||
(bool l_pass = true; l_pass; l_pass = false) \
|
||||
for(sub_type(container) *item; l_pass ; l_pass = false) \
|
||||
for(it_type(container) l_it; l_pass ; l_pass = false) \
|
||||
for(it_first(l_it, container) ; \
|
||||
!it_end_p(l_it) \
|
||||
&& (item = it_ref(l_it), true) ; \
|
||||
it_next(l_it))
|
||||
|
||||
|
||||
// TODO: init_with ? How to handle the different type of parameters ? Using EMPLACE_TYPE ?
|
||||
// TODO: support of PUSH_EMPLACE ?
|
||||
// TODO: support of "let" directly to avoid using the post-processing registration of M_LET?
|
||||
|
||||
// Overwrite M_FPRINT & M_PRINT to support global oplists registration
|
||||
#define M_FPRINT_ARG_G3N(f, x) \
|
||||
M_G3N_BEGIN_PROTECTED_CODE \
|
||||
_Generic(((void)0,(x)), \
|
||||
char: fprintf(f, "%c", M_AS_TYPE(char,x)), \
|
||||
bool: fprintf(f, "%d", M_AS_TYPE(bool,x)), \
|
||||
signed char: fprintf(f, "%hhd", M_AS_TYPE(signed char,x)), \
|
||||
unsigned char: fprintf(f, "%hhu", M_AS_TYPE(unsigned char,x)), \
|
||||
signed short: fprintf(f, "%hd", M_AS_TYPE(signed short,x)), \
|
||||
unsigned short: fprintf(f, "%hu", M_AS_TYPE(unsigned short,x)), \
|
||||
signed int: fprintf(f, "%d", M_AS_TYPE(signed int,x)), \
|
||||
unsigned int: fprintf(f, "%u", M_AS_TYPE(unsigned int,x)), \
|
||||
long int: fprintf(f, "%ld", M_AS_TYPE(long int,x)), \
|
||||
unsigned long int: fprintf(f, "%lu", M_AS_TYPE(unsigned long int,x)), \
|
||||
long long int: fprintf(f, "%lld", M_AS_TYPE(long long int,x)), \
|
||||
unsigned long long int: fprintf(f, "%llu", M_AS_TYPE(unsigned long long int,x)), \
|
||||
float: fprintf(f, "%f", M_AS_TYPE(float,x)), \
|
||||
double: fprintf(f, "%f", M_AS_TYPE(double,x)), \
|
||||
long double: fprintf(f, "%Lf", M_AS_TYPE(long double,x)), \
|
||||
const char *: fprintf(f, "%s", M_AS_TYPE(const char*,x)), \
|
||||
char *: fprintf(f, "%s", M_AS_TYPE(char*,x)), \
|
||||
const void *: fprintf(f, "%p", M_AS_TYPE(const void *,x)), \
|
||||
void *: fprintf(f, "%p", M_AS_TYPE(void *,x)), \
|
||||
M_MAP2(M_G3N_CALL_2_func, (OUT_STR, x, m_g3n_file, f, TYPE, x) M_G3N_REGISTERED_ITEMS() ) \
|
||||
struct m_g3neric_dummy_s *: /* cannot happen */ (void) 0) \
|
||||
M_G3N_END_PROTECTED_CODE
|
||||
|
||||
#define M_G3N_FPRINT_ARG(f, x) \
|
||||
M_IF(M_PARENTHESIS_P(x)) \
|
||||
( M_FPRINT_ARG_OUT_STR(f, M_PAIR_2 x, M_PAIR_1 x), \
|
||||
M_FPRINT_ARG_G3N(f, x) )
|
||||
|
||||
/* Ovverride M_PRINT */
|
||||
#undef M_PRINT
|
||||
#define M_PRINT(...) do { M_REDUCE2(M_G3N_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, stdout, __VA_ARGS__); } while (0)
|
||||
|
||||
#undef M_FPRINT
|
||||
#define M_FPRINT(f,...) do { M_REDUCE2(M_G3N_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, f, __VA_ARGS__); } while (0)
|
||||
|
||||
// Register CORE component of M*LIB
|
||||
#define M_GENERIC_ORG_MLIB_COMP_1() (CORE)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Integer Generator (GENINT) module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -45,42 +45,40 @@ M_BEGIN_PROTECTED_CODE
|
||||
enough.
|
||||
*/
|
||||
|
||||
// TO DO: We may want a specialization with constant N value.
|
||||
|
||||
// Define the limb size used by genint
|
||||
typedef unsigned long long genint_limb_ct;
|
||||
typedef unsigned long long m_genint_limb_ct;
|
||||
|
||||
/* Define a generator of unique integer (Lock Free) */
|
||||
typedef struct genint_s {
|
||||
unsigned int n; // size of the container
|
||||
unsigned int max; // number of allocated limb - 1
|
||||
genint_limb_ct mask0; // mask of the last limb (constant)
|
||||
genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
|
||||
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
|
||||
atomic_ullong *data; // the bitfield which informs if an integer is used or not
|
||||
} genint_t[1];
|
||||
typedef struct m_genint_s {
|
||||
unsigned int n; // size of the container
|
||||
unsigned int max; // number of allocated limb - 1
|
||||
m_genint_limb_ct mask0; // mask of the last limb (constant)
|
||||
m_genint_limb_ct mask_master; // mask of the master limb that controls others (constant)
|
||||
atomic_ullong master; // master bitfield (which informs if a limb is full or not)
|
||||
atomic_ullong *data; // the bitfield which informs if an integer is used or not
|
||||
} m_genint_t[1];
|
||||
|
||||
// Define the max absolute supported value. It should be 2048 on most implementations.
|
||||
#define GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
|
||||
#define M_GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
|
||||
|
||||
// Define the size of a limb in bits.
|
||||
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
|
||||
#define M_GEN1NT_LIMBSIZE ((unsigned)(sizeof(m_genint_limb_ct) * CHAR_BIT))
|
||||
|
||||
// Define the contract of a genint
|
||||
#define M_GEN1NT_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
M_ASSERT (s->n > 0 && s->n <= M_GENINT_MAX_ALLOC); \
|
||||
M_ASSERT ((s->max+1) * M_GEN1NT_LIMBSIZE >= s->n); \
|
||||
M_ASSERT (s->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
// Define the limb one
|
||||
#define M_GEN1NT_ONE ((genint_limb_ct)1)
|
||||
#define M_GEN1NT_ONE ((m_genint_limb_ct)1)
|
||||
|
||||
#define M_GEN1NT_FULL_MASK ULLONG_MAX
|
||||
|
||||
// Value returned in case of error (not integer available).
|
||||
#define GENINT_ERROR (UINT_MAX)
|
||||
#define M_GENINT_ERROR (UINT_MAX)
|
||||
|
||||
/* 32 bits of the master mask are kept for handling the ABA problem.
|
||||
* NOTE: May be too much. 16 bits should be more than enough. TBC
|
||||
@@ -105,14 +103,14 @@ typedef struct genint_s {
|
||||
* meaning it can be used to index global unique resources shared
|
||||
* for all threads.
|
||||
*/
|
||||
static inline void
|
||||
genint_init(genint_t s, unsigned int n)
|
||||
M_INLINE void
|
||||
m_genint_init(m_genint_t s, unsigned int n)
|
||||
{
|
||||
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
|
||||
M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC);
|
||||
const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE;
|
||||
const unsigned int index = n % M_GEN1NT_LIMBSIZE;
|
||||
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
|
||||
M_MEMORY_FULL(alloc);
|
||||
return;
|
||||
}
|
||||
@@ -121,15 +119,15 @@ genint_init(genint_t s, unsigned int n)
|
||||
s->max = (unsigned int) (alloc-1);
|
||||
s->mask0 = (index == 0) ? M_GEN1NT_FULL_MASK : ~((M_GEN1NT_ONE<<(M_GEN1NT_LIMBSIZE-index))-1);
|
||||
s->mask_master = (((M_GEN1NT_ONE << alloc) - 1) << (M_GEN1NT_LIMBSIZE-alloc)) >> M_GEN1NT_ABA_CPT;
|
||||
atomic_init (&s->master, (genint_limb_ct)0);
|
||||
atomic_init (&s->master, (m_genint_limb_ct)0);
|
||||
for(unsigned int i = 0; i < alloc; i++)
|
||||
atomic_init(&s->data[i], (genint_limb_ct)0);
|
||||
atomic_init(&s->data[i], (m_genint_limb_ct)0);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear an integer generator (Destructor) */
|
||||
static inline void
|
||||
genint_clear(genint_t s)
|
||||
M_INLINE void
|
||||
m_genint_clear(m_genint_t s)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_MEMORY_FREE(s->data);
|
||||
@@ -137,8 +135,8 @@ genint_clear(genint_t s)
|
||||
}
|
||||
|
||||
/* Return the maximum integer that the generator will provide */
|
||||
static inline size_t
|
||||
genint_size(genint_t s)
|
||||
M_INLINE size_t
|
||||
m_genint_size(m_genint_t s)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return s->n;
|
||||
@@ -146,23 +144,23 @@ genint_size(genint_t s)
|
||||
|
||||
/* Get an unique integer from the integer generator.
|
||||
* NOTE: For a typical case, the amortized cost is one CAS per pop. */
|
||||
static inline unsigned int
|
||||
genint_pop(genint_t s)
|
||||
M_INLINE unsigned int
|
||||
m_genint_pop(m_genint_t s)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
// First read master to see which limb is not full.
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
m_genint_limb_ct master = atomic_load(&s->master);
|
||||
// While master is not full
|
||||
while ((master >> M_GEN1NT_ABA_CPT) != s->mask_master) {
|
||||
// Let's get the index i of the first not full limb according to master.
|
||||
unsigned int i = m_core_clz64(~master);
|
||||
M_ASSERT (i < M_GEN1NT_LIMBSIZE);
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
genint_limb_ct mask = s->mask0;
|
||||
m_genint_limb_ct mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
|
||||
unsigned int bit;
|
||||
// Let's load this limb,
|
||||
genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
// If it is now full, we have been preempted by another.
|
||||
if (M_UNLIKELY (org == mask))
|
||||
@@ -181,7 +179,7 @@ genint_pop(genint_t s)
|
||||
// If the limb is now full, try to update master
|
||||
if (M_UNLIKELY(next == mask)) {
|
||||
while (true) {
|
||||
genint_limb_ct newMaster;
|
||||
m_genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
@@ -201,21 +199,21 @@ genint_pop(genint_t s)
|
||||
master = atomic_load(&s->master);
|
||||
}
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return GENINT_ERROR; // No more resource available
|
||||
return M_GENINT_ERROR; // No more resource available
|
||||
}
|
||||
|
||||
/* Restore a used integer in the integer generator.
|
||||
* NOTE: For a typical case, the amortized cost is one CAS per pop */
|
||||
static inline void
|
||||
genint_push(genint_t s, unsigned int n)
|
||||
M_INLINE void
|
||||
m_genint_push(m_genint_t s, unsigned int n)
|
||||
{
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_ASSERT (n < s->n);
|
||||
const unsigned int i = n / M_GEN1NT_LIMBSIZE;
|
||||
const unsigned int bit = M_GEN1NT_LIMBSIZE - 1 - (n % M_GEN1NT_LIMBSIZE);
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
m_genint_limb_ct master = atomic_load(&s->master);
|
||||
// Load the limb
|
||||
genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
m_genint_limb_ct next, org = atomic_load(&s->data[i]);
|
||||
do {
|
||||
M_ASSERT ((org & (M_GEN1NT_ONE << bit)) != 0);
|
||||
// Reset it
|
||||
@@ -223,13 +221,13 @@ genint_push(genint_t s, unsigned int n)
|
||||
// Try to unreserve it.
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// if the limb was marked as full by master
|
||||
genint_limb_ct mask = s->mask0;
|
||||
m_genint_limb_ct mask = s->mask0;
|
||||
mask = (i == s->max) ? mask : M_GEN1NT_FULL_MASK;
|
||||
if (M_UNLIKELY (next != mask)) {
|
||||
// Let's compute the mask of this limb representing the limb as being full
|
||||
// Let's try to update master to say that this limb is not full
|
||||
while (true) {
|
||||
genint_limb_ct newMaster;
|
||||
m_genint_limb_ct newMaster;
|
||||
if (next == mask) {
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -38,16 +38,16 @@
|
||||
...
|
||||
} tmp_str_t;
|
||||
*/
|
||||
#define ILIST_INTERFACE(name, type) \
|
||||
struct m_ilist_head_s name
|
||||
#define M_ILIST_INTERFACE(name, type) \
|
||||
struct m_il1st_head_s name
|
||||
|
||||
|
||||
/* Define a doubly-linked intrusive list of a given type.
|
||||
The type needs to have ILIST_INTERFACE().
|
||||
USAGE:
|
||||
ILIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define ILIST_DEF(name, ...) \
|
||||
ILIST_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_ILIST_DEF(name, ...) \
|
||||
M_ILIST_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a doubly-linked intrusive list of a given type
|
||||
@@ -55,7 +55,7 @@
|
||||
The type needs to have ILIST_INTERFACE().
|
||||
USAGE:
|
||||
ILIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define ILIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_ILIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IL1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
@@ -66,19 +66,21 @@
|
||||
/* Define the oplist of a doubly-linked instrusive list of type.
|
||||
USAGE:
|
||||
ILIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ILIST_OPLIST(...) \
|
||||
#define M_ILIST_OPLIST(...) \
|
||||
M_IL1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/*****************************************************************************/
|
||||
/******************************** INTERNAL ***********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Define the basic structure to be added in all objects. */
|
||||
typedef struct m_ilist_head_s {
|
||||
struct m_ilist_head_s *next;
|
||||
struct m_ilist_head_s *prev;
|
||||
} m_ilist_head_ct;
|
||||
typedef struct m_il1st_head_s {
|
||||
struct m_il1st_head_s *next;
|
||||
struct m_il1st_head_s *prev;
|
||||
} m_il1st_head_ct;
|
||||
|
||||
/* Indirection call to allow expanding all arguments */
|
||||
#define M_IL1ST_OPLIST_P1(arg) M_IL1ST_OPLIST_P2 arg
|
||||
@@ -93,35 +95,36 @@ typedef struct m_ilist_head_s {
|
||||
|
||||
/* Define the oplist of an ilist of type */
|
||||
#define M_IL1ST_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
(INIT(M_F(name, _init)), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
INIT_MOVE(M_F(name, _init_move)), \
|
||||
MOVE(M_F(name, _move)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
SUBTYPE(M_C(name,_subtype_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
IT_TYPE(M_C(name,_it_ct)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_LAST(M_C(name,_it_last)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_PREVIOUS(M_C(name,_previous)), \
|
||||
IT_REF(M_C(name,_ref)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
IT_REMOVE(M_C(name,_remove)), \
|
||||
M_IF_METHOD(NEW, oplist)(IT_INSERT(M_C(name,_insert)),), \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
RESET(M_F(name,_reset)), \
|
||||
SUBTYPE(M_F(name,_subtype_ct)), \
|
||||
EMPTY_P(M_F(name,_empty_p)), \
|
||||
IT_TYPE(M_F(name,_it_ct)), \
|
||||
IT_FIRST(M_F(name,_it)), \
|
||||
IT_SET(M_F(name,_it_set)), \
|
||||
IT_LAST(M_F(name,_it_last)), \
|
||||
IT_END(M_F(name,_it_end)), \
|
||||
IT_END_P(M_F(name,_end_p)), \
|
||||
IT_LAST_P(M_F(name,_last_p)), \
|
||||
IT_EQUAL_P(M_F(name,_it_equal_p)), \
|
||||
IT_NEXT(M_F(name,_next)), \
|
||||
IT_PREVIOUS(M_F(name,_previous)), \
|
||||
IT_REF(M_F(name,_ref)), \
|
||||
IT_CREF(M_F(name,_cref)), \
|
||||
IT_REMOVE(M_F(name,_remove)), \
|
||||
M_IF_METHOD(NEW, oplist)(IT_INSERT(M_F(name,_insert)),), \
|
||||
OPLIST(oplist), \
|
||||
SPLICE_BACK(M_C(name,_splice_back)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
SPLICE_BACK(M_F(name,_splice_back)) \
|
||||
)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
/* Contract respected by all intrusive lists */
|
||||
#define M_IL1ST_CONTRACT(name, list) do { \
|
||||
M_ASSERT(list != NULL); \
|
||||
@@ -140,8 +143,8 @@ typedef struct m_ilist_head_s {
|
||||
M_ASSERT((node)->prev->next == node); \
|
||||
} while (0)
|
||||
|
||||
/* Indirection call to allow expanding all arguments (TBC) */
|
||||
#define M_IL1ST_DEF_P1(arg) M_IL1ST_DEF_P2 arg
|
||||
/* Indirection call to allow expanding all arguments */
|
||||
#define M_IL1ST_DEF_P1(arg) M_ID( M_IL1ST_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_IL1ST_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
@@ -160,34 +163,43 @@ typedef struct m_ilist_head_s {
|
||||
it_t: iterator of the intrusive list (name##_it_t)
|
||||
*/
|
||||
#define M_IL1ST_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
M_IL1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_IL1ST_DEF_CORE(name, type, oplist, list_t, it_t) \
|
||||
/* Used of internal macro from m-list */ \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
/* Define the type of an intrusive list */
|
||||
#define M_IL1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Define the list as a structure containing pointers \
|
||||
* to the front & back nodes */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct m_ilist_head_s name; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
struct m_il1st_head_s name; \
|
||||
} list_t[1]; \
|
||||
\
|
||||
/* Define internal types pointers to such a list */ \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
\
|
||||
/* Define iterator of such a list */ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct m_ilist_head_s *head; \
|
||||
struct m_ilist_head_s *previous; \
|
||||
struct m_ilist_head_s *current; \
|
||||
struct m_ilist_head_s *next; \
|
||||
typedef struct M_F(name, _it_s) { \
|
||||
struct m_il1st_head_s *head; \
|
||||
struct m_il1st_head_s *previous; \
|
||||
struct m_il1st_head_s *current; \
|
||||
struct m_il1st_head_s *next; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Define types used by oplist */ \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef list_t M_C(name, _ct); \
|
||||
typedef it_t M_C(name, _it_ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef list_t M_F(name, _ct); \
|
||||
typedef it_t M_F(name, _it_ct); \
|
||||
|
||||
/* Define core functions for intrusive lists */
|
||||
#define M_IL1ST_DEF_CORE(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(list_t list) \
|
||||
{ \
|
||||
M_ASSERT (list != NULL); \
|
||||
list->name.next = &list->name; \
|
||||
@@ -195,15 +207,15 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reset)(list_t list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _reset)(list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
for(struct m_ilist_head_s *it = list->name.next, *next ; \
|
||||
for(struct m_il1st_head_s *it = list->name.next, *next ; \
|
||||
it != &list->name; it = next) { \
|
||||
/* Cannot check node contract as previous node may be deleted */ \
|
||||
type *obj = M_TYPE_FROM_FIELD(type, it, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
/* Read next now before the object is destroyed */ \
|
||||
next = it->next; \
|
||||
M_ASSERT (next != NULL); \
|
||||
@@ -217,37 +229,31 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(list_t list) \
|
||||
{ \
|
||||
M_C(name,_reset)(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(list_t list) \
|
||||
{ \
|
||||
/* Nothing to do more than clean the list itself */ \
|
||||
M_C(name, _reset)(list); \
|
||||
M_F(name, _reset)(list); \
|
||||
/* For safety purpose (create invalid represenation of object) */ \
|
||||
list->name.next = NULL; \
|
||||
list->name.prev = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t list) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _empty_p)(const list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
return list->name.next == &list->name; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t ref) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_move)(list_t list, list_t ref) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, ref); \
|
||||
M_ASSERT (list != ref); \
|
||||
M_C(name,_init)(list); \
|
||||
if (!M_C(name,_empty_p)(ref)) { \
|
||||
M_F(name,_init)(list); \
|
||||
if (!M_F(name,_empty_p)(ref)) { \
|
||||
list->name.next = ref->name.next; \
|
||||
list->name.prev = ref->name.prev; \
|
||||
list->name.next->prev = &list->name; \
|
||||
@@ -258,20 +264,20 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(list_t list, list_t ref) \
|
||||
M_INLINE void \
|
||||
M_F(name, _move)(list_t list, list_t ref) \
|
||||
{ \
|
||||
M_C(name, _clear)(list); \
|
||||
M_C(name, _init_move)(list, ref); \
|
||||
M_F(name, _clear)(list); \
|
||||
M_F(name, _init_move)(list, ref); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t list) \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _size)(const list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
size_t s = 0; \
|
||||
/* Scan the full list to count the number of elements */ \
|
||||
for(const struct m_ilist_head_s *it = list->name.next ; \
|
||||
for(const struct m_il1st_head_s *it = list->name.next ; \
|
||||
it != &list->name; it = it->next) { \
|
||||
M_IL1ST_NODE_CONTRACT(it); \
|
||||
s++; \
|
||||
@@ -279,12 +285,12 @@ typedef struct m_ilist_head_s {
|
||||
return s; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_back)(list_t list, type *obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _push_back)(list_t list, type *obj) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct m_ilist_head_s *prev = list->name.prev; \
|
||||
struct m_il1st_head_s *prev = list->name.prev; \
|
||||
list->name.prev = &obj->name; \
|
||||
obj->name.prev = prev; \
|
||||
obj->name.next = &list->name; \
|
||||
@@ -292,12 +298,12 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_front)(list_t list, type *obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _push_front)(list_t list, type *obj) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct m_ilist_head_s *next = list->name.next; \
|
||||
struct m_il1st_head_s *next = list->name.next; \
|
||||
list->name.next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = &list->name; \
|
||||
@@ -305,21 +311,21 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_after)(type *obj_pos, type *obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _push_after)(type *obj_pos, type *obj) \
|
||||
{ \
|
||||
M_ASSERT (obj_pos != NULL && obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
M_IL1ST_NODE_CONTRACT(&obj_pos->name); \
|
||||
struct m_ilist_head_s *next = obj_pos->name.next; \
|
||||
struct m_il1st_head_s *next = obj_pos->name.next; \
|
||||
obj_pos->name.next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = &obj_pos->name; \
|
||||
next->prev = &obj->name; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_field)(type *obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_field)(type *obj) \
|
||||
{ \
|
||||
M_ASSERT (obj != NULL); \
|
||||
/* Init the fields of the node. To be used in object constructor */ \
|
||||
@@ -327,14 +333,14 @@ typedef struct m_ilist_head_s {
|
||||
obj->name.prev = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _unlink)(type *obj) \
|
||||
M_INLINE void \
|
||||
M_F(name, _unlink)(type *obj) \
|
||||
{ \
|
||||
M_ASSERT (obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
struct m_ilist_head_s *next = obj->name.next; \
|
||||
struct m_ilist_head_s *prev = obj->name.prev; \
|
||||
struct m_il1st_head_s *next = obj->name.next; \
|
||||
struct m_il1st_head_s *prev = obj->name.prev; \
|
||||
next->prev = prev; \
|
||||
prev->next = next; \
|
||||
/* Note: not really needed, but safer */ \
|
||||
@@ -342,48 +348,48 @@ typedef struct m_ilist_head_s {
|
||||
obj->name.prev = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _back)(const list_t list) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _back)(const list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
M_ASSERT(!M_F(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.prev, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _front)(const list_t list) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _front)(const list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
M_ASSERT(!M_F(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.next, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _next_obj)(const list_t list, type const *obj) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _next_obj)(const list_t list, type const *obj) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.next == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.next, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _previous_obj)(const list_t list, type const *obj) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _previous_obj)(const list_t list, type const *obj) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.prev == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.prev, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const list_t list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it)(it_t it, const list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (it != NULL); \
|
||||
@@ -394,8 +400,8 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t cit) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_set)(it_t it, const it_t cit) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && cit != NULL); \
|
||||
it->head = cit->head; \
|
||||
@@ -405,8 +411,8 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, list_t const list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_last)(it_t it, list_t const list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (it != NULL); \
|
||||
@@ -417,8 +423,8 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, list_t const list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_end)(it_t it, list_t const list) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && list != NULL); \
|
||||
it->head = list->name.next->prev; \
|
||||
@@ -428,24 +434,24 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
return it->current == it->head; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
return it->next == it->head || it->current == it->head; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
M_INLINE void \
|
||||
M_F(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
/* Cannot check node for it->current: it may have been deleted! */ \
|
||||
@@ -459,8 +465,8 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
M_INLINE void \
|
||||
M_F(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
/* Cannot check node for it->current: it may have been deleted! */ \
|
||||
@@ -474,97 +480,97 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, const it_t it2 ) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _it_equal_p)(const it_t it1, const it_t it2 ) \
|
||||
{ \
|
||||
M_ASSERT (it1 != NULL && it2 != NULL); \
|
||||
/* No need to check for next & previous */ \
|
||||
return it1->head == it2->head && it1->current == it2->current; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _ref)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->current != NULL); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
/* check if 'it' was not deleted */ \
|
||||
M_ASSERT (it->current->next == it->next); \
|
||||
M_ASSERT (it->current->prev == it->previous); \
|
||||
M_ASSERT (!M_C(name, _end_p)(it)); \
|
||||
M_ASSERT (!M_F(name, _end_p)(it)); \
|
||||
return M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct m_ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
type *ptr = M_C(name, _ref)(it); \
|
||||
type *ptr = M_F(name, _ref)(it); \
|
||||
return M_CONST_CAST(type, ptr); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, it_t it) \
|
||||
M_INLINE void \
|
||||
M_F(name, _remove)(list_t list, it_t it) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
(void)list; /* list param is not used */ \
|
||||
type *obj = M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct m_ilist_head_s, name); \
|
||||
M_C(name, _unlink)(obj); \
|
||||
struct m_il1st_head_s, name); \
|
||||
M_F(name, _unlink)(obj); \
|
||||
M_CALL_CLEAR(oplist, obj); \
|
||||
M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \
|
||||
M_C(name, _next)(it); \
|
||||
M_F(name, _next)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(NEW, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _insert)(list_t list, it_t it, type x) \
|
||||
M_IF_METHOD2(NEW, INIT_SET, oplist)( \
|
||||
M_INLINE void \
|
||||
M_F(name, _insert)(list_t list, it_t it, type x) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
type *p = M_CALL_NEW(oplist, type); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
if (M_UNLIKELY_NOMEM (p == NULL)) { \
|
||||
M_MEMORY_FULL (sizeof (type)); \
|
||||
return ; \
|
||||
} \
|
||||
M_CALL_INIT_SET(oplist, *p, x); \
|
||||
type *obj = M_C(name, _ref)(it); \
|
||||
M_C(name, _push_after)(obj, p); \
|
||||
type *obj = M_F(name, _ref)(it); \
|
||||
M_F(name, _push_after)(obj, p); \
|
||||
it->current = p; \
|
||||
(void) list; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
, /* NEW not defined */) \
|
||||
, /* NEW & INIT_SET not defined */) \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _pop_back)(list_t list) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _pop_back)(list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (!M_C(name, _empty_p)(list)); \
|
||||
type *obj = M_C(name, _back)(list); \
|
||||
M_ASSERT (!M_F(name, _empty_p)(list)); \
|
||||
type *obj = M_F(name, _back)(list); \
|
||||
list->name.prev = list->name.prev->prev; \
|
||||
list->name.prev->next = &list->name; \
|
||||
return obj; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _pop_front)(list_t list) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _pop_front)(list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (!M_C(name, _empty_p)(list)); \
|
||||
type *obj = M_C(name, _front)(list); \
|
||||
M_ASSERT (!M_F(name, _empty_p)(list)); \
|
||||
type *obj = M_F(name, _front)(list); \
|
||||
list->name.next = list->name.next->next; \
|
||||
list->name.next->prev = &list->name; \
|
||||
return obj; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
M_INLINE void \
|
||||
M_F(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list1); \
|
||||
M_IL1ST_CONTRACT(name, list2); \
|
||||
struct m_ilist_head_s *midle1 = list1->name.prev; \
|
||||
struct m_ilist_head_s *midle2 = list2->name.next; \
|
||||
struct m_il1st_head_s *midle1 = list1->name.prev; \
|
||||
struct m_il1st_head_s *midle2 = list2->name.next; \
|
||||
midle1->next = midle2; \
|
||||
midle2->prev = midle1; \
|
||||
list1->name.prev = list2->name.prev; \
|
||||
@@ -575,44 +581,44 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \
|
||||
M_INLINE void \
|
||||
M_F(name, _splice_back)(list_t nv, list_t ov, it_t it) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, nv); \
|
||||
M_IL1ST_CONTRACT(name, ov); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
M_ASSERT (it != NULL); \
|
||||
(void) ov; \
|
||||
type *obj = M_C(name, _ref)(it); \
|
||||
M_C(name, _unlink)(obj); \
|
||||
M_C(name, _push_back)(nv, obj); \
|
||||
M_C(name, _next)(it); \
|
||||
type *obj = M_F(name, _ref)(it); \
|
||||
M_F(name, _unlink)(obj); \
|
||||
M_F(name, _push_back)(nv, obj); \
|
||||
M_F(name, _next)(it); \
|
||||
M_IL1ST_CONTRACT(name, nv); \
|
||||
M_IL1ST_CONTRACT(name, ov); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
M_INLINE void \
|
||||
M_F(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
list_t olist, it_t opos) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, nlist); \
|
||||
M_IL1ST_CONTRACT(name, olist); \
|
||||
M_ASSERT (npos != NULL && opos != NULL); \
|
||||
M_ASSERT (!M_C(name, _end_p)(opos)); \
|
||||
M_ASSERT (!M_F(name, _end_p)(opos)); \
|
||||
/* npos may be end */ \
|
||||
(void) olist, (void) nlist; \
|
||||
type *obj = M_C(name, _ref)(opos); \
|
||||
struct m_ilist_head_s *ref = npos->current; \
|
||||
type *obj = M_F(name, _ref)(opos); \
|
||||
struct m_il1st_head_s *ref = npos->current; \
|
||||
/* Remove object */ \
|
||||
M_C(name, _unlink)(obj); \
|
||||
M_F(name, _unlink)(obj); \
|
||||
/* Push 'obj' after 'ref' */ \
|
||||
struct m_ilist_head_s *next = ref->next; \
|
||||
struct m_il1st_head_s *next = ref->next; \
|
||||
ref->next = &obj->name; \
|
||||
obj->name.next = next; \
|
||||
obj->name.prev = ref; \
|
||||
next->prev = &obj->name; \
|
||||
/* Move iterator in old list */ \
|
||||
M_C(name, _next)(opos); \
|
||||
M_F(name, _next)(opos); \
|
||||
/* Set npos iterator to new position of object */ \
|
||||
npos->previous = ref; \
|
||||
npos->current = &obj->name; \
|
||||
@@ -621,13 +627,13 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, olist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t d, list_t e) \
|
||||
M_INLINE void \
|
||||
M_F(name, _swap)(list_t d, list_t e) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, d); \
|
||||
M_IL1ST_CONTRACT(name, e); \
|
||||
struct m_ilist_head_s *d_item = d->name.next; \
|
||||
struct m_ilist_head_s *e_item = e->name.next; \
|
||||
struct m_il1st_head_s *d_item = d->name.next; \
|
||||
struct m_il1st_head_s *e_item = e->name.next; \
|
||||
/* it is more complicated than other swap functions since \
|
||||
we need to detect "cyclic" loop */ \
|
||||
d->name.next = e_item == &e->name ? &d->name : e_item; \
|
||||
@@ -644,11 +650,11 @@ typedef struct m_ilist_head_s {
|
||||
M_IL1ST_CONTRACT(name, e); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
M_INLINE void \
|
||||
M_F(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
struct m_ilist_head_s *next, *it; \
|
||||
struct m_il1st_head_s *next, *it; \
|
||||
for(it = list->name.next ; it != &list->name; it = next) { \
|
||||
next = it->next; \
|
||||
it->next = it->prev; \
|
||||
@@ -659,9 +665,15 @@ typedef struct m_ilist_head_s {
|
||||
it->prev = next; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
/* Used of internal macro from m-list */ \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ILIST_INTERFACE M_ILIST_INTERFACE
|
||||
#define ILIST_DEF M_ILIST_DEF
|
||||
#define ILIST_DEF_AS M_ILIST_DEF_AS
|
||||
#define ILIST_OPLIST M_ILIST_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -32,9 +32,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a intrusive shared pointer.
|
||||
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ISHARED_PTR_OPLIST(...) \
|
||||
#define M_ISHARED_PTR_OPLIST(...) \
|
||||
M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -42,29 +42,29 @@ M_BEGIN_PROTECTED_CODE
|
||||
name: name of the intrusive shared pointer.
|
||||
type: name of the type of the structure (aka. struct test_s) - not used currently.
|
||||
NOTE: There can be only one interface of this kind in a type! */
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
atomic_int M_C(name, _cpt)
|
||||
#define M_ISHARED_PTR_INTERFACE(name, type) \
|
||||
atomic_int M_F(name, _cpt)
|
||||
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C99 designated element). */
|
||||
#define ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
|
||||
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
.M_F(name, _cpt) = M_ATOMIC_VAR_INIT(0)
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C89 designated element). */
|
||||
#define ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
ATOMIC_VAR_INIT(0)
|
||||
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
M_ATOMIC_VAR_INIT(0)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
/* Define the intrusive shared pointer type and its M_INLINE functions.
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
ISHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_ISHARED_PTR_DEF(name, ...) \
|
||||
M_ISHARED_PTR_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions
|
||||
/* Define the intrusive shared pointer type and its M_INLINE functions
|
||||
as the name name_t
|
||||
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
#define M_ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -72,7 +72,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/*****************************************************************************/
|
||||
/******************************** INTERNAL ***********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
// Deferred evaluation
|
||||
#define M_ISHAR3D_PTR_OPLIST_P1(arg) M_ISHAR3D_PTR_OPLIST_P2 arg
|
||||
@@ -88,21 +90,21 @@ M_BEGIN_PROTECTED_CODE
|
||||
// Define the oplist
|
||||
#define M_ISHAR3D_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
INIT_SET(API_4(M_C(name, _init_set))), \
|
||||
SET(M_C(name, _set) M_IPTR), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
RESET(M_C(name, _reset) M_IPTR), \
|
||||
INIT_SET(API_4(M_F(name, _init_set))), \
|
||||
SET(M_F(name, _set) M_IPTR), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
RESET(M_F(name, _reset) M_IPTR), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
)
|
||||
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
// Deferred evaluatioin
|
||||
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ISHAR3D_PTR_DEF_P2 arg
|
||||
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
@@ -113,31 +115,38 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define M_ISHAR3D_PTR_DEF_P3(name, type, oplist, shared_t) \
|
||||
M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
|
||||
|
||||
/* Define the types */
|
||||
#define M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
|
||||
\
|
||||
/* The shared pointer is only a pointer to the type */ \
|
||||
typedef type *shared_t; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef shared_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init)(type *ptr) \
|
||||
M_INLINE shared_t \
|
||||
M_F(name, _init)(type *ptr) \
|
||||
{ \
|
||||
/* Initialize the type referenced by the pointer */ \
|
||||
if (M_LIKELY (ptr != NULL)) { \
|
||||
atomic_init(&ptr->M_C(name, _cpt), 2); \
|
||||
atomic_init(&ptr->M_F(name, _cpt), 2); \
|
||||
} \
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init_set)(shared_t shared) \
|
||||
M_INLINE shared_t \
|
||||
M_F(name, _init_set)(shared_t shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 2); \
|
||||
int n = atomic_fetch_add(&(shared->M_F(name, _cpt)), 2); \
|
||||
(void) n; \
|
||||
} \
|
||||
return shared; \
|
||||
@@ -147,95 +156,100 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_IF_DISABLED_METHOD(NEW, oplist) \
|
||||
( \
|
||||
/* This function is only for static object */ \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_once)(type *shared) \
|
||||
M_INLINE shared_t \
|
||||
M_F(name, _init_once)(type *shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
/* Pretty much like atomic_add, except the first one increment by 1, others by 2 */ \
|
||||
int o = atomic_load(&(shared->M_C(name, _cpt))); \
|
||||
int o = atomic_load(&(shared->M_F(name, _cpt))); \
|
||||
int n; \
|
||||
do { \
|
||||
n = o + 1 + (o != 0); \
|
||||
} while (!atomic_compare_exchange_strong(&(shared->M_C(name, _cpt)), &o, n)); \
|
||||
} while (!atomic_compare_exchange_strong(&(shared->M_F(name, _cpt)), &o, n)); \
|
||||
if (o == 0) { \
|
||||
/* Partial initialization: _cpt is odd */ \
|
||||
/* Call the INIT function once */ \
|
||||
M_CALL_INIT(oplist, *shared); \
|
||||
/* Finish initialization: _cpt is even */ \
|
||||
atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
atomic_fetch_add(&(shared->M_F(name, _cpt)), 1); \
|
||||
} else if ( (o&1) != 0) { \
|
||||
/* Not fully initialized yet: wait for initialization */ \
|
||||
m_core_backoff_ct bkoff; \
|
||||
m_core_backoff_init(bkoff); \
|
||||
/* Wait for _cpt to be _even */ \
|
||||
while ((atomic_load(&(shared->M_C(name, _cpt)))&1) != 0 ) { \
|
||||
while ((atomic_load(&(shared->M_F(name, _cpt)))&1) != 0 ) { \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
M_ASSERT( (atomic_load(&(shared->M_C(name, _cpt)))&1) == 0); \
|
||||
M_ASSERT( (atomic_load(&(shared->M_F(name, _cpt)))&1) == 0); \
|
||||
} \
|
||||
return shared; \
|
||||
} \
|
||||
, \
|
||||
/* This function is only for dynamic object */ \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_new)(void) \
|
||||
M_INLINE shared_t \
|
||||
M_F(name, _init_new)(void) \
|
||||
{ \
|
||||
type *ptr = M_CALL_NEW(oplist, type); \
|
||||
if (ptr == NULL) { \
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT(oplist, *ptr); \
|
||||
atomic_init (&ptr->M_C(name, _cpt), 2); \
|
||||
atomic_init (&ptr->M_F(name, _cpt), 2); \
|
||||
return ptr; \
|
||||
} \
|
||||
/* End of NEW */) \
|
||||
, /* End of INIT */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t shared) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(shared_t shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 2) == 2) { \
|
||||
if (atomic_fetch_sub(&(shared->M_F(name, _cpt)), 2) == 2) { \
|
||||
M_CALL_CLEAR(oplist, *shared); \
|
||||
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear_ptr)(shared_t *shared) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear_ptr)(shared_t *shared) \
|
||||
{ \
|
||||
M_ASSERT(shared != NULL); \
|
||||
M_C(name, _clear)(*shared); \
|
||||
M_F(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reset)(shared_t *shared) \
|
||||
M_INLINE void \
|
||||
M_F(name, _reset)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
M_F(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _reset)(shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t *ptr, shared_t shared) \
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(shared_t *ptr, shared_t shared) \
|
||||
{ \
|
||||
M_ASSERT (ptr != NULL); \
|
||||
if (M_LIKELY (*ptr != shared)) { \
|
||||
M_C(name, _clear)(*ptr); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
M_F(name, _clear)(*ptr); \
|
||||
*ptr = M_F(name, _init_set)(shared); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ISHARED_PTR_OPLIST M_ISHARED_PTR_OPLIST
|
||||
#define ISHARED_PTR_INTERFACE M_ISHARED_PTR_INTERFACE
|
||||
#define ISHARED_PTR_STATIC_DESIGNATED_INIT M_ISHARED_PTR_STATIC_DESIGNATED_INIT
|
||||
#define ISHARED_PTR_STATIC_INIT M_ISHARED_PTR_STATIC_INIT
|
||||
#define ISHARED_PTR_DEF M_ISHARED_PTR_DEF
|
||||
#define ISHARED_PTR_DEF_AS M_ISHARED_PTR_DEF_AS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -27,35 +27,38 @@
|
||||
|
||||
#include "m-core.h"
|
||||
|
||||
/* Fast Fixed Size thread unsafe allocator based on memory region.
|
||||
/* Fast, fixed size, thread unsafe allocator based on memory regions.
|
||||
No oplist is needed.
|
||||
USAGE:
|
||||
MEMPOOL_DEF(memppol_uint, unsigned int)
|
||||
MEMPOOL_DEF(name, type)
|
||||
Example:
|
||||
MEMPOOL_DEF(mempool_uint, unsigned int)
|
||||
...
|
||||
memppol_uint_t m;
|
||||
mempool_uint_t m;
|
||||
mempool_uint_init(m);
|
||||
unsigned int *ptr = mempool_uint_alloc(m);
|
||||
*ptr = 17;
|
||||
mempool_uint_free(m, ptr);
|
||||
mempool_uint_clear(m); // Give back memory to system
|
||||
NOTE: Can not use m-list since it may be expanded from LIST_DEF
|
||||
*/
|
||||
#define MEMPOOL_DEF(name, type) \
|
||||
MEMPOOL_DEF_AS(name, M_C(name,_t), type)
|
||||
#define M_MEMPOOL_DEF(name, type) \
|
||||
M_MEMPOOL_DEF_AS(name, M_F(name,_t), type)
|
||||
|
||||
|
||||
/* Fast Fixed Size thread unsafe allocator based on memory region.
|
||||
/* Fast, fixed Size, thread unsafe allocator based on memory region.
|
||||
USAGE:
|
||||
MEMPOOL_DEF_AS(memppol_uint, name_t, unsigned int)
|
||||
MEMPOOL_DEF_AS(name, name_t, type)
|
||||
*/
|
||||
#define MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
#define M_MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_M3MPOOL_DEF_P2(name, type, name_t ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* User shall be able to cutomize the size of the segment and/or
|
||||
/* User shall be able to cutomize the size of the region segment and/or
|
||||
the minimun number of elements.
|
||||
The default is the number of elements that fits in 16KB.
|
||||
The default is the number of elements that fits in 16KB, or 256
|
||||
is the size of the type is too big.
|
||||
*/
|
||||
#ifndef M_USE_MEMPOOL_MAX_PER_SEGMENT
|
||||
#define M_USE_MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
@@ -63,40 +66,56 @@
|
||||
#endif
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/*****************************************************************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
Technically, it uses a list of memory regions, where multiple
|
||||
allocations are performed in each region. However, it
|
||||
can not use m-list since it may be expanded from LIST_DEF
|
||||
(recursive dependency problem). */
|
||||
#define M_M3MPOOL_DEF_P2(name, type, name_t) \
|
||||
M_M3MPOOL_DEF_TYPE(name, type, name_t) \
|
||||
M_M3MPOOL_DEF_CORE(name, type, name_t)
|
||||
|
||||
/* Define the types of the mempool */
|
||||
#define M_M3MPOOL_DEF_TYPE(name, type, name_t) \
|
||||
\
|
||||
/* Define the type of element in a segment of the mempool. \
|
||||
Either it is the basic type or a pointer to another one. */ \
|
||||
typedef union M_C(name,_union_s) { \
|
||||
typedef union M_F(name,_union_s) { \
|
||||
type t; \
|
||||
union M_C(name,_union_s) *next; \
|
||||
} M_C(name,_union_ct); \
|
||||
union M_F(name,_union_s) *next; \
|
||||
} M_F(name,_union_ct); \
|
||||
\
|
||||
/* Define a segment of a mempool. \
|
||||
It is an array of basic type, each segment is in a linked list */ \
|
||||
typedef struct M_C(name,_segment_s) { \
|
||||
typedef struct M_F(name,_segment_s) { \
|
||||
unsigned int count; \
|
||||
struct M_C(name,_segment_s) *next; \
|
||||
M_C(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_C(name,_segment_ct); \
|
||||
struct M_F(name,_segment_s) *next; \
|
||||
M_F(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_F(name,_segment_ct); \
|
||||
\
|
||||
/* Define a mempool. \
|
||||
It is a pointer to the first free object within the segments \
|
||||
and the segments themselves */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name,_union_ct) *free_list; \
|
||||
M_C(name,_segment_ct) *current_segment; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name,_union_ct) *free_list; \
|
||||
M_F(name,_segment_ct) *current_segment; \
|
||||
} name_t[1]; \
|
||||
|
||||
|
||||
/* Define the core functions of the mempool */
|
||||
#define M_M3MPOOL_DEF_CORE(name, type, name_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_init)(name_t mem) \
|
||||
M_INLINE void \
|
||||
M_F(name,_init)(name_t mem) \
|
||||
{ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = M_MEMORY_ALLOC(M_C(name,_segment_ct)); \
|
||||
if (mem->current_segment == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
mem->current_segment = M_MEMORY_ALLOC(M_F(name,_segment_ct)); \
|
||||
if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \
|
||||
return; \
|
||||
} \
|
||||
mem->current_segment->next = NULL; \
|
||||
@@ -104,13 +123,13 @@
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_clear)(name_t mem) \
|
||||
M_INLINE void \
|
||||
M_F(name,_clear)(name_t mem) \
|
||||
{ \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
M_F(name,_segment_ct) *segment = mem->current_segment; \
|
||||
while (segment != NULL) { \
|
||||
M_C(name,_segment_ct) *next = segment->next; \
|
||||
M_F(name,_segment_ct) *next = segment->next; \
|
||||
M_MEMORY_DEL (segment); \
|
||||
segment = next; \
|
||||
} \
|
||||
@@ -119,26 +138,26 @@
|
||||
mem->current_segment = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name,_alloc)(name_t mem) \
|
||||
M_INLINE type * \
|
||||
M_F(name,_alloc)(name_t mem) \
|
||||
{ \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
/* Test if one object is in the free list */ \
|
||||
M_C(name,_union_ct) *ret = mem->free_list; \
|
||||
M_F(name,_union_ct) *ret = mem->free_list; \
|
||||
if (ret != NULL) { \
|
||||
/* Yes, so return it, and pop it from the free list */ \
|
||||
mem->free_list = ret->next; \
|
||||
return &ret->t; \
|
||||
} \
|
||||
/* No cheap free object exist. Test within a segment */ \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
M_F(name,_segment_ct) *segment = mem->current_segment; \
|
||||
M_ASSERT(segment != NULL); \
|
||||
unsigned int count = segment->count; \
|
||||
/* If segment is full, allocate a new one from the system */ \
|
||||
if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
M_C(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_ct)); \
|
||||
if (M_UNLIKELY (new_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_F(name,_segment_ct)); \
|
||||
if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \
|
||||
return NULL; \
|
||||
} \
|
||||
new_segment->next = segment; \
|
||||
@@ -154,13 +173,13 @@
|
||||
return &ret->t; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_free)(name_t mem, type *ptr) \
|
||||
M_INLINE void \
|
||||
M_F(name,_free)(name_t mem, type *ptr) \
|
||||
{ \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
/* NOTE: Unsafe cast: suppose that the given pointer \
|
||||
was allocated by the previous alloc function. */ \
|
||||
M_C(name,_union_ct) *ret = (M_C(name,_union_ct) *)(uintptr_t)ptr; \
|
||||
M_F(name,_union_ct) *ret = (M_F(name,_union_ct) *)(uintptr_t)ptr; \
|
||||
/* Add the object back in the free list */ \
|
||||
ret->next = mem->free_list; \
|
||||
mem->free_list = ret; \
|
||||
@@ -169,11 +188,19 @@
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
} \
|
||||
|
||||
/* MEMPOOL contract */
|
||||
/* MEMPOOL contract. We only control the current segment. */
|
||||
#define M_M3MPOOL_CONTRACT(mempool, type) do { \
|
||||
M_ASSERT((mempool) != NULL); \
|
||||
M_ASSERT((mempool)->current_segment != NULL); \
|
||||
M_ASSERT((mempool)->current_segment->count <= M_USE_MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define MEMPOOL_DEF M_MEMPOOL_DEF
|
||||
#define MEMPOOL_DEF_AS M_MEMPOOL_DEF_AS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin Mutex & Thread wrapper
|
||||
* M*LIB - Thin Mutex & Thread wrapper (compatibility layer)
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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,506 +22,7 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef MSTARLIB_MUTEX_H
|
||||
#define MSTARLIB_MUTEX_H
|
||||
|
||||
/* Auto-detect the thread backend to use if the user has not override it */
|
||||
#ifndef M_USE_THREAD_BACKEND
|
||||
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
|
||||
&& !defined(__STDC_NO_THREADS__)
|
||||
# define M_USE_THREAD_BACKEND 1
|
||||
# elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
# define M_USE_THREAD_BACKEND 2
|
||||
# else
|
||||
# define M_USE_THREAD_BACKEND 3
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/****************************** C11 version ********************************/
|
||||
#if M_USE_THREAD_BACKEND == 1
|
||||
|
||||
#include <threads.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a mutex type based on C11 definition */
|
||||
typedef mtx_t m_mutex_t[1];
|
||||
|
||||
/* Define a condition variable type based on C11 definition */
|
||||
typedef cnd_t m_cond_t[1];
|
||||
|
||||
/* Define a thread type based on C11 definition */
|
||||
typedef thrd_t m_thread_t[1];
|
||||
|
||||
/* Initialize the mutex (constructor) */
|
||||
static inline void m_mutex_init(m_mutex_t m)
|
||||
{
|
||||
int rc = mtx_init(m, mtx_plain);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if a mutex cannot be constructed
|
||||
M_ASSERT_INIT (rc == 0, "mutex");
|
||||
}
|
||||
|
||||
/* Clear the mutex (destructor) */
|
||||
static inline void m_mutex_clear(m_mutex_t m)
|
||||
{
|
||||
mtx_destroy(m);
|
||||
}
|
||||
|
||||
/* Lock the mutex */
|
||||
static inline void m_mutex_lock(m_mutex_t m)
|
||||
{
|
||||
mtx_lock(m);
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
static inline void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
mtx_unlock(m);
|
||||
}
|
||||
|
||||
/* Initialize the condition variable (constructor) */
|
||||
static inline void m_cond_init(m_cond_t c)
|
||||
{
|
||||
int rc = cnd_init(c);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if the object cannot be constructed
|
||||
M_ASSERT_INIT (rc == 0, "conditional variable");
|
||||
}
|
||||
|
||||
/* Clear the condition variable (destructor) */
|
||||
static inline void m_cond_clear(m_cond_t c)
|
||||
{
|
||||
cnd_destroy(c);
|
||||
}
|
||||
|
||||
/* Signal the condition variable to at least one waiting thread */
|
||||
static inline void m_cond_signal(m_cond_t c)
|
||||
{
|
||||
cnd_signal(c);
|
||||
}
|
||||
|
||||
/* Signal the condition variable to all waiting threads */
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
cnd_broadcast(c);
|
||||
}
|
||||
|
||||
/* Wait for signaling the condition variable by another thread */
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
cnd_wait(c, m);
|
||||
}
|
||||
|
||||
/* Create the thread (constructor) and start it */
|
||||
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void* arg)
|
||||
{
|
||||
int rc = thrd_create(t, (int(*)(void*))(void(*)(void))func, arg);
|
||||
// Abort program in case of initialization failure
|
||||
M_ASSERT_INIT (rc == thrd_success, "thread");
|
||||
}
|
||||
|
||||
/* Wait for the thread to terminate and destroy it (destructor) */
|
||||
static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
int rc = thrd_join(*t, NULL);
|
||||
M_ASSERT (rc == thrd_success);
|
||||
// Avoid warning about variable unused.
|
||||
(void) rc;
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
static inline void m_thread_yield(void)
|
||||
{
|
||||
thrd_yield();
|
||||
}
|
||||
|
||||
/* Sleep the thread for at least usec microseconds.
|
||||
Return true if the sleep was successful */
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
struct timespec tv;
|
||||
tv.tv_sec = (long) (usec / 1000000ULL);
|
||||
tv.tv_nsec = (long) ((usec % 1000000ULL) * 1000UL);
|
||||
int retval = thrd_sleep(&tv, NULL);
|
||||
return retval == 0;
|
||||
}
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef once_flag m_once_ct[1];
|
||||
|
||||
// Initial value for m_once_ct
|
||||
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
|
||||
|
||||
// Call the function exactly once
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
{
|
||||
call_once(o,func);
|
||||
}
|
||||
|
||||
// Attribute to use to allocate a global variable to a thread.
|
||||
#define M_THREAD_ATTR _Thread_local
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/****************************** WIN32 version ******************************/
|
||||
#elif M_USE_THREAD_BACKEND == 2
|
||||
|
||||
/* CLANG provides some useless and wrong warnings:
|
||||
* - _WIN32_WINNT starts with '_' which is reserved by the standard
|
||||
* as per the MSVC compiler, it is needed to be defined by the user
|
||||
* to define which version of windows it want to be compatible with.
|
||||
* - windows.h may be different than the case used by the file sytem
|
||||
* there is however no normalized case.
|
||||
*
|
||||
* So, theses warnings have to be ignored and are disabled.
|
||||
*
|
||||
* We cannot add theses warnings in M_BEGIN_PROTECTED_CODE
|
||||
* as they need to be disabled **BEFORE** including any system header
|
||||
* and m-core includes some system headers.
|
||||
* So we need to disable them explictly here.
|
||||
*/
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
|
||||
_Pragma("clang diagnostic ignored \"-Wnonportable-system-include-path\"")
|
||||
#endif
|
||||
|
||||
/* CriticalSection & ConditionVariable are available from Windows Vista */
|
||||
#ifndef WINVER
|
||||
#define WINVER _WIN32_WINNT_VISTA
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#endif
|
||||
|
||||
/* Include system headers */
|
||||
#include <windows.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic pop")
|
||||
#endif
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a thread type based on WINDOWS definition */
|
||||
typedef HANDLE m_thread_t[1];
|
||||
|
||||
/* Define a mutex type based on WINDOWS definition */
|
||||
typedef CRITICAL_SECTION m_mutex_t[1];
|
||||
|
||||
/* Define a condition variable type based on WINDOWS definition */
|
||||
typedef CONDITION_VARIABLE m_cond_t[1];
|
||||
|
||||
/* Initialize a mutex (Constructor)*/
|
||||
static inline void m_mutex_init(m_mutex_t m)
|
||||
{
|
||||
InitializeCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Clear a mutex (destructor) */
|
||||
static inline void m_mutex_clear(m_mutex_t m)
|
||||
{
|
||||
DeleteCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Lock a mutex */
|
||||
static inline void m_mutex_lock(m_mutex_t m)
|
||||
{
|
||||
EnterCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Unlock a mutex */
|
||||
static inline void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
LeaveCriticalSection(m);
|
||||
}
|
||||
|
||||
/* Initialize a condition variable (constructor) */
|
||||
static inline void m_cond_init(m_cond_t c)
|
||||
{
|
||||
InitializeConditionVariable(c);
|
||||
}
|
||||
|
||||
/* Clear a condition variable (destructor) */
|
||||
static inline void m_cond_clear(m_cond_t c)
|
||||
{
|
||||
(void) c; // There is no destructor for this object.
|
||||
}
|
||||
|
||||
/* Signal a condition variable to at least one waiting thread */
|
||||
static inline void m_cond_signal(m_cond_t c)
|
||||
{
|
||||
WakeConditionVariable(c);
|
||||
}
|
||||
|
||||
/* Signal a condition variable to all waiting threads */
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
WakeAllConditionVariable(c);
|
||||
}
|
||||
|
||||
/* Wait for a condition variable */
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
SleepConditionVariableCS(c, m, INFINITE);
|
||||
}
|
||||
|
||||
/* Create a thread (constructor) and start it */
|
||||
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
|
||||
{
|
||||
*t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) (uintptr_t) func, arg, 0, NULL);
|
||||
M_ASSERT_INIT (*t != NULL, "thread");
|
||||
}
|
||||
|
||||
/* Wait for the thread to terminate and destroy it (destructor) */
|
||||
static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
DWORD dwWaitResult = WaitForSingleObject(*t, INFINITE);
|
||||
(void) dwWaitResult;
|
||||
M_ASSERT (dwWaitResult == WAIT_OBJECT_0);
|
||||
CloseHandle(*t);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
static inline void m_thread_yield(void)
|
||||
{
|
||||
Sleep(0);
|
||||
}
|
||||
|
||||
/* Sleep the thread for at least usec microseconds
|
||||
Return true if the sleep was successful */
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
LARGE_INTEGER ft;
|
||||
M_ASSERT (usec <= LLONG_MAX);
|
||||
ft.QuadPart = -(10LL*(long long) usec);
|
||||
HANDLE hd = CreateWaitableTimer(NULL, TRUE, NULL);
|
||||
M_ASSERT_INIT (hd != NULL, "timer");
|
||||
SetWaitableTimer(hd, &ft, 0, NULL, NULL, 0);
|
||||
DWORD dwWaitResult = WaitForSingleObject(hd, INFINITE);
|
||||
CloseHandle(hd);
|
||||
return dwWaitResult == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef INIT_ONCE m_once_ct[1];
|
||||
#define M_ONCEI_INIT_VALUE { INIT_ONCE_STATIC_INIT }
|
||||
static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
|
||||
{
|
||||
void (*func)(void);
|
||||
(void) InitOnce;
|
||||
(void) lpContext;
|
||||
func = (void (*)(void))(uintptr_t) Parameter;
|
||||
(*func)();
|
||||
return TRUE;
|
||||
}
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
{
|
||||
InitOnceExecuteOnce(o, m_oncei_callback, (void*)(intptr_t)func, NULL);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Attribute to use to allocate a global variable to a thread (MSVC def).
|
||||
# define M_THREAD_ATTR __declspec( thread )
|
||||
#else
|
||||
// Attribute to use to allocate a global variable to a thread (GCC def).
|
||||
# define M_THREAD_ATTR __thread
|
||||
#endif
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/**************************** PTHREAD version ******************************/
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
#ifdef _POSIX_PRIORITY_SCHEDULING
|
||||
#include <sched.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "m-core.h"
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a mutex type based on PTHREAD definition */
|
||||
typedef pthread_mutex_t m_mutex_t[1];
|
||||
|
||||
/* Define a condition variable type based on PTHREAD definition */
|
||||
typedef pthread_cond_t m_cond_t[1];
|
||||
|
||||
/* Define a thread type based on PTHREAD definition */
|
||||
typedef pthread_t m_thread_t[1];
|
||||
|
||||
/* Initialize the mutex (constructor) */
|
||||
static inline void m_mutex_init(m_mutex_t m)
|
||||
{
|
||||
int _rc = pthread_mutex_init(m, NULL);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if a mutex cannot be constructed
|
||||
M_ASSERT_INIT (_rc == 0, "mutex");
|
||||
}
|
||||
|
||||
/* Clear the mutex (destructor) */
|
||||
static inline void m_mutex_clear(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_destroy(m);
|
||||
}
|
||||
|
||||
/* Lock the mutex */
|
||||
static inline void m_mutex_lock(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_lock(m);
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
static inline void m_mutex_unlock(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_unlock(m);
|
||||
}
|
||||
|
||||
/* Lazy lock initialization */
|
||||
#define M_MUTEXI_INIT_VALUE { PTHREAD_MUTEX_INITIALIZER }
|
||||
|
||||
/* Internal function compatible with lazy lock */
|
||||
static inline void m_mutexi_lazy_lock(m_mutex_t m)
|
||||
{
|
||||
pthread_mutex_lock(m);
|
||||
}
|
||||
|
||||
/* Initialize the condition variable (constructor) */
|
||||
static inline void m_cond_init(m_cond_t c)
|
||||
{
|
||||
int _rc = pthread_cond_init(c, NULL);
|
||||
// Abort program in case of initialization failure
|
||||
// There is really nothing else to do if a mutex cannot be constructed
|
||||
M_ASSERT_INIT (_rc == 0, "conditional variable");
|
||||
}
|
||||
|
||||
/* Clear the condition variable (destructor) */
|
||||
static inline void m_cond_clear(m_cond_t c)
|
||||
{
|
||||
pthread_cond_destroy(c);
|
||||
}
|
||||
|
||||
/* Signal a condition variable to at least a waiting thread */
|
||||
static inline void m_cond_signal(m_cond_t c)
|
||||
{
|
||||
pthread_cond_signal(c);
|
||||
}
|
||||
|
||||
/* Signal a condition variable to all waiting threads */
|
||||
static inline void m_cond_broadcast(m_cond_t c)
|
||||
{
|
||||
pthread_cond_broadcast(c);
|
||||
}
|
||||
|
||||
/* Waiting for a condition variable */
|
||||
static inline void m_cond_wait(m_cond_t c, m_mutex_t m)
|
||||
{
|
||||
pthread_cond_wait(c, m);
|
||||
}
|
||||
|
||||
/* Create a thread (constructor) and start it */
|
||||
static inline void m_thread_create(m_thread_t t, void (*func)(void*), void *arg)
|
||||
{
|
||||
int _rc = pthread_create(t, NULL, (void*(*)(void*))(void(*)(void))func, arg);
|
||||
M_ASSERT_INIT (_rc == 0, "thread");
|
||||
}
|
||||
|
||||
/* Wait for the thread to terminate and destroy it (destructor) */
|
||||
static inline void m_thread_join(m_thread_t t)
|
||||
{
|
||||
int _rc = pthread_join(*t, NULL);
|
||||
(void)_rc; // Avoid warning about variable unused.
|
||||
M_ASSERT (_rc == 0);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
static inline void m_thread_yield(void)
|
||||
{
|
||||
#ifdef _POSIX_PRIORITY_SCHEDULING
|
||||
sched_yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Sleep for at least usec microseconds
|
||||
Return true if the sleep was successful */
|
||||
static inline bool m_thread_sleep(unsigned long long usec)
|
||||
{
|
||||
struct timeval tv;
|
||||
/* We don't want to use usleep or nanosleep so that
|
||||
we remain compatible with strict C99 build */
|
||||
tv.tv_sec = (time_t) (usec / 1000000ULL);
|
||||
tv.tv_usec = (suseconds_t) (usec % 1000000ULL);
|
||||
int retval = select(1, NULL, NULL, NULL, &tv);
|
||||
return retval == 0;
|
||||
}
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef pthread_once_t m_once_ct[1];
|
||||
#define M_ONCEI_INIT_VALUE { PTHREAD_ONCE_INIT }
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
{
|
||||
pthread_once(o,func);
|
||||
}
|
||||
|
||||
#define M_THREAD_ATTR __thread
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#endif
|
||||
|
||||
// TODO: Obsolete M_LOCK macro.
|
||||
|
||||
/* M_LOCK macro. Allow simple locking encapsulation.
|
||||
USAGE:
|
||||
static M_LOCK_DECL(name);
|
||||
int f(int n) {
|
||||
M_LOCK(name) {
|
||||
// Exclusive access
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* NOTE: Either using direct support by the OS (WIN32/PTHREAD)
|
||||
or using C11's ONCE mechanism */
|
||||
#ifdef M_MUTEXI_INIT_VALUE
|
||||
# define M_LOCK_DECL(name) m_mutex_t name = M_MUTEXI_INIT_VALUE
|
||||
# define M_LOCK(name) \
|
||||
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), m_mutexi_lazy_lock, m_mutex_unlock)
|
||||
#else
|
||||
# define M_LOCK_DECL(name) \
|
||||
m_mutex_t name; \
|
||||
static void M_C(m_mutex_init_, name)(void) { \
|
||||
m_mutex_init(name); \
|
||||
} \
|
||||
m_once_ct M_C(m_once_, name) = M_ONCEI_INIT_VALUE
|
||||
# define M_LOCKI_BY_ONCE(name) \
|
||||
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
m_mutex_lock(name), (void) 0 )
|
||||
# define M_LOCK(name) \
|
||||
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), M_LOCKI_BY_ONCE, m_mutex_unlock)
|
||||
#endif
|
||||
|
||||
#define M_LOCKI_DO(name, cont, lock_func, unlock_func) \
|
||||
for(bool cont = true \
|
||||
; cont && (lock_func (name), true); \
|
||||
(unlock_func (name), cont = false))
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
#warning "m-mutex.h is an obsolete header. Use m-thread.h instead."
|
||||
#endif
|
||||
#include "m-thread.h"
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -32,14 +32,14 @@
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
PRIOQUEUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_PRIOQUEUE_DEF(name, ...) \
|
||||
M_PRIOQUEUE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
as the name name_t with an iterator named it_t
|
||||
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_PR1OQUEUE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
@@ -49,14 +49,15 @@
|
||||
|
||||
/* Define the oplist of a prioqueue of type.
|
||||
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
#define M_PRIOQUEUE_OPLIST(...) \
|
||||
M_PR1OQUEUE_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/*****************************************************************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
@@ -72,38 +73,46 @@
|
||||
|
||||
/* Define oplist of a priority queue */
|
||||
#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
(INIT(M_F(name, _init)) \
|
||||
,INIT_SET(M_F(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,INIT_MOVE(M_C(name, _init_move)) \
|
||||
,MOVE(M_C(name, _move)) \
|
||||
,SWAP(M_C(name, _swap)) \
|
||||
,SET(M_F(name, _set)) \
|
||||
,CLEAR(M_F(name, _clear)) \
|
||||
,INIT_MOVE(M_F(name, _init_move)) \
|
||||
,MOVE(M_F(name, _move)) \
|
||||
,SWAP(M_F(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,RESET(M_F(name,_reset)) \
|
||||
,PUSH(M_F(name,_push)) \
|
||||
,POP(M_F(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,EMPTY_P(M_C(name, _empty_p)), \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,IT_TYPE(M_C(name, _it_ct)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
,EMPTY_P(M_F(name, _empty_p)) \
|
||||
,GET_SIZE(M_F(name, _size)) \
|
||||
,IT_TYPE(M_F(name, _it_ct)) \
|
||||
,IT_FIRST(M_F(name,_it)) \
|
||||
,IT_END(M_F(name,_it_end)) \
|
||||
,IT_SET(M_F(name,_it_set)) \
|
||||
,IT_END_P(M_F(name,_end_p)) \
|
||||
,IT_EQUAL_P(M_F(name,_it_equal_p)) \
|
||||
,IT_LAST_P(M_F(name,_last_p)) \
|
||||
,IT_NEXT(M_F(name,_next)) \
|
||||
,IT_CREF(M_F(name,_cref)) \
|
||||
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \
|
||||
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),) \
|
||||
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
|
||||
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_F(name, _in_str)),) \
|
||||
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),) \
|
||||
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \
|
||||
)
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_PR1OQUEUE_DEF_P1(arg) M_PR1OQUEUE_DEF_P2 arg
|
||||
#define M_PR1OQUEUE_DEF_P1(arg) M_ID( M_PR1OQUEUE_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_PR1OQUEUE_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
@@ -121,322 +130,391 @@
|
||||
- it_t: iterator of the container
|
||||
*/
|
||||
#define M_PR1OQUEUE_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
/* Definition of the internal array used to construct the priority queue */ \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
ARRAY_DEF(M_F(name, _array), type, oplist) \
|
||||
M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
|
||||
|
||||
/* Define the types */
|
||||
#define M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
/* Define the priority queue over the defined array */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _array_t) array; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _array_t) array; \
|
||||
} prioqueue_t[1]; \
|
||||
/* Define the pointer references to the priority queue */ \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
\
|
||||
/* The iterator is the same one as the one of the internal array */ \
|
||||
typedef M_C(name, _array_it_t) it_t; \
|
||||
typedef M_F(name, _array_it_t) it_t; \
|
||||
\
|
||||
/* Definition of the internal types used by the oplist */ \
|
||||
typedef prioqueue_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef it_t M_C(name, _it_ct); \
|
||||
typedef prioqueue_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef it_t M_F(name, _it_ct); \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(prioqueue_t p) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_init)(p->array); \
|
||||
M_F(name, _array_init)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_init_set)(p->array, o->array); \
|
||||
M_F(name, _array_init_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(prioqueue_t p, prioqueue_t const o) \
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_set)(p->array, o->array); \
|
||||
M_F(name, _array_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(prioqueue_t p) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clear)(p->array); \
|
||||
M_F(name, _array_clear)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_init_move)(p->array, o->array); \
|
||||
M_F(name, _array_init_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
|
||||
M_INLINE void \
|
||||
M_F(name, _move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_move)(p->array, o->array); \
|
||||
M_F(name, _array_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
|
||||
M_INLINE void \
|
||||
M_F(name, _swap)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_swap)(p->array, o->array); \
|
||||
M_F(name, _array_swap)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reset)(prioqueue_t p) \
|
||||
M_INLINE void \
|
||||
M_F(name, _reset)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_reset)(p->array); \
|
||||
M_F(name, _array_reset)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name,_reset)(p); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_parent)(size_t i) \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _i_parent)(size_t i) \
|
||||
{ \
|
||||
M_ASSERT (i > 0); \
|
||||
return (i - 1) / 2; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_lchild)(size_t i) \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _i_lchild)(size_t i) \
|
||||
{ \
|
||||
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 1; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_rchild)(size_t i) \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _i_rchild)(size_t i) \
|
||||
{ \
|
||||
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 2; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
|
||||
M_INLINE int \
|
||||
M_F(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
|
||||
{ \
|
||||
return M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), \
|
||||
*M_C(name, _array_cget)(p->array, j)); \
|
||||
return M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), \
|
||||
*M_F(name, _array_cget)(p->array, j)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(prioqueue_t const p) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _empty_p)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_empty_p)(p->array); \
|
||||
return M_F(name, _array_empty_p)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(prioqueue_t const p) \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _size)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_size)(p->array); \
|
||||
return M_F(name, _array_size)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(prioqueue_t p, type const x) \
|
||||
M_INLINE void \
|
||||
M_F(name, _push)(prioqueue_t p, type const x) \
|
||||
{ \
|
||||
/* Push back the new element at the end of the array */ \
|
||||
M_C(name, _array_push_back)(p->array, x); \
|
||||
M_F(name, _array_push_back)(p->array, x); \
|
||||
\
|
||||
/* Reorder the array by swapping with its parent \
|
||||
* until it reaches the right position */ \
|
||||
size_t i = M_C(name, _array_size)(p->array)-1; \
|
||||
size_t i = M_F(name, _array_size)(p->array)-1; \
|
||||
while (i > 0) { \
|
||||
size_t j = M_C(name, _i_parent)(i); \
|
||||
if (M_C(name, _i_cmp)(p, j, i) <= 0) \
|
||||
size_t j = M_F(name, _i_parent)(i); \
|
||||
if (M_F(name, _i_cmp)(p, j, i) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, j); \
|
||||
M_F(name, _array_swap_at) (p->array, i, j); \
|
||||
i = j; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _front)(prioqueue_t const p) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _front)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_cget)(p->array, 0); \
|
||||
return M_F(name, _array_cget)(p->array, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop)(type *x, prioqueue_t p) \
|
||||
M_INLINE void \
|
||||
M_F(name, _pop)(type *x, prioqueue_t p) \
|
||||
{ \
|
||||
/* Swap the front element with the last element */ \
|
||||
size_t size = M_C(name, _array_size)(p->array)-1; \
|
||||
M_C(name, _array_swap_at) (p->array, 0, size); \
|
||||
size_t size = M_F(name, _array_size)(p->array)-1; \
|
||||
M_F(name, _array_swap_at) (p->array, 0, size); \
|
||||
/* Swap the new last element */ \
|
||||
M_C(name, _array_pop_back)(x, p->array); \
|
||||
M_F(name, _array_pop_back)(x, p->array); \
|
||||
\
|
||||
/* Reorder the heap */ \
|
||||
size_t i = 0; \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
size_t child = M_F(name, _i_lchild)(i); \
|
||||
if (child >= size) \
|
||||
break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
size_t otherChild = M_F(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) \
|
||||
if (M_F(name, _i_cmp)(p, i, child) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
M_F(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Define iterators over the array iterator */ \
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_last)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_end)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t org) \
|
||||
{ \
|
||||
M_C(name, _array_it_set)(it, org); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_end_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_last_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
{ \
|
||||
return M_C(name, _array_it_equal_p)(it1, it2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_next)(it); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_previous)(it); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_cref)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist) \
|
||||
( \
|
||||
/* EQUAL & CMP may be uncorrelated */ \
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(prioqueue_t const p, prioqueue_t const q) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _equal_p)(prioqueue_t const p, prioqueue_t const q) \
|
||||
{ \
|
||||
return M_C(name, _array_equal_p)(p->array, q->array); \
|
||||
return M_F(name, _array_equal_p)(p->array, q->array); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _erase)(prioqueue_t p, type x) \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _i_find)(prioqueue_t p, type const x) \
|
||||
{ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
/* NOTE: An HASHMAP may be a good idea to optimize this pass. */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t size = M_F(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
|
||||
/* We cannot use CMP and the partial order to go faster \
|
||||
EQUAL & CMP may be uncorrelated */ \
|
||||
if (M_CALL_EQUAL(oplist, *M_F(name, _array_cget)(p->array, i), x)) \
|
||||
break; \
|
||||
} \
|
||||
return i; \
|
||||
} \
|
||||
\
|
||||
M_INLINE bool \
|
||||
M_F(name, _erase)(prioqueue_t p, type const x) \
|
||||
{ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
size_t size = M_F(name, _array_size)(p->array); \
|
||||
size_t i = M_F(name, _i_find)(p, x); \
|
||||
/* If x is not found, then stop */ \
|
||||
if (i >= size) \
|
||||
return false; \
|
||||
/* Swap the found item and the last element */ \
|
||||
size--; \
|
||||
M_C(name, _array_swap_at) (p->array, i, size); \
|
||||
M_C(name, _array_pop_back)(NULL, p->array); \
|
||||
M_F(name, _array_swap_at) (p->array, i, size); \
|
||||
M_F(name, _array_pop_back)(NULL, p->array); \
|
||||
/* Move back the last swapped element to its right position in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
size_t child = M_F(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
size_t otherChild = M_F(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
if (M_F(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_F(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _update)(prioqueue_t p, type const xold, type const xnew) \
|
||||
M_INLINE void \
|
||||
M_F(name, _update)(prioqueue_t p, type const xold, type const xnew) \
|
||||
{ \
|
||||
/* NOTE: xold can be the same pointer than xnew */ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), xold)) \
|
||||
break; \
|
||||
} \
|
||||
size_t size = M_F(name, _array_size)(p->array); \
|
||||
size_t i = M_F(name, _i_find)(p, xold); \
|
||||
/* We shall have found the item */ \
|
||||
M_ASSERT (i < size); \
|
||||
/* Test if the position of the old data is further or nearer than the new */ \
|
||||
int cmp = M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), xnew); \
|
||||
int cmp = M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), xnew); \
|
||||
/* Set the found item to the new element */ \
|
||||
M_C(name, _array_set_at) (p->array, i, xnew); \
|
||||
M_F(name, _array_set_at) (p->array, i, xnew); \
|
||||
if (cmp < 0) { \
|
||||
/* Move back the updated element to its new position, further in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
size_t child = M_F(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
size_t otherChild = M_F(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
if (M_F(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_F(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} else { \
|
||||
/* Move back the updated element to its new position, nearest in the heap */ \
|
||||
while (i > 0) { \
|
||||
size_t parent = M_C(name, _i_parent)(i); \
|
||||
if (M_C(name, _i_cmp)(p, parent, i) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, parent); \
|
||||
size_t parent = M_F(name, _i_parent)(i); \
|
||||
if (M_F(name, _i_cmp)(p, parent, i) <= 0) break; \
|
||||
M_F(name, _array_swap_at) (p->array, i, parent); \
|
||||
i = parent; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
, /* No EQUAL */ ) \
|
||||
|
||||
/* Define the IT based functions */
|
||||
#define M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
/* Define iterators over the array iterator */ \
|
||||
M_INLINE void \
|
||||
M_F(name, _it)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_F(name, _array_it)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _it_last)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_F(name, _array_it_last)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _it_end)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_F(name, _array_it_end)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _it_set)(it_t it, const it_t org) \
|
||||
{ \
|
||||
M_F(name, _array_it_set)(it, org); \
|
||||
} \
|
||||
\
|
||||
M_INLINE bool \
|
||||
M_F(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
return M_F(name, _array_end_p)(it); \
|
||||
} \
|
||||
\
|
||||
M_INLINE bool \
|
||||
M_F(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
return M_F(name, _array_last_p)(it); \
|
||||
} \
|
||||
\
|
||||
M_INLINE bool \
|
||||
M_F(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
{ \
|
||||
return M_F(name, _array_it_equal_p)(it1, it2); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_F(name, _array_next)(it); \
|
||||
} \
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_F(name, _array_previous)(it); \
|
||||
} \
|
||||
\
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_F(name, _array_cref)(it); \
|
||||
} \
|
||||
|
||||
/* Define the IO functions */
|
||||
#define M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
M_INLINE void \
|
||||
M_F(name, _out_str)(FILE *file, const prioqueue_t p) \
|
||||
{ \
|
||||
M_F(name, _array_out_str)(file, p->array); \
|
||||
} \
|
||||
,/* No OUT_STR */) \
|
||||
\
|
||||
M_IF_METHOD(IN_STR, oplist)( \
|
||||
M_INLINE bool \
|
||||
M_F(name, _in_str)(prioqueue_t p, FILE *file) \
|
||||
{ \
|
||||
return M_F(name, _array_in_str)(p->array, file); \
|
||||
} \
|
||||
,/* No IN_STR */) \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
M_INLINE void \
|
||||
M_F(name, _get_str)(string_t str, const prioqueue_t p, bool append) \
|
||||
{ \
|
||||
M_F(name, _array_get_str)(str, p->array, append); \
|
||||
} \
|
||||
,/* No GET_STR */) \
|
||||
\
|
||||
M_IF_METHOD(PARSE_STR, oplist)( \
|
||||
M_INLINE bool \
|
||||
M_F(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \
|
||||
{ \
|
||||
return M_F(name, _array_parse_str)(p->array, str, endp); \
|
||||
} \
|
||||
,/* No PARSE_STR */) \
|
||||
\
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)( \
|
||||
M_INLINE m_serial_return_code_t \
|
||||
M_F(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \
|
||||
{ \
|
||||
return M_F(name, _array_out_serial)(f, p->array); \
|
||||
} \
|
||||
,/* No OUT_SERIAL */) \
|
||||
\
|
||||
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
|
||||
M_INLINE m_serial_return_code_t \
|
||||
M_F(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \
|
||||
{ \
|
||||
return M_F(name, _array_in_serial)(p->array, f); \
|
||||
} \
|
||||
,/* No in_SERIAL */) \
|
||||
|
||||
|
||||
// TODO: set all & remove all function
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define PRIOQUEUE_DEF M_PRIOQUEUE_DEF
|
||||
#define PRIOQUEUE_DEF_AS M_PRIOQUEUE_DEF_AS
|
||||
#define PRIOQUEUE_OPLIST M_PRIOQUEUE_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - RED BLACK TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -29,26 +29,26 @@
|
||||
|
||||
/* Define a Red/Black binary tree of a given type.
|
||||
USAGE: RBTREE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define RBTREE_DEF(name, ...) \
|
||||
RBTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_RBTREE_DEF(name, ...) \
|
||||
M_RBTREE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Red/Black binary tree of a given type
|
||||
as the name name_t and the iterator it_t.
|
||||
USAGE: RBTREE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define RBTREE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_RBTREE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_RBTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, M_C(name, _node_ct), it_t ), \
|
||||
(name, __VA_ARGS__, name_t, M_C(name, _node_ct), it_t ))) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, M_F(name, _node_ct), it_t ), \
|
||||
(name, __VA_ARGS__, name_t, M_F(name, _node_ct), it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a rbtree of type.
|
||||
USAGE: RBTREE_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define RBTREE_OPLIST(...) \
|
||||
#define M_RBTREE_OPLIST(...) \
|
||||
M_RBTR33_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -72,48 +72,48 @@
|
||||
NOTE: IT_REF is not exported so that the container appears as not modifiable
|
||||
by algorithm.*/
|
||||
#define M_RBTR33_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
SET(M_C(name, _set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
(INIT(M_F(name, _init)), \
|
||||
INIT_SET(M_F(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_EMPLACE_VAI)), \
|
||||
SET(M_F(name, _set)), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
INIT_MOVE(M_F(name, _init_move)), \
|
||||
MOVE(M_F(name, _move)), \
|
||||
SWAP(M_F(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
GET_SIZE(M_C(name, _size)), \
|
||||
IT_TYPE(M_C(name, _it_ct)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_LAST(M_C(name,_it_last)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_PREVIOUS(M_C(name,_previous)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
IT_REMOVE(M_C(name,_remove)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
PUSH(M_C(name,_push)), \
|
||||
GET_MIN(M_C(name,_min)), \
|
||||
GET_MAX(M_C(name,_max)), \
|
||||
M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),), \
|
||||
M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),), \
|
||||
M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),), \
|
||||
M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),), \
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \
|
||||
M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),), \
|
||||
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),), \
|
||||
M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
|
||||
SUBTYPE(M_F(name, _subtype_ct)), \
|
||||
EMPTY_P(M_F(name,_empty_p)), \
|
||||
GET_SIZE(M_F(name, _size)), \
|
||||
IT_TYPE(M_F(name, _it_ct)), \
|
||||
IT_FIRST(M_F(name,_it)), \
|
||||
IT_SET(M_F(name,_it_set)), \
|
||||
IT_LAST(M_F(name,_it_last)), \
|
||||
IT_END(M_F(name,_it_end)), \
|
||||
IT_END_P(M_F(name,_end_p)), \
|
||||
IT_LAST_P(M_F(name,_last_p)), \
|
||||
IT_EQUAL_P(M_F(name,_it_equal_p)), \
|
||||
IT_NEXT(M_F(name,_next)), \
|
||||
IT_PREVIOUS(M_F(name,_previous)), \
|
||||
IT_CREF(M_F(name,_cref)), \
|
||||
IT_REMOVE(M_F(name,_remove)), \
|
||||
RESET(M_F(name,_reset)), \
|
||||
PUSH(M_F(name,_push)), \
|
||||
GET_MIN(M_F(name,_min)), \
|
||||
GET_MAX(M_F(name,_max)), \
|
||||
M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),), \
|
||||
M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),), \
|
||||
M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),), \
|
||||
M_IF_METHOD(IN_STR, oplist)(IN_STR(M_F(name, _in_str)),), \
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),), \
|
||||
M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),), \
|
||||
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \
|
||||
M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
|
||||
)
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Max depth of the binary tree
|
||||
It is at worst twice the depth of a perfectly even tree with maximum elements.
|
||||
The maximum number of elements is the max of size_t.
|
||||
@@ -122,10 +122,10 @@
|
||||
#define M_RBTR33_MAX_STACK (2*CHAR_BIT*sizeof (size_t))
|
||||
|
||||
/* Encapsulation of the color of the nodes. */
|
||||
#define M_RBTR33_SET_RED(x) ((x)->color = RBTREE_RED)
|
||||
#define M_RBTR33_SET_BLACK(x) ((x)->color = RBTREE_BLACK)
|
||||
#define M_RBTR33_IS_RED(x) ((x)->color == RBTREE_RED)
|
||||
#define M_RBTR33_IS_BLACK(x) ((x)->color == RBTREE_BLACK)
|
||||
#define M_RBTR33_SET_RED(x) ((x)->color = M_RBTR33_RED)
|
||||
#define M_RBTR33_SET_BLACK(x) ((x)->color = M_RBTR33_BLACK)
|
||||
#define M_RBTR33_IS_RED(x) ((x)->color == M_RBTR33_RED)
|
||||
#define M_RBTR33_IS_BLACK(x) ((x)->color == M_RBTR33_BLACK)
|
||||
#define M_RBTR33_COPY_COLOR(x,y) ((x)->color = (y)->color)
|
||||
#define M_RBTR33_GET_COLOR(x) (true ? (x)->color : (x)->color)
|
||||
#define M_RBTR33_SET_COLOR(x, c) ((x)->color = (c))
|
||||
@@ -134,8 +134,8 @@
|
||||
|
||||
// Color of a node of a Red/Black tree
|
||||
typedef enum {
|
||||
RBTREE_BLACK = 0, RBTREE_RED
|
||||
} rbtreei_color_e;
|
||||
M_RBTR33_BLACK = 0, M_RBTR33_RED
|
||||
} m_rbtr33_color_e;
|
||||
|
||||
// General contact of a Read/Black tree
|
||||
#define M_RBTR33_CONTRACT(tree) do { \
|
||||
@@ -156,7 +156,7 @@ typedef enum {
|
||||
|
||||
/* Deferred evaluation for the rbtree definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_RBTR33_DEF_P1(arg) M_RBTR33_DEF_P2 arg
|
||||
#define M_RBTR33_DEF_P1(arg) M_ID( M_RBTR33_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_RBTR33_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \
|
||||
@@ -175,73 +175,78 @@ typedef enum {
|
||||
- node_t: alias for the node of an element of the container
|
||||
*/
|
||||
#define M_RBTR33_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
|
||||
M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \
|
||||
M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \
|
||||
M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \
|
||||
M_EMPLACE_QUEUE_DEF(name, tree_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
|
||||
|
||||
/* Define the types associated to a R/B Tree */
|
||||
#define M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \
|
||||
\
|
||||
/* Node of Red/Black tree. \
|
||||
Each node has up to two child, a color (Red or black) \
|
||||
and the data stored in it */ \
|
||||
typedef struct M_C(name, _node_s) { \
|
||||
struct M_C(name, _node_s) *child[2]; \
|
||||
typedef struct M_F(name, _node_s) { \
|
||||
struct M_F(name, _node_s) *child[2]; \
|
||||
type data; \
|
||||
rbtreei_color_e color; \
|
||||
m_rbtr33_color_e color; \
|
||||
} node_t; \
|
||||
\
|
||||
/* Define the Red/Black tree */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
typedef struct M_F(name, _s) { \
|
||||
size_t size; /* Number of elements in the tree */ \
|
||||
node_t *node; /* Root node of the tree */ \
|
||||
} tree_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
\
|
||||
/* Iterator on a tree. The iterator stores the full path to the \
|
||||
current node through all its parents and its depth */ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
typedef struct M_F(name, _it_s) { \
|
||||
node_t *stack[M_RBTR33_MAX_STACK]; \
|
||||
int8_t which[M_RBTR33_MAX_STACK]; \
|
||||
unsigned int cpt; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Definition of the alias used by the oplists */ \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef tree_t M_C(name, _ct); \
|
||||
typedef it_t M_C(name, _it_ct); \
|
||||
\
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef tree_t M_F(name, _ct); \
|
||||
typedef it_t M_F(name, _it_ct); \
|
||||
|
||||
/* Define the mempool encapsulation */
|
||||
#define M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \
|
||||
/* Link with fast memory allocator if requested */ \
|
||||
M_IF_METHOD(MEMPOOL, oplist)( \
|
||||
/* Definition of the memory pool of this kind of node */ \
|
||||
MEMPOOL_DEF(M_C(name, _mempool), node_t) \
|
||||
MEMPOOL_DEF(M_F(name, _mempool), node_t) \
|
||||
/* Definition of the global variable used to reference this pool */ \
|
||||
M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \
|
||||
M_GET_MEMPOOL_LINKAGE oplist M_F(name, _mempool_t) M_GET_MEMPOOL oplist; \
|
||||
/* Allocator function */ \
|
||||
static inline node_t *M_C3(m_rbtr33_,name,_new)(void) { \
|
||||
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \
|
||||
return M_F(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
} \
|
||||
/* Deallocator function */ \
|
||||
static inline void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
|
||||
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
|
||||
M_F(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
} \
|
||||
\
|
||||
, /* No mempool allocation */ \
|
||||
/* Callic allocator function (common case) */ \
|
||||
static inline node_t *M_C3(m_rbtr33_,name,_new)(void) { \
|
||||
/* Classic Allocator function (common case) */ \
|
||||
M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \
|
||||
return M_CALL_NEW(oplist, node_t); \
|
||||
} \
|
||||
/* Callic deallocator function (common case) */ \
|
||||
static inline void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
|
||||
/* Classic deallocator function (common case) */ \
|
||||
M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
|
||||
M_CALL_DEL(oplist, ptr); \
|
||||
} ) \
|
||||
\
|
||||
/* Check if the given oplist is compatible with the given type */ \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
/* Generate all functions */ \
|
||||
M_RBTR33_DEF_P4(name, type, oplist, tree_t, node_t, it_t)
|
||||
|
||||
|
||||
#define M_RBTR33_DEF_P4(name, type, oplist, tree_t, node_t, it_t) \
|
||||
/* Define the core functions */
|
||||
#define M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(tree_t tree) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(tree_t tree) \
|
||||
{ \
|
||||
M_ASSERT (tree != NULL); \
|
||||
tree->size = 0; \
|
||||
@@ -249,8 +254,8 @@ typedef enum {
|
||||
M_RBTR33_CONTRACT(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reset)(tree_t tree) \
|
||||
M_INLINE void \
|
||||
M_F(name, _reset)(tree_t tree) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT(tree); \
|
||||
node_t *stack[M_RBTR33_MAX_STACK]; \
|
||||
@@ -294,21 +299,15 @@ typedef enum {
|
||||
tree->size = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(tree_t tree) \
|
||||
{ \
|
||||
M_C(name,_reset)(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(tree_t tree) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(tree_t tree) \
|
||||
{ \
|
||||
/* Nothing more than clean the tree as everything is cleared */ \
|
||||
M_C(name, _reset)(tree); \
|
||||
M_F(name, _reset)(tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(tree_t tree, type const data) \
|
||||
M_INLINE void \
|
||||
M_F(name, _push)(tree_t tree, type const data) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT(tree); \
|
||||
node_t *tab[M_RBTR33_MAX_STACK]; \
|
||||
@@ -318,7 +317,7 @@ typedef enum {
|
||||
/* If there is no root node, create a new node */ \
|
||||
if (n == NULL) { \
|
||||
n = M_C3(m_rbtr33_,name,_new)(); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
if (M_UNLIKELY_NOMEM (n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (node_t)); \
|
||||
return; \
|
||||
} \
|
||||
@@ -359,7 +358,7 @@ typedef enum {
|
||||
} \
|
||||
/* Create new node to store the data */ \
|
||||
n = M_C3(m_rbtr33_,name,_new)(); \
|
||||
if (M_UNLIKELY (n == NULL) ) { \
|
||||
if (M_UNLIKELY_NOMEM (n == NULL) ) { \
|
||||
M_MEMORY_FULL (sizeof (node_t)); \
|
||||
return; \
|
||||
} \
|
||||
@@ -433,15 +432,15 @@ typedef enum {
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const tree_t tree) \
|
||||
M_INLINE size_t \
|
||||
M_F(name, _size)(const tree_t tree) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
return tree->size; \
|
||||
} \
|
||||
\
|
||||
/* Set the iterator to the first (child=0) or last (child=1) element */ \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(m_rbtr33_,name,_it)(it_t it, const tree_t tree, int child) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
@@ -463,42 +462,43 @@ typedef enum {
|
||||
it->cpt = cpt; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const tree_t tree) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
M_C3(m_rbtr33_,name,_it)(it, tree, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const tree_t tree) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_last)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
M_C3(m_rbtr33_,name,_it)(it, tree, 1); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const tree_t tree) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_end)(it_t it, const tree_t tree) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
M_ASSERT (it != NULL); \
|
||||
(void) tree; /* parameter not used */ \
|
||||
it->cpt = 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t ref) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_set)(it_t it, const it_t ref) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && ref != NULL); \
|
||||
*it = *ref; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
return it->cpt == 0; \
|
||||
} \
|
||||
\
|
||||
/* Go to the next (child = 0)or previous element (child = 1) */ \
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(m_rbtr33_,name,_next)(it_t it, int child) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
@@ -530,20 +530,20 @@ typedef enum {
|
||||
it->cpt = cpt; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
M_INLINE void \
|
||||
M_F(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C3(m_rbtr33_,name,_next)(it, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
M_INLINE void \
|
||||
M_F(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C3(m_rbtr33_,name,_next)(it, 1); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _ref)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT(it != NULL); \
|
||||
/* There shall be at least one element */ \
|
||||
@@ -552,14 +552,14 @@ typedef enum {
|
||||
return &(it->stack[it->cpt-1]->data); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _ref)(it)); \
|
||||
return M_CONST_CAST(type, M_F(name, _ref)(it)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _it_equal_p)(const it_t it1, const it_t it2) \
|
||||
{ \
|
||||
M_ASSERT(it1 != NULL && it2 != NULL); \
|
||||
/* There can be no element */ \
|
||||
@@ -569,8 +569,8 @@ typedef enum {
|
||||
&& (it1->cpt == 0 || it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_from)(it_t it, const tree_t tree, type const data) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_from)(it_t it, const tree_t tree, type const data) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
M_ASSERT (it != NULL); \
|
||||
@@ -594,12 +594,12 @@ typedef enum {
|
||||
/* The iterator found may be strictly lower than data. \
|
||||
In this case, go to the next element */ \
|
||||
if (cmp < 0) { \
|
||||
M_C(name, _next)(it); \
|
||||
M_F(name, _next)(it); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_until_p)(it_t it, type const data) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _it_until_p)(it_t it, type const data) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
if (M_UNLIKELY(it->cpt == 0)) return true; \
|
||||
@@ -609,8 +609,8 @@ typedef enum {
|
||||
return (cmp >= 0); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_while_p)(it_t it, type const data) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _it_while_p)(it_t it, type const data) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
if (M_UNLIKELY(it->cpt == 0)) return false; \
|
||||
@@ -620,8 +620,8 @@ typedef enum {
|
||||
return (cmp <= 0); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _min)(const tree_t tree) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _min)(const tree_t tree) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
@@ -633,8 +633,8 @@ typedef enum {
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _max)(const tree_t tree) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _max)(const tree_t tree) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
@@ -646,20 +646,20 @@ typedef enum {
|
||||
return &n->data; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cmin)(const tree_t tree) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cmin)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _min)(tree)); \
|
||||
return M_CONST_CAST(type, M_F(name, _min)(tree)); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cmax)(const tree_t tree) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cmax)(const tree_t tree) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _max)(tree)); \
|
||||
return M_CONST_CAST(type, M_F(name, _max)(tree)); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get)(const tree_t tree, type const data) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _get)(const tree_t tree, type const data) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
node_t *n = tree->node; \
|
||||
@@ -677,19 +677,19 @@ typedef enum {
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cget)(const tree_t tree, type const data) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cget)(const tree_t tree, type const data) \
|
||||
{ \
|
||||
return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \
|
||||
return M_CONST_CAST(type, M_F(name, _get)(tree, data)); \
|
||||
} \
|
||||
\
|
||||
/* Create a copy of the given node (recursively) */ \
|
||||
static inline node_t * \
|
||||
M_INLINE node_t * \
|
||||
M_C3(m_rbtr33_,name,_copy_node)(const node_t *o) \
|
||||
{ \
|
||||
if (o == NULL) return NULL; \
|
||||
node_t *n = M_C3(m_rbtr33_,name,_new)(); \
|
||||
if (M_UNLIKELY (n == NULL) ) { \
|
||||
if (M_UNLIKELY_NOMEM (n == NULL) ) { \
|
||||
M_MEMORY_FULL (sizeof (node_t)); \
|
||||
return NULL; \
|
||||
} \
|
||||
@@ -700,8 +700,8 @@ typedef enum {
|
||||
return n; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(tree_t tree, const tree_t ref) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (ref); \
|
||||
M_ASSERT (tree != NULL && tree != ref); \
|
||||
@@ -711,18 +711,18 @@ typedef enum {
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(tree_t tree, const tree_t ref) \
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(tree_t tree, const tree_t ref) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
M_RBTR33_CONTRACT (ref); \
|
||||
if (tree == ref) return; \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_set)(tree, ref); \
|
||||
M_F(name,_clear)(tree); \
|
||||
M_F(name,_init_set)(tree, ref); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(tree_t tree, tree_t ref) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (ref); \
|
||||
M_ASSERT (tree != NULL && tree != ref); \
|
||||
@@ -733,19 +733,19 @@ typedef enum {
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(tree_t tree, tree_t ref) \
|
||||
M_INLINE void \
|
||||
M_F(name, _move)(tree_t tree, tree_t ref) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
M_RBTR33_CONTRACT (ref); \
|
||||
M_ASSERT (tree != ref); \
|
||||
M_C(name,_clear)(tree); \
|
||||
M_C(name,_init_move)(tree, ref); \
|
||||
M_F(name,_clear)(tree); \
|
||||
M_F(name,_init_move)(tree, ref); \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
M_INLINE void \
|
||||
M_F(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree1); \
|
||||
M_RBTR33_CONTRACT (tree2); \
|
||||
@@ -755,27 +755,27 @@ typedef enum {
|
||||
M_RBTR33_CONTRACT (tree2); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const tree_t tree) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _empty_p)(const tree_t tree) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
return tree->size == 0; \
|
||||
} \
|
||||
\
|
||||
/* Take care of the case n == NULL too */ \
|
||||
static inline bool \
|
||||
M_INLINE bool \
|
||||
M_C3(m_rbtr33_,name,_black_p)(const node_t *n) \
|
||||
{ \
|
||||
return (n == NULL) ? true : M_RBTR33_IS_BLACK(n); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_INLINE void \
|
||||
M_C3(m_rbtr33_,name,_set_black)(node_t *n) \
|
||||
{ \
|
||||
if (n != NULL) M_RBTR33_SET_BLACK(n); \
|
||||
} \
|
||||
\
|
||||
static inline node_t * \
|
||||
M_INLINE node_t * \
|
||||
M_C3(m_rbtr33_,name,_rotate)(node_t *pp, node_t *ppp, const bool right) \
|
||||
{ \
|
||||
M_ASSERT (pp != NULL && ppp != NULL); \
|
||||
@@ -792,7 +792,7 @@ typedef enum {
|
||||
\
|
||||
M_IF_DEBUG( \
|
||||
/* Compute the depth of a node */ \
|
||||
static size_t \
|
||||
M_INLINE size_t \
|
||||
M_C3(m_rbtr33_,name,_compute_depth)(const node_t *n) \
|
||||
{ \
|
||||
if (n == NULL) return 1; \
|
||||
@@ -801,8 +801,8 @@ typedef enum {
|
||||
} \
|
||||
) \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT (tree); \
|
||||
node_t *tab[M_RBTR33_MAX_STACK]; \
|
||||
@@ -837,7 +837,7 @@ typedef enum {
|
||||
unsigned int cpt_n = cpt; \
|
||||
node_t *v = n; /* the replacement node */ \
|
||||
node_t *u; /* the deleted node */ \
|
||||
rbtreei_color_e v_color = M_RBTR33_GET_COLOR(v); \
|
||||
m_rbtr33_color_e v_color = M_RBTR33_GET_COLOR(v); \
|
||||
/* Classical removal of a node from a binary tree */ \
|
||||
if (v->child[0] != NULL && v->child[1] != NULL) { \
|
||||
/* node has 2 child. */ \
|
||||
@@ -883,7 +883,7 @@ typedef enum {
|
||||
} \
|
||||
\
|
||||
/* Rebalance from child to root */ \
|
||||
if (v_color == RBTREE_BLACK \
|
||||
if (v_color == M_RBTR33_BLACK \
|
||||
&& M_C3(m_rbtr33_,name,_black_p)(u)) { \
|
||||
/* tab[0] is NULL, tab[1] is root, u is double black */ \
|
||||
node_t *p = u, *s; \
|
||||
@@ -924,7 +924,7 @@ typedef enum {
|
||||
/* at least one child of 's' is red */ \
|
||||
/* perform rotation(s) */ \
|
||||
bool childIsRight = !M_C3(m_rbtr33_,name,_black_p)(s->child[1]); \
|
||||
rbtreei_color_e p_color = M_RBTR33_GET_COLOR (p); \
|
||||
m_rbtr33_color_e p_color = M_RBTR33_GET_COLOR (p); \
|
||||
if (childIsRight != nbChild) { \
|
||||
/* left-left or right-right case */ \
|
||||
p = M_C3(m_rbtr33_,name,_rotate) (p, tab[cpt-1], childIsRight); \
|
||||
@@ -961,22 +961,22 @@ typedef enum {
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name,_remove)(tree_t t, it_t it) \
|
||||
M_INLINE void M_F(name,_remove)(tree_t t, it_t it) \
|
||||
{ \
|
||||
/* Not optimum: another search in the tree is performed */ \
|
||||
type data; \
|
||||
M_CALL_INIT_SET(oplist, data, *M_C(name,_cref)(it)); \
|
||||
M_C(name,_next)(it); \
|
||||
M_C(name, _pop_at)(NULL, t, data); \
|
||||
M_CALL_INIT_SET(oplist, data, *M_F(name,_cref)(it)); \
|
||||
M_F(name,_next)(it); \
|
||||
M_F(name, _pop_at)(NULL, t, data); \
|
||||
/* We have changed the tree: the iterator is partialy invalid */ \
|
||||
if (!M_C(name, _end_p)(it)) { \
|
||||
M_C(name, _it_from)(it, t, *M_C(name,_cref)(it)); \
|
||||
if (!M_F(name, _end_p)(it)) { \
|
||||
M_F(name, _it_from)(it, t, *M_F(name,_cref)(it)); \
|
||||
} \
|
||||
M_CALL_CLEAR(oplist, data); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist)( \
|
||||
static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \
|
||||
M_INLINE bool M_F(name,_equal_p)(const tree_t t1, const tree_t t2) { \
|
||||
M_RBTR33_CONTRACT(t1); \
|
||||
M_RBTR33_CONTRACT(t2); \
|
||||
if (t1->size != t2->size) return false; \
|
||||
@@ -986,77 +986,79 @@ typedef enum {
|
||||
structuraly different but functionnaly equal (you get this by \
|
||||
constructing the tree in a different way). We have to \
|
||||
compare the ordered value within the tree. */ \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
M_C(name, _it)(it2, t2); \
|
||||
while (!M_C(name, _end_p)(it1) \
|
||||
&& !M_C(name, _end_p)(it2)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref2 = M_C(name, _cref)(it2); \
|
||||
M_F(name, _it)(it1, t1); \
|
||||
M_F(name, _it)(it2, t2); \
|
||||
while (!M_F(name, _end_p)(it1) \
|
||||
&& !M_F(name, _end_p)(it2)) { \
|
||||
type const *ref1 = M_F(name, _cref)(it1); \
|
||||
type const *ref2 = M_F(name, _cref)(it2); \
|
||||
if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \
|
||||
return false; \
|
||||
M_C(name, _next)(it1); \
|
||||
M_C(name, _next)(it2); \
|
||||
M_F(name, _next)(it1); \
|
||||
M_F(name, _next)(it2); \
|
||||
} \
|
||||
return M_C(name, _end_p)(it1) \
|
||||
&& M_C(name, _end_p)(it2); \
|
||||
return M_F(name, _end_p)(it1) \
|
||||
&& M_F(name, _end_p)(it2); \
|
||||
} \
|
||||
, /* NO EQUAL METHOD */ ) \
|
||||
\
|
||||
M_IF_METHOD(HASH, oplist)( \
|
||||
static inline size_t M_C(name,_hash)(const tree_t t1) { \
|
||||
M_INLINE size_t M_F(name,_hash)(const tree_t t1) { \
|
||||
M_RBTR33_CONTRACT(t1); \
|
||||
M_HASH_DECL(hash); \
|
||||
/* NOTE: We can't compute the hash directly for the same reason \
|
||||
than for EQUAL operator. */ \
|
||||
it_t it1; \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
M_F(name, _it)(it1, t1); \
|
||||
while (!M_F(name, _end_p)(it1)) { \
|
||||
type const *ref1 = M_F(name, _cref)(it1); \
|
||||
M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_F(name, _next)(it1); \
|
||||
} \
|
||||
return M_HASH_FINAL (hash); \
|
||||
} \
|
||||
, /* NO HASH METHOD */ ) \
|
||||
\
|
||||
|
||||
/* Define the I/O functions */
|
||||
#define M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
M_INLINE void M_F(name, _get_str)(m_string_t str, \
|
||||
tree_t const t1, bool append) { \
|
||||
M_RBTR33_CONTRACT(t1); \
|
||||
M_ASSERT(str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
/* NOTE: The print is really naive, and not really efficient */ \
|
||||
bool commaToPrint = false; \
|
||||
it_t it1; \
|
||||
M_C(name, _it)(it1, t1); \
|
||||
while (!M_C(name, _end_p)(it1)) { \
|
||||
M_F(name, _it)(it1, t1); \
|
||||
while (!M_F(name, _end_p)(it1)) { \
|
||||
if (commaToPrint) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
commaToPrint = true; \
|
||||
type const *ref1 = M_C(name, _cref)(it1); \
|
||||
type const *ref1 = M_F(name, _cref)(it1); \
|
||||
M_CALL_GET_STR(oplist, str, *ref1, true); \
|
||||
M_C(name, _next)(it1); \
|
||||
M_F(name, _next)(it1); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* NO GET_STR */ ) \
|
||||
\
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, tree_t const rbtree) \
|
||||
M_INLINE void \
|
||||
M_F(name, _out_str)(FILE *file, tree_t const rbtree) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT(rbtree); \
|
||||
M_ASSERT (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
it_t it; \
|
||||
bool commaToPrint = false; \
|
||||
for (M_C(name, _it)(it, rbtree) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
for (M_F(name, _it)(it, rbtree) ; \
|
||||
!M_F(name, _end_p)(it); \
|
||||
M_F(name, _next)(it)){ \
|
||||
if (commaToPrint) \
|
||||
fputc (M_GET_SEPARATOR oplist, file); \
|
||||
commaToPrint = true; \
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
type const *item = M_F(name, _cref)(it); \
|
||||
M_CALL_OUT_STR(oplist, file, *item); \
|
||||
} \
|
||||
fputc (']', file); \
|
||||
@@ -1064,12 +1066,12 @@ typedef enum {
|
||||
, /* no out_str */ ) \
|
||||
\
|
||||
M_IF_METHOD(PARSE_STR, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT(rbtree); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_C(name,_reset)(rbtree); \
|
||||
M_F(name,_reset)(rbtree); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -1083,7 +1085,7 @@ typedef enum {
|
||||
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
|
||||
do { c = *str++; } while (isspace(c)); \
|
||||
if (b == false || c == 0) goto exit_clear; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
M_F(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
@@ -1095,12 +1097,12 @@ typedef enum {
|
||||
, /* no parse_str */ ) \
|
||||
\
|
||||
M_IF_METHOD(IN_STR, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(tree_t rbtree, FILE *file) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _in_str)(tree_t rbtree, FILE *file) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT(rbtree); \
|
||||
M_ASSERT (file != NULL); \
|
||||
M_C(name,_reset)(rbtree); \
|
||||
M_F(name,_reset)(rbtree); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -1113,7 +1115,7 @@ typedef enum {
|
||||
bool b = M_CALL_IN_STR(oplist, item, file); \
|
||||
do { c = fgetc(file); } while (isspace(c)); \
|
||||
if (b == false || c == EOF) break; \
|
||||
M_C(name, _push)(rbtree, item); \
|
||||
M_F(name, _push)(rbtree, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
return c == ']'; \
|
||||
@@ -1121,21 +1123,21 @@ typedef enum {
|
||||
, /* no in_str */ ) \
|
||||
\
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
|
||||
M_INLINE m_serial_return_code_t \
|
||||
M_F(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT(t1); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
M_C(name, _subtype_ct) const *item; \
|
||||
M_F(name, _subtype_ct) const *item; \
|
||||
bool first_done = false; \
|
||||
it_t it; \
|
||||
ret = f->m_interface->write_array_start(local, f, t1->size); \
|
||||
for (M_C(name, _it)(it, t1) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)){ \
|
||||
item = M_C(name, _cref)(it); \
|
||||
for (M_F(name, _it)(it, t1) ; \
|
||||
!M_F(name, _end_p)(it); \
|
||||
M_F(name, _next)(it)){ \
|
||||
item = M_F(name, _cref)(it); \
|
||||
if (first_done) \
|
||||
ret |= f->m_interface->write_array_next(local, f); \
|
||||
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
|
||||
@@ -1147,8 +1149,8 @@ typedef enum {
|
||||
, /* no OUT_SERIAL */ ) \
|
||||
\
|
||||
M_IF_METHOD(IN_SERIAL, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \
|
||||
M_INLINE m_serial_return_code_t \
|
||||
M_F(name, _in_serial)(tree_t t1, m_serial_read_t f) \
|
||||
{ \
|
||||
M_RBTR33_CONTRACT(t1); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
@@ -1156,23 +1158,29 @@ typedef enum {
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
type key; \
|
||||
M_C(name,_reset)(t1); \
|
||||
M_F(name,_reset)(t1); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
M_CALL_INIT(oplist, key); \
|
||||
do { \
|
||||
ret = M_CALL_IN_SERIAL(oplist, key, f); \
|
||||
if (ret != M_SERIAL_OK_DONE) { break; } \
|
||||
M_C(name, _push)(t1, key); \
|
||||
M_F(name, _push)(t1, key); \
|
||||
} while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(oplist, key); \
|
||||
return ret; \
|
||||
} \
|
||||
, /* no in_serial */ ) \
|
||||
\
|
||||
\
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
// TODO: specialized _sort shall do nothing, but shall check the requested order. How ?
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define RBTREE_DEF M_RBTREE_DEF
|
||||
#define RBTREE_DEF_AS M_RBTREE_DEF_AS
|
||||
#define RBTREE_OPLIST M_RBTREE_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial BIN
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -32,12 +32,17 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/************************** FILE / WRITE / BIN *******************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Internal service:
|
||||
* Write size_t in the stream in a compact form to reduce consumption
|
||||
* (and I/O bandwidth)
|
||||
*/
|
||||
static inline bool
|
||||
m_serial_bin_write_size(FILE *f, const size_t size)
|
||||
M_INLINE bool
|
||||
m_ser1al_bin_write_size(FILE *f, const size_t size)
|
||||
{
|
||||
bool b;
|
||||
if (M_LIKELY(size < 253))
|
||||
@@ -83,8 +88,8 @@ m_serial_bin_write_size(FILE *f, const size_t size)
|
||||
* Read size_t in the stream from a compact form to reduce consumption
|
||||
* (and I/O bandwidth)
|
||||
*/
|
||||
static inline bool
|
||||
m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
M_INLINE bool
|
||||
m_ser1al_bin_read_size(FILE *f, size_t *size)
|
||||
{
|
||||
int c;
|
||||
c = fgetc(f);
|
||||
@@ -94,7 +99,7 @@ m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
return true;
|
||||
}
|
||||
size_t s = 0;
|
||||
int l = (c = 255) ? 8 : (c == 254) ? 4 : 2;
|
||||
int l = (c == 255) ? 8 : (c == 254) ? 4 : 2;
|
||||
for(int i = 0; i < l; i++) {
|
||||
c = fgetc(f);
|
||||
if (M_UNLIKELY(c == EOF)) return false;
|
||||
@@ -106,8 +111,8 @@ m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
|
||||
/* Write the boolean 'data' into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_boolean(m_serial_write_t serial, const bool data)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_boolean(m_serial_write_t serial, const bool data)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f);
|
||||
@@ -116,76 +121,61 @@ m_serial_bin_write_boolean(m_serial_write_t serial, const bool data)
|
||||
|
||||
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
|
||||
{
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
size_t n;
|
||||
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
switch (size_of_type) {
|
||||
case 1:
|
||||
i8 = (int8_t) data;
|
||||
if (size_of_type == 1) {
|
||||
int8_t i8 = (int8_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i8), sizeof i8, 1, f);
|
||||
break;
|
||||
case 2:
|
||||
i16 = (int16_t) data;
|
||||
} else if (size_of_type == 2) {
|
||||
int16_t i16 = (int16_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i16), sizeof i16, 1, f);
|
||||
break;
|
||||
case 4:
|
||||
i32 = (int32_t) data;
|
||||
} else if (size_of_type == 4) {
|
||||
int32_t i32 = (int32_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i32), sizeof i32, 1, f);
|
||||
break;
|
||||
case 8:
|
||||
i64 = (int64_t) data;
|
||||
} else {
|
||||
M_ASSERT(size_of_type == 8);
|
||||
int64_t i64 = (int64_t) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &i64), sizeof i64, 1, f);
|
||||
break;
|
||||
default:
|
||||
M_ASSERT_INIT(false, "an integer of suitable size (8/16/32/64)");
|
||||
break;
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
{
|
||||
float f1;
|
||||
double f2;
|
||||
long double f3;
|
||||
size_t n;
|
||||
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
if (size_of_type == sizeof f1) {
|
||||
f1 = (float) data;
|
||||
if (size_of_type == sizeof (float) ) {
|
||||
float f1 = (float) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f1), sizeof f1, 1, f);
|
||||
} else if (size_of_type == sizeof f2) {
|
||||
f2 = (double) data;
|
||||
} else if (size_of_type == sizeof (double) ) {
|
||||
double f2 = (double) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f2), sizeof f2, 1, f);
|
||||
} else if (size_of_type == sizeof f3) {
|
||||
f3 = (long double) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f3), sizeof f3, 1, f);
|
||||
} else {
|
||||
M_ASSERT_INIT(false, "a float of suitable size");
|
||||
M_ASSERT(size_of_type == sizeof (long double) );
|
||||
long double f3 = (long double) data;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &f3), sizeof f3, 1, f);
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write the null-terminated string 'data'into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
|
||||
{
|
||||
M_ASSERT_SLOW(length == strlen(data) );
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
M_ASSERT(f != NULL && data != NULL);
|
||||
// Write first the number of (non null) characters
|
||||
if (m_serial_bin_write_size(f, length) != true) return m_core_serial_fail();
|
||||
if (m_ser1al_bin_write_size(f, length) != true) return m_core_serial_fail();
|
||||
// Write the characters (excluding the final null char)
|
||||
// NOTE: fwrite supports length == 0.
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, data), 1, length, f);
|
||||
@@ -198,51 +188,40 @@ m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t len
|
||||
Initialize 'local' so that it can be used to serialize the array
|
||||
(local is an unique serialization object of the array).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
{
|
||||
(void) local; //Unused
|
||||
if (number_of_elements == (size_t)-1) return M_SERIAL_FAIL_RETRY;
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
size_t n = fwrite (M_ASSIGN_CAST(const void*, &number_of_elements), sizeof number_of_elements, 1, f);
|
||||
local->data[0].b = (number_of_elements == 0);
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
}
|
||||
|
||||
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
// Need separator if we don't know the real size
|
||||
if (local->data[0].b) {
|
||||
size_t n = 0xABCDEF;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &n), sizeof n, 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
(void) local; // Unused
|
||||
(void) serial; // Unused
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* End the writing of an array into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
// Need mark if we don't know the real size
|
||||
if (local->data[0].b) {
|
||||
size_t n = 0x12345678;
|
||||
n = fwrite (M_ASSIGN_CAST(const void*, &n), sizeof n, 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
|
||||
} else {
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
(void) local; // Unused
|
||||
(void) serial; // Unused
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -253,8 +232,8 @@ m_serial_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
Initialize 'local' so that it can serial the tuple
|
||||
(local is an unique serialization object of the tuple).
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -263,8 +242,8 @@ m_serial_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
|
||||
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -276,8 +255,8 @@ m_serial_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, con
|
||||
|
||||
/* End the write of a tuple into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -289,8 +268,8 @@ m_serial_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise
|
||||
Otherwise, the field 'field_name[index]' will be filled.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
|
||||
{
|
||||
(void) field_name;
|
||||
(void) max;
|
||||
@@ -302,8 +281,8 @@ m_serial_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial
|
||||
|
||||
/* End Writing a variant into the serial stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -311,32 +290,32 @@ m_serial_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
}
|
||||
|
||||
/* The exported interface. */
|
||||
static const m_serial_write_interface_t m_serial_write_bin_interface = {
|
||||
m_serial_bin_write_boolean,
|
||||
m_serial_bin_write_integer,
|
||||
m_serial_bin_write_float,
|
||||
m_serial_bin_write_string,
|
||||
m_serial_bin_write_array_start,
|
||||
m_serial_bin_write_array_next,
|
||||
m_serial_bin_write_array_end,
|
||||
m_serial_bin_write_array_start,
|
||||
m_serial_bin_write_map_value,
|
||||
m_serial_bin_write_array_next,
|
||||
m_serial_bin_write_array_end,
|
||||
m_serial_bin_write_tuple_start,
|
||||
m_serial_bin_write_tuple_id,
|
||||
m_serial_bin_write_tuple_end,
|
||||
m_serial_bin_write_variant_start,
|
||||
m_serial_bin_write_variant_end
|
||||
static const m_serial_write_interface_t m_ser1al_bin_write_interface = {
|
||||
m_ser1al_bin_write_boolean,
|
||||
m_ser1al_bin_write_integer,
|
||||
m_ser1al_bin_write_float,
|
||||
m_ser1al_bin_write_string,
|
||||
m_ser1al_bin_write_array_start,
|
||||
m_ser1al_bin_write_array_next,
|
||||
m_ser1al_bin_write_array_end,
|
||||
m_ser1al_bin_write_array_start,
|
||||
m_ser1al_bin_write_map_value,
|
||||
m_ser1al_bin_write_array_next,
|
||||
m_ser1al_bin_write_array_end,
|
||||
m_ser1al_bin_write_tuple_start,
|
||||
m_ser1al_bin_write_tuple_id,
|
||||
m_ser1al_bin_write_tuple_end,
|
||||
m_ser1al_bin_write_variant_start,
|
||||
m_ser1al_bin_write_variant_end
|
||||
};
|
||||
|
||||
static inline void m_serial_bin_write_init(m_serial_write_t serial, FILE *f)
|
||||
M_INLINE void m_serial_bin_write_init(m_serial_write_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_write_bin_interface;
|
||||
serial->m_interface = &m_ser1al_bin_write_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
static inline void m_serial_bin_write_clear(m_serial_write_t serial)
|
||||
M_INLINE void m_serial_bin_write_clear(m_serial_write_t serial)
|
||||
{
|
||||
(void) serial; // Nothing to do
|
||||
}
|
||||
@@ -344,16 +323,22 @@ static inline void m_serial_bin_write_clear(m_serial_write_t serial)
|
||||
|
||||
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
|
||||
typedef m_serial_write_t m_serial_bin_write_t;
|
||||
|
||||
#define M_OPL_m_serial_bin_write_t() \
|
||||
(INIT_WITH(m_serial_bin_write_init), CLEAR(m_serial_bin_write_clear), \
|
||||
TYPE(m_serial_bin_write_t), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/************************** FILE / READ / BIN *******************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* Read from the stream 'serial' a boolean.
|
||||
Set '*b' with the boolean value if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
size_t n = fread (M_ASSIGN_CAST(void*, b), sizeof (bool), 1, f);
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
@@ -362,34 +347,27 @@ m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
/* Read from the stream 'serial' an integer that can be represented with 'size_of_type' bytes.
|
||||
Set '*i' with the integer value if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_integer(m_serial_read_t serial, long long *i, const size_t size_of_type){
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
size_t n;
|
||||
FILE *f = (FILE *)serial->data[0].p;
|
||||
switch (size_of_type) {
|
||||
case 1:
|
||||
if (size_of_type == 1) {
|
||||
n = fread (M_ASSIGN_CAST(void*, &i8), sizeof i8, 1, f);
|
||||
*i = i8;
|
||||
break;
|
||||
case 2:
|
||||
} else if (size_of_type == 2) {
|
||||
n = fread (M_ASSIGN_CAST(void*, &i16), sizeof i16, 1, f);
|
||||
*i = i16;
|
||||
break;
|
||||
case 4:
|
||||
} else if (size_of_type == 4) {
|
||||
n = fread (M_ASSIGN_CAST(void*, &i32), sizeof i32, 1, f);
|
||||
*i = i32;
|
||||
break;
|
||||
case 8:
|
||||
} else {
|
||||
M_ASSERT(size_of_type == 8);
|
||||
n = fread (M_ASSIGN_CAST(void*, &i64), sizeof i64, 1, f);
|
||||
*i = i64;
|
||||
break;
|
||||
default:
|
||||
M_ASSERT_INIT(false, "an integer of suitable size");
|
||||
break;
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
@@ -397,8 +375,8 @@ m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t siz
|
||||
/* Read from the stream 'serial' a float that can be represented with 'size_of_type' bytes.
|
||||
Set '*r' with the boolean value if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_float(m_serial_read_t serial, long double *r, const size_t size_of_type){
|
||||
float f1;
|
||||
double f2;
|
||||
long double f3;
|
||||
@@ -410,11 +388,10 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
} else if (size_of_type == sizeof f2) {
|
||||
n = fread (M_ASSIGN_CAST(void*, &f2), sizeof f2, 1, f);
|
||||
*r = f2;
|
||||
} else if (size_of_type == sizeof f3) {
|
||||
} else {
|
||||
M_ASSERT(size_of_type == sizeof f3);
|
||||
n = fread (M_ASSIGN_CAST(void*, &f3), sizeof f3, 1, f);
|
||||
*r = f3;
|
||||
} else {
|
||||
M_ASSERT_INIT(false, "a float of suitable size");
|
||||
}
|
||||
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
@@ -422,13 +399,13 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
/* Read from the stream 'serial' a string.
|
||||
Set 's' with the string if succeeds
|
||||
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
M_ASSERT(f != NULL && s != NULL);
|
||||
// First read the number of non null characters
|
||||
size_t length;
|
||||
if (m_serial_bin_read_size(f, &length) != true) return m_core_serial_fail();
|
||||
if (m_ser1al_bin_read_size(f, &length) != true) return m_core_serial_fail();
|
||||
// Use of internal string interface to dimension the string
|
||||
char *p = m_str1ng_fit2size(s, length + 1);
|
||||
m_str1ng_set_size(s, length);
|
||||
@@ -447,54 +424,34 @@ m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the array continue,
|
||||
M_SERIAL_OK_DONE if it succeeds and the array ends (the array is empty),
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, size_t *num)
|
||||
{
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
size_t n = fread (M_ASSIGN_CAST(void*, num), sizeof *num, 1, f);
|
||||
if (n != 1)
|
||||
return m_core_serial_fail();
|
||||
local->data[0].b = (*num == 0);
|
||||
local->data[1].s = *num;
|
||||
if (local->data[0].b) {
|
||||
// Size not know ==> use of marker in the stream.
|
||||
size_t p;
|
||||
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
|
||||
if (n != 1)
|
||||
return m_core_serial_fail();
|
||||
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
}
|
||||
return M_SERIAL_OK_CONTINUE;
|
||||
return (n != 1) ? m_core_serial_fail() : (local->data[1].s == 0) ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Continue reading from the stream 'serial' an array.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the array continue,
|
||||
M_SERIAL_OK_DONE if it succeeds and the array ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
FILE *f = (FILE*) serial->data[0].p;
|
||||
if (local->data[0].b) {
|
||||
// Size not know ==> use of marker in the stream.
|
||||
size_t p, n;
|
||||
n = fread (M_ASSIGN_CAST(void*, &p), sizeof p, 1, f);
|
||||
if (n != 1)
|
||||
return m_core_serial_fail();
|
||||
return p == 0xABCDEF ? M_SERIAL_OK_CONTINUE : p == 0x12345678 ? M_SERIAL_OK_DONE : m_core_serial_fail();
|
||||
} else {
|
||||
M_ASSERT(local->data[1].s > 0);
|
||||
local->data[1].s --;
|
||||
return local->data[1].s == 0 ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
(void) serial; // Unused
|
||||
M_ASSERT(local->data[1].s > 0);
|
||||
local->data[1].s --;
|
||||
return local->data[1].s == 0 ? M_SERIAL_OK_DONE : M_SERIAL_OK_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
/* Continue reading from the stream 'serial' the value separator
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the map continue,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -504,8 +461,8 @@ m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
/* Start reading a tuple from the stream 'serial'.
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) serial;
|
||||
local->data[1].i = 0;
|
||||
@@ -518,8 +475,8 @@ m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the tuple continues,
|
||||
Return M_SERIAL_OK_DONE if it succeeds and the tuple ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const char *const field_name [], const int max, int *id)
|
||||
{
|
||||
(void) serial;
|
||||
(void) field_name;
|
||||
@@ -535,8 +492,8 @@ m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const
|
||||
Return M_SERIAL_OK_CONTINUE if it succeeds and the variant continues,
|
||||
Return M_SERIAL_OK_DONE if it succeeds and the variant ends(variant is empty),
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial, const char *const field_name[], const int max, int*id)
|
||||
{
|
||||
(void) field_name;
|
||||
(void) max;
|
||||
@@ -549,37 +506,37 @@ m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t serial,
|
||||
/* End reading a variant from the stream 'serial'.
|
||||
Return M_SERIAL_OK_DONE if it succeeds and the variant ends,
|
||||
M_SERIAL_FAIL otherwise */
|
||||
static inline m_serial_return_code_t
|
||||
m_serial_bin_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
M_INLINE m_serial_return_code_t
|
||||
m_ser1al_bin_read_variant_end(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
return M_SERIAL_OK_DONE;
|
||||
}
|
||||
|
||||
static const m_serial_read_interface_t m_serial_bin_read_interface = {
|
||||
m_serial_bin_read_boolean,
|
||||
m_serial_bin_read_integer,
|
||||
m_serial_bin_read_float,
|
||||
m_serial_bin_read_string,
|
||||
m_serial_bin_read_array_start,
|
||||
m_serial_bin_read_array_next,
|
||||
m_serial_bin_read_array_start,
|
||||
m_serial_bin_read_map_value,
|
||||
m_serial_bin_read_array_next,
|
||||
m_serial_bin_read_tuple_start,
|
||||
m_serial_bin_read_tuple_id,
|
||||
m_serial_bin_read_variant_start,
|
||||
m_serial_bin_read_variant_end
|
||||
static const m_serial_read_interface_t m_ser1al_bin_read_interface = {
|
||||
m_ser1al_bin_read_boolean,
|
||||
m_ser1al_bin_read_integer,
|
||||
m_ser1al_bin_read_float,
|
||||
m_ser1al_bin_read_string,
|
||||
m_ser1al_bin_read_array_start,
|
||||
m_ser1al_bin_read_array_next,
|
||||
m_ser1al_bin_read_array_start,
|
||||
m_ser1al_bin_read_map_value,
|
||||
m_ser1al_bin_read_array_next,
|
||||
m_ser1al_bin_read_tuple_start,
|
||||
m_ser1al_bin_read_tuple_id,
|
||||
m_ser1al_bin_read_variant_start,
|
||||
m_ser1al_bin_read_variant_end
|
||||
};
|
||||
|
||||
static inline void m_serial_bin_read_init(m_serial_read_t serial, FILE *f)
|
||||
M_INLINE void m_serial_bin_read_init(m_serial_read_t serial, FILE *f)
|
||||
{
|
||||
serial->m_interface = &m_serial_bin_read_interface;
|
||||
serial->m_interface = &m_ser1al_bin_read_interface;
|
||||
serial->data[0].p = M_ASSIGN_CAST(void*, f);
|
||||
}
|
||||
|
||||
static inline void m_serial_bin_read_clear(m_serial_read_t serial)
|
||||
M_INLINE void m_serial_bin_read_clear(m_serial_read_t serial)
|
||||
{
|
||||
(void) serial; // Nothing to do
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED Module
|
||||
* M*LIB - SHARED Pointer Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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,24 +31,16 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
SHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SHARED_PTR_DEF(name, ...) \
|
||||
M_SHARED_PTR_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define shared pointer and its function
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
#define M_SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_ATOMIC_OPLIST, name_t ), \
|
||||
@@ -56,16 +48,24 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define M_SHARED_PTR_OPLIST(...) \
|
||||
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe).
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
SHARED_PTR_RELAXED_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_SHARED_PTR_RELAXED_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe)
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
#define M_SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_INTEGER_OPLIST, name_t ), \
|
||||
@@ -76,15 +76,15 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define shared resource and its function.
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
SHARED_RESOURCE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
#define M_SHARED_RESOURCE_DEF(name, ...) \
|
||||
M_SHARED_RESOURCE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define shared resource and its function
|
||||
as the given name named_t and the iterator it_t
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SHAR3D_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
@@ -93,7 +93,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/*****************************************************************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
// deferred evaluation
|
||||
#define M_SHAR3D_PTR_OPLIST_P1(arg) M_SHAR3D_PTR_OPLIST_P2 arg
|
||||
@@ -107,19 +109,16 @@ M_BEGIN_PROTECTED_CODE
|
||||
((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
#define M_SHAR3D_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)) \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
RESET(M_C(name, _reset)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)) \
|
||||
INIT(M_F(name, _init)), \
|
||||
CLEAR(M_F(name, _clear)), \
|
||||
INIT_SET(M_F(name, _init_set)), \
|
||||
SET(M_F(name, _set)) \
|
||||
INIT_MOVE(M_F(name, _init_move)), \
|
||||
RESET(M_F(name, _reset)), \
|
||||
MOVE(M_F(name, _move)), \
|
||||
SWAP(M_F(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
,TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*) \
|
||||
)
|
||||
|
||||
// OPLIST to handle a counter of atomic type
|
||||
@@ -137,10 +136,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
IT_CREF(m_shar3d_integer_cref))
|
||||
|
||||
/* Atomic like interface for basic integers */
|
||||
static inline void m_shar3d_integer_init_set(int *p, int val) { *p = val; }
|
||||
static inline int m_shar3d_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
|
||||
static inline int m_shar3d_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
|
||||
static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_INLINE void m_shar3d_integer_init_set(int *p, int val) { *p = val; }
|
||||
M_INLINE int m_shar3d_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
|
||||
M_INLINE int m_shar3d_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
|
||||
M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Contract of a shared pointer */
|
||||
#define M_SHAR3D_CONTRACT(shared, cpt_oplist) do { \
|
||||
@@ -149,7 +151,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
} while (0)
|
||||
|
||||
// deferred evaluation
|
||||
#define M_SHAR3D_PTR_DEF_P1(arg) M_SHAR3D_PTR_DEF_P2 arg
|
||||
#define M_SHAR3D_PTR_DEF_P1(arg) M_ID( M_SHAR3D_PTR_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SHAR3D_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
@@ -161,44 +163,53 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
|
||||
/* Code generation */
|
||||
#define M_SHAR3D_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_EMPLACE_QUEUE_DEF(name, cpt_oplist, M_F(name, _init_with), oplist, M_SHAR3D_PTR_DEF_EMPLACE)
|
||||
|
||||
/* Define the types */
|
||||
#define M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
typedef struct M_F(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
M_GET_TYPE cpt_oplist cpt; /* Counter of how many refs the data */ \
|
||||
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
|
||||
} *shared_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
typedef shared_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
\
|
||||
typedef struct M_C(name, combine_s) { \
|
||||
typedef struct M_F(name, _combine_s) { \
|
||||
struct M_F(name, _s) ptr; \
|
||||
type data; \
|
||||
struct M_C(name, _s) ptr; \
|
||||
} M_C(name, combine_ct)[1]; \
|
||||
} M_F(name, combine_ct)[1]; \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t shared) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(shared_t shared) \
|
||||
{ \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init2)(shared_t shared, type *data) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init2)(shared_t shared, type *data) \
|
||||
{ \
|
||||
M_ASSERT (shared != NULL); \
|
||||
/* The shared ptr get exclusive access to data */ \
|
||||
struct M_C(name, _s) *ptr; \
|
||||
struct M_F(name, _s) *ptr; \
|
||||
if (M_UNLIKELY (data == NULL)) { \
|
||||
*shared = NULL; \
|
||||
return; \
|
||||
} \
|
||||
ptr = M_CALL_NEW(oplist, struct M_C(name, _s)); \
|
||||
if (M_UNLIKELY (ptr == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, _s))); \
|
||||
ptr = M_CALL_NEW(oplist, struct M_F(name, _s)); \
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_F(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
ptr->data = data; \
|
||||
@@ -208,35 +219,37 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_new)(shared_t shared) \
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_new)(shared_t shared) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_C(name, combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_C(name, combine_s)); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, combine_s))); \
|
||||
struct M_F(name, _combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
|
||||
if (M_UNLIKELY_NOMEM (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_C(name, _s) *ptr = &p->ptr; \
|
||||
struct M_F(name, _s) *ptr = &p->ptr; \
|
||||
ptr->combineAlloc = true; \
|
||||
type *data = &p->data; \
|
||||
M_CALL_INIT( oplist, *data); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
, /* No INIT */ ) \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const shared_t shared) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _NULL_p)(const shared_t shared) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(shared_t dest, \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
@@ -249,8 +262,8 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t dest) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(shared_t dest) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
@@ -261,40 +274,35 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
first element, aka data itself. Static analyzer tools don't \
|
||||
seem to detect this and report error. */ \
|
||||
M_CALL_CLEAR(oplist, *(*dest)->data); \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
if (combineAlloc == false) \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
if (combineAlloc == false) { \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
} \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reset)(shared_t dest) \
|
||||
M_INLINE void \
|
||||
M_F(name, _reset)(shared_t dest) \
|
||||
{ \
|
||||
/* NOTE: Clear will also set dest to NULL */ \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_F(name, _clear)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _clean)(shared_t dest) \
|
||||
{ \
|
||||
M_C(name, _reset)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t dest, \
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
M_F(name, _clear)(dest); \
|
||||
M_F(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(shared_t dest, \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
@@ -304,31 +312,31 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(shared_t dest, \
|
||||
M_INLINE void \
|
||||
M_F(name, _move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != shared); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_move)(dest, shared); \
|
||||
M_F(name, _clear)(dest); \
|
||||
M_F(name, _init_move)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(shared_t p1, \
|
||||
M_INLINE void \
|
||||
M_F(name, _swap)(shared_t p1, \
|
||||
shared_t p2) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
|
||||
/* NOTE: SWAP is not atomic */ \
|
||||
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
|
||||
M_SWAP (struct M_F(name, _s)*, *p1, *p2); \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const shared_t p1, \
|
||||
M_INLINE bool \
|
||||
M_F(name, _equal_p)(const shared_t p1, \
|
||||
const shared_t p2) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
@@ -336,8 +344,8 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const shared_t shared) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cref)(const shared_t shared) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
@@ -346,8 +354,8 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
return M_CONST_CAST (type, data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(shared_t shared) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _ref)(shared_t shared) \
|
||||
{ \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
@@ -355,10 +363,33 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_ASSERT (data != NULL); \
|
||||
return data; \
|
||||
} \
|
||||
|
||||
|
||||
/* Definition of the emplace_back function for arrays */
|
||||
#define M_SHAR3D_PTR_DEF_EMPLACE(name, cpt_oplist, function_name, oplist, init_func, exp_emplace_type) \
|
||||
M_INLINE void \
|
||||
function_name(M_F(name, _ct) shared \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_F(name, _combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
|
||||
if (M_UNLIKELY_NOMEM (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_F(name, _s) *ptr = &p->ptr; \
|
||||
ptr->combineAlloc = true; \
|
||||
M_F(name, _subtype_ct) *data = &p->data; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
*shared = ptr; \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
|
||||
|
||||
/********************************** SHARED RESOURCE ************************************/
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
#define M_SHAR3D_RESOURCE_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
@@ -366,7 +397,7 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
} while (0)
|
||||
|
||||
// deferred
|
||||
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_SHAR3D_RESOURCE_DEF_P2 arg
|
||||
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_ID( M_SHAR3D_RESOURCE_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SHAR3D_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
@@ -377,120 +408,129 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define M_SHAR3D_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
|
||||
M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \
|
||||
|
||||
/* Define the types */
|
||||
#define M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
typedef struct M_F(name, _atype_s) { \
|
||||
atomic_uint cpt; \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type, atomic_uint); \
|
||||
} M_C(name, _atype_ct); \
|
||||
} M_F(name, _atype_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
M_C(name, _atype_ct) *buffer; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
m_genint_t core; \
|
||||
M_F(name, _atype_ct) *buffer; \
|
||||
} shared_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
typedef struct M_F(name, _it_s) { \
|
||||
unsigned int idx; \
|
||||
struct M_C(name, _s) *ref; \
|
||||
struct M_F(name, _s) *ref; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Internal Types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t s, size_t n) \
|
||||
typedef shared_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(shared_t s, size_t n) \
|
||||
{ \
|
||||
M_ASSERT(s != NULL); \
|
||||
M_ASSERT (n > 0 && n < UINT_MAX); \
|
||||
s->buffer = M_CALL_REALLOC(oplist, M_C(name, _atype_ct), NULL, n); \
|
||||
if (M_UNLIKELY (s->buffer == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _atype_ct)) * n); \
|
||||
s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, n); \
|
||||
if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_F(name, _atype_ct)) * n); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_INIT(oplist, s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, (unsigned int) n); \
|
||||
m_genint_init(s->core, (unsigned int) n); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t s) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(shared_t s) \
|
||||
{ \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
size_t n = m_genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_CLEAR(oplist, s->buffer[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, s->buffer); \
|
||||
s->buffer = NULL; \
|
||||
genint_clear(s->core); \
|
||||
m_genint_clear(s->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, shared_t s) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it)(it_t it, shared_t s) \
|
||||
{ \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
M_ASSERT (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
unsigned int idx = m_genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
it->ref = s; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
|
||||
M_ASSERT(atomic_load(&s->buffer[idx].cpt) == 0); \
|
||||
atomic_store(&s->buffer[idx].cpt, 1U); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(it_t it) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _end_p)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
return it->idx == GENINT_ERROR; \
|
||||
return it->idx == M_GENINT_ERROR; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(it_t it) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _ref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(it_t it) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _cref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _end)(it_t it, shared_t s) \
|
||||
M_INLINE void \
|
||||
M_F(name, _end)(it_t it, shared_t s) \
|
||||
{ \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
M_ASSERT (it != NULL); \
|
||||
M_ASSERT (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
|
||||
if (c == 1) { \
|
||||
genint_push(it->ref->core, idx); \
|
||||
m_genint_push(it->ref->core, idx); \
|
||||
} \
|
||||
it->idx = GENINT_ERROR; \
|
||||
it->idx = M_GENINT_ERROR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t itd, it_t its) \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_set)(it_t itd, it_t its) \
|
||||
{ \
|
||||
M_ASSERT (itd != NULL && its != NULL); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(its->ref); \
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
|
||||
M_ASSERT (c >= 1); \
|
||||
} \
|
||||
@@ -498,4 +538,16 @@ static inline int m_shar3d_integer_cref(int *p) { return *p; }
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define SHARED_PTR_OPLIST M_SHARED_PTR_OPLIST
|
||||
#define SHARED_PTR_DEF M_SHARED_PTR_DEF
|
||||
#define SHARED_PTR_DEF_AS M_SHARED_PTR_DEF_AS
|
||||
#define SHARED_PTR_RELAXED_DEF M_SHARED_PTR_RELAXED_DEF
|
||||
#define SHARED_PTR_RELAXED_DEF_AS M_SHARED_PTR_RELAXED_DEF_AS
|
||||
#define SHARED_RESOURCE_DEF M_SHARED_RESOURCE_DEF
|
||||
#define SHARED_RESOURCE_DEF_AS M_SHARED_RESOURCE_DEF_AS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, 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:
|
||||
@@ -33,14 +33,14 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
SNAPSHOT_SPSC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPSC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPSC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
#define M_SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SNAPSH0T_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -50,14 +50,14 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
SNAPSHOT_SPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPMC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPMC_DEF_AS(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
#define M_SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SNAPSH0T_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -67,14 +67,14 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
SNAPSHOT_MPMC_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
#define M_SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_MPMC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_MPMC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
#define M_SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_SNAPSH0T_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
@@ -84,13 +84,15 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
|
||||
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
#define M_SNAPSHOT_OPLIST(...) \
|
||||
M_SNAPSH0T_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
/*****************************************************************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
// deferred evaluation of the input
|
||||
#define M_SNAPSH0T_OPLIST_P1(arg) M_SNAPSH0T_OPLIST_P2 arg
|
||||
@@ -105,20 +107,20 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a snapshot */
|
||||
#define M_SNAPSH0T_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
(INIT(M_F(name, _init)) \
|
||||
,INIT_SET(M_F(name, _init_set)) \
|
||||
,SET(M_F(name, _set)) \
|
||||
,CLEAR(M_F(name, _clear)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,TYPE(M_F(name, _ct)) , GENTYPE(struct M_F(name,_s)*) \
|
||||
,SUBTYPE(M_F(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
|
||||
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_F(name, _init_move)),) \
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(M_F(name, _move)),) \
|
||||
)
|
||||
|
||||
|
||||
/******************************** INTERNAL SPSC **********************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Flag defining the atomic state of a snapshot:
|
||||
* - r: Index of the read buffer Range [0..2]
|
||||
@@ -156,7 +158,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_SNAPSH0T_SPSC_MAX_BUFFER 3
|
||||
|
||||
// Defered evaluation of the arguments.
|
||||
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_SNAPSH0T_SPSC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPSC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SNAPSH0T_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
@@ -168,28 +170,35 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Expand the type and the functions of a SPSC snapshot */
|
||||
#define M_SNAPSH0T_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
M_SNAPSH0T_SPSC_DEF_TYPE(name, type, oplist, snapshot_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_SNAPSH0T_SPSC_DEF_CORE(name, type, oplist, snapshot_t) \
|
||||
|
||||
/* Define the type */
|
||||
#define M_SNAPSH0T_SPSC_DEF_TYPE(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
typedef struct M_F(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type); \
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
} M_F(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) data[M_SNAPSH0T_SPSC_MAX_BUFFER]; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _aligned_type_ct) data[M_SNAPSH0T_SPSC_MAX_BUFFER]; \
|
||||
atomic_uchar flags; \
|
||||
} snapshot_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef snapshot_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_SNAPSH0T_SPSC_DEF_CORE(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(snapshot_t snap) \
|
||||
{ \
|
||||
M_ASSERT(snap != NULL); \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
@@ -199,8 +208,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
@@ -209,8 +218,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
/* const is missing for org due to use of atomic_load of org */ \
|
||||
static inline void \
|
||||
M_C(name, _init_set)(snapshot_t snap, snapshot_t org) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != NULL && snap != org); \
|
||||
@@ -222,8 +231,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
/* const is missing for org due to use of atomic_load of org */ \
|
||||
static inline void \
|
||||
M_C(name, _set)(snapshot_t snap, snapshot_t org) \
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
@@ -235,8 +244,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT_MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _init_move)(snapshot_t snap, snapshot_t org) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_move)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != NULL && snap != org); \
|
||||
@@ -250,8 +259,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
,) /* IF_METHOD (INIT_MOVE) */ \
|
||||
\
|
||||
M_IF_METHOD(MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _move)(snapshot_t snap, \
|
||||
M_INLINE void \
|
||||
M_F(name, _move)(snapshot_t snap, \
|
||||
snapshot_t org) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
@@ -266,8 +275,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
,) /* IF_METHOD (MOVE) */ \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
@@ -285,8 +294,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
return &snap->data[M_SNAPSH0T_SPSC_W(nextFlags)].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read)(snapshot_t snap) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _read)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
@@ -310,8 +319,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline bool \
|
||||
M_C(name, _updated_p)(snapshot_t snap) \
|
||||
M_INLINE bool \
|
||||
M_F(name, _updated_p)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load (&snap->flags); \
|
||||
@@ -319,8 +328,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
@@ -328,8 +337,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type const * \
|
||||
M_C(name, _get_read_buffer)(snapshot_t snap) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _get_read_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
@@ -337,8 +346,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/******************************** INTERNAL SPMC **********************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG_W(f) ((f) >> 1)
|
||||
@@ -347,7 +355,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
// 2 more buffer than the number of readers are needed
|
||||
#define M_SNAPSH0T_SPMC_EXTRA_BUFFER 2
|
||||
|
||||
#define M_SNAPSH0T_SPMC_MAX_READER (GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
|
||||
#define M_SNAPSH0T_SPMC_MAX_READER (M_GENINT_MAX_ALLOC-M_SNAPSH0T_SPMC_EXTRA_BUFFER)
|
||||
|
||||
/* Internal structure to handle SPMC snapshot but return an unique index in the buffer array.
|
||||
- lastNext: last published written index + next flag (format M_SNAPSH0T_SPMC_INT_FLAG)
|
||||
@@ -356,13 +364,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
- cptTab: ref counter array to keep track of how many readers use the corresponding buffer.
|
||||
- freeList: a pool of free integers.
|
||||
*/
|
||||
typedef struct m_snapshot_mrsw_s {
|
||||
typedef struct m_snapsh0t_mrsw_s {
|
||||
atomic_uint lastNext;
|
||||
unsigned int currentWrite;
|
||||
size_t n_reader;
|
||||
atomic_uint *cptTab;
|
||||
genint_t freeList;
|
||||
} m_snapshot_mrsw_ct[1];
|
||||
m_genint_t freeList;
|
||||
} m_snapsh0t_mrsw_ct[1];
|
||||
|
||||
// can't check currentWrite due to potential data race on it
|
||||
#define M_SNAPSH0T_SPMC_INT_CONTRACT(s) do { \
|
||||
@@ -373,9 +381,9 @@ typedef struct m_snapshot_mrsw_s {
|
||||
M_ASSERT (s->cptTab != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Initialize m_snapshot_mrsw_ct for n readers (constructor) */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
|
||||
/* Initialize m_snapsh0t_mrsw_ct for n readers (constructor) */
|
||||
M_INLINE void
|
||||
m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n)
|
||||
{
|
||||
M_ASSERT (s != NULL);
|
||||
M_ASSERT (n >= 1 && n <= M_SNAPSH0T_SPMC_MAX_READER);
|
||||
@@ -384,50 +392,50 @@ m_snapsh0t_mrsw_init(m_snapshot_mrsw_ct s, size_t n)
|
||||
|
||||
// Initialize the counters to zero (no reader use it)
|
||||
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n);
|
||||
if (M_UNLIKELY (ptr == NULL)) {
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
|
||||
M_MEMORY_FULL(sizeof (atomic_uint) * n);
|
||||
return;
|
||||
}
|
||||
s->cptTab = ptr;
|
||||
for(size_t i = 0; i < n; i++)
|
||||
atomic_init(&s->cptTab[i], 0U);
|
||||
genint_init (s->freeList, (unsigned int) n);
|
||||
m_genint_init (s->freeList, (unsigned int) n);
|
||||
|
||||
// Get a free buffer and set it as available for readers
|
||||
unsigned int w = genint_pop(s->freeList);
|
||||
M_ASSERT (w != GENINT_ERROR);
|
||||
unsigned int w = m_genint_pop(s->freeList);
|
||||
M_ASSERT (w != M_GENINT_ERROR);
|
||||
atomic_store(&s->cptTab[w], 1U);
|
||||
atomic_init(&s->lastNext, M_SNAPSH0T_SPMC_INT_FLAG(w, true));
|
||||
|
||||
// Get working buffer
|
||||
s->currentWrite = genint_pop(s->freeList);
|
||||
M_ASSERT (s->currentWrite != GENINT_ERROR);
|
||||
s->currentWrite = m_genint_pop(s->freeList);
|
||||
M_ASSERT (s->currentWrite != M_GENINT_ERROR);
|
||||
atomic_store(&s->cptTab[s->currentWrite], 1U);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear m_snapshot_mrsw_ct (destructor) */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_clear(m_snapshot_mrsw_ct s)
|
||||
/* Clear m_snapsh0t_mrsw_ct (destructor) */
|
||||
M_INLINE void
|
||||
m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
M_MEMORY_FREE (s->cptTab);
|
||||
genint_clear(s->freeList);
|
||||
m_genint_clear(s->freeList);
|
||||
s->cptTab = NULL;
|
||||
s->n_reader = 0;
|
||||
}
|
||||
|
||||
/* Return the current index that is written in the buffer */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_get_write_idx(m_snapshot_mrsw_ct s)
|
||||
M_INLINE unsigned int
|
||||
m_snapsh0t_mrsw_get_write_idx(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
}
|
||||
|
||||
/* Return the number of readers */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
|
||||
M_INLINE unsigned int
|
||||
m_snapsh0t_mrsw_size(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return (unsigned int) s->n_reader;
|
||||
@@ -435,8 +443,8 @@ m_snapsh0t_mrsw_size(m_snapshot_mrsw_ct s)
|
||||
|
||||
/* Give the current index that is written to the readers,
|
||||
and return new available index for the writer thread */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
M_INLINE unsigned int
|
||||
m_snapsh0t_mrsw_write_idx(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
@@ -462,8 +470,8 @@ m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
if (c != 1) {
|
||||
// If someone else keeps a ref on the buffer, we can't reuse it
|
||||
// get another free one.
|
||||
idx = genint_pop(s->freeList);
|
||||
M_ASSERT(idx != GENINT_ERROR);
|
||||
idx = m_genint_pop(s->freeList);
|
||||
M_ASSERT(idx != M_GENINT_ERROR);
|
||||
} else {
|
||||
// No other thread keep track of this buffer.
|
||||
// Reuse it.
|
||||
@@ -477,8 +485,8 @@ m_snapsh0t_mrsw_write_idx(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
}
|
||||
|
||||
/* Perform a swap of the current write buffer and return a new one */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_write(m_snapshot_mrsw_ct s)
|
||||
M_INLINE unsigned int
|
||||
m_snapsh0t_mrsw_write(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
s->currentWrite = m_snapsh0t_mrsw_write_idx(s, s->currentWrite);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
@@ -486,13 +494,13 @@ m_snapsh0t_mrsw_write(m_snapshot_mrsw_ct s)
|
||||
}
|
||||
|
||||
/* Start writing to the write buffer and return its index */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
|
||||
M_INLINE unsigned int
|
||||
m_snapsh0t_mrsw_write_start(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
// Get a new buffer.
|
||||
unsigned int idx = genint_pop(s->freeList);
|
||||
M_ASSERT (idx != GENINT_ERROR);
|
||||
unsigned int idx = m_genint_pop(s->freeList);
|
||||
M_ASSERT (idx != M_GENINT_ERROR);
|
||||
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
|
||||
M_ASSERT (atomic_load(&s->cptTab[idx]) == 0);
|
||||
atomic_store(&s->cptTab[idx], 1U);
|
||||
@@ -501,8 +509,8 @@ m_snapsh0t_mrsw_write_start(m_snapshot_mrsw_ct s)
|
||||
}
|
||||
|
||||
/* End writing to the given write buffer */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
M_INLINE void
|
||||
m_snapsh0t_mrsw_write_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
@@ -517,14 +525,14 @@ m_snapsh0t_mrsw_write_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
M_ASSERT (c != 0 && c <= s->n_reader + 1);
|
||||
if (c == 1) {
|
||||
genint_push(s->freeList, idx);
|
||||
m_genint_push(s->freeList, idx);
|
||||
}
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Start reading the latest written buffer and return the index to it */
|
||||
static inline unsigned int
|
||||
m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
|
||||
M_INLINE unsigned int
|
||||
m_snapsh0t_mrsw_read_start(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
unsigned int idx, previous;
|
||||
@@ -558,7 +566,7 @@ m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
|
||||
c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
M_ASSERT (c != 0 && c <= s->n_reader + 1);
|
||||
if (c == 1) {
|
||||
genint_push(s->freeList, idx);
|
||||
m_genint_push(s->freeList, idx);
|
||||
}
|
||||
}
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
@@ -566,8 +574,8 @@ m_snapsh0t_mrsw_read_start(m_snapshot_mrsw_ct s)
|
||||
}
|
||||
|
||||
/* End the reading the given buffer */
|
||||
static inline void
|
||||
m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
M_INLINE void
|
||||
m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
|
||||
@@ -577,11 +585,14 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
if (c == 1) {
|
||||
// Buffer no longer used by any reader thread.
|
||||
// Push back index in free list
|
||||
genint_push(s->freeList, idx);
|
||||
m_genint_push(s->freeList, idx);
|
||||
}
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Contract of a SPMC snapshot.
|
||||
Nothing notable as it can be accessed concurrently */
|
||||
#define M_SNAPSH0T_SPMC_CONTRACT(snap) do { \
|
||||
@@ -591,7 +602,7 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
|
||||
|
||||
// Defered evaluation
|
||||
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_SNAPSH0T_SPMC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SNAPSH0T_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
@@ -603,33 +614,40 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
|
||||
/* Expand the type and the functions of a SPMC snapshot */
|
||||
#define M_SNAPSH0T_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
M_SNAPSH0T_SPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_SNAPSH0T_SPMC_DEF_CORE(name, type, oplist, snapshot_t) \
|
||||
|
||||
/* Define the type */
|
||||
#define M_SNAPSH0T_SPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
typedef struct M_F(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type); \
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
} M_F(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) *data; \
|
||||
m_snapshot_mrsw_ct core; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _aligned_type_ct) *data; \
|
||||
m_snapsh0t_mrsw_ct core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef snapshot_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_SNAPSH0T_SPMC_DEF_CORE(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(snapshot_t snap, size_t nReader) \
|
||||
{ \
|
||||
M_ASSERT (snap != NULL); \
|
||||
M_ASSERT (nReader > 0 && nReader <= M_SNAPSH0T_SPMC_MAX_READER); \
|
||||
snap->data = M_CALL_REALLOC(oplist, M_C(name, _aligned_type_ct), \
|
||||
snap->data = M_CALL_REALLOC(oplist, M_F(name, _aligned_type_ct), \
|
||||
NULL, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
if (M_UNLIKELY (snap->data == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_ct)) * \
|
||||
if (M_UNLIKELY_NOMEM (snap->data == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_F(name, _aligned_type_ct)) * \
|
||||
(nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \
|
||||
return; \
|
||||
} \
|
||||
@@ -640,8 +658,8 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
size_t nReader = m_snapsh0t_mrsw_size(snap->core); \
|
||||
@@ -652,29 +670,29 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_clear(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_write(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read_start)(snapshot_t snap) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _read_start)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_read_start(snap->core); \
|
||||
return M_CONST_CAST(type, &snap->data[idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
M_INLINE void \
|
||||
M_F(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
M_ASSERT (old != NULL); \
|
||||
const M_C(name, _aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _aligned_type_ct), old, type, x); \
|
||||
const M_F(name, _aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_F(name, _aligned_type_ct), old, type, x); \
|
||||
M_ASSERT (oldx >= snap->data); \
|
||||
M_ASSERT (oldx < snap->data + snap->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->n_reader +M_SNAPSH0T_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
@@ -682,8 +700,8 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_read_end(snap->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_get_write_idx(snap->core); \
|
||||
@@ -691,16 +709,13 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
} \
|
||||
\
|
||||
|
||||
//FIXME: Evaluate the needs for the methods _set_, _init_set.
|
||||
|
||||
|
||||
|
||||
/******************************** INTERNAL MPMC **********************************/
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
// MPMC is built upon SPMC
|
||||
|
||||
// Defered evaluation
|
||||
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_SNAPSH0T_MPMC_DEF_P2 arg
|
||||
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_MPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define M_SNAPSH0T_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
@@ -712,48 +727,54 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
|
||||
/* Expand the type and the functions of a MPMC snapshot */
|
||||
#define M_SNAPSH0T_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
M_SNAPSH0T_SPMC_DEF_P1((M_F(name, _mrsw), type, oplist, M_F(name, _mrsw_pct))) \
|
||||
M_SNAPSH0T_MPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
M_SNAPSH0T_MPMC_DEF_CORE(name, type, oplist, snapshot_t) \
|
||||
|
||||
/* Define the types */
|
||||
#define M_SNAPSH0T_MPMC_DEF_TYPE(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
M_SNAPSH0T_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist, M_C(name, _mrsw_pct))) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _mrsw_pct) core; \
|
||||
typedef struct M_F(name, _s) { \
|
||||
M_F(name, _mrsw_pct) core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef snapshot_t M_F(name, _ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
|
||||
/* Define the core functions */
|
||||
#define M_SNAPSH0T_MPMC_DEF_CORE(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \
|
||||
{ \
|
||||
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
M_F(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
unsigned int idx = snap->core->core->currentWrite; \
|
||||
snap->core->core->currentWrite = GENINT_ERROR; \
|
||||
snap->core->core->currentWrite = M_GENINT_ERROR; \
|
||||
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
M_INLINE void \
|
||||
M_F(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
M_C(name, _mrsw_clear)(snap->core); \
|
||||
M_F(name, _mrsw_clear)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write_start)(snapshot_t snap) \
|
||||
M_INLINE type * \
|
||||
M_F(name, _write_start)(snapshot_t snap) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap->core); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_write_start(snap->core->core); \
|
||||
return &snap->core->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _write_end)(snapshot_t snap, type *old) \
|
||||
M_INLINE void \
|
||||
M_F(name, _write_end)(snapshot_t snap, type *old) \
|
||||
{ \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap->core); \
|
||||
const M_C(name, _mrsw_aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _mrsw_aligned_type_ct), old, type, x); \
|
||||
const M_F(name, _mrsw_aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_F(name, _mrsw_aligned_type_ct), old, type, x); \
|
||||
M_ASSERT (oldx >= snap->core->data); \
|
||||
M_ASSERT (oldx < snap->core->data + snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->core->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
@@ -761,16 +782,16 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read_start)(snapshot_t snap) \
|
||||
M_INLINE type const * \
|
||||
M_F(name, _read_start)(snapshot_t snap) \
|
||||
{ \
|
||||
return M_C(name, _mrsw_read_start)(snap->core); \
|
||||
return M_F(name, _mrsw_read_start)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
M_INLINE void \
|
||||
M_F(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
{ \
|
||||
M_C(name, _mrsw_read_end)(snap->core, old); \
|
||||
M_F(name, _mrsw_read_end)(snap->core, old); \
|
||||
} \
|
||||
\
|
||||
|
||||
@@ -778,4 +799,16 @@ m_snapsh0t_mrsw_read_end(m_snapshot_mrsw_ct s, unsigned int idx)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define SNAPSHOT_SPSC_DEF M_SNAPSHOT_SPSC_DEF
|
||||
#define SNAPSHOT_SPSC_DEF_AS M_SNAPSHOT_SPSC_DEF_AS
|
||||
#define SNAPSHOT_SPMC_DEF M_SNAPSHOT_SPMC_DEF
|
||||
#define SNAPSHOT_SPMC_DEF_AS M_SNAPSHOT_SPMC_DEF_AS
|
||||
#define SNAPSHOT_MPMC_DEF M_SNAPSHOT_MPMC_DEF
|
||||
#define SNAPSHOT_MPMC_DEF_AS M_SNAPSHOT_MPMC_DEF_AS
|
||||
#define SNAPSHOT_OPLIST M_SNAPSHOT_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||