Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43fdd10e77 | ||
|
|
b1183de0f8 | ||
|
|
3a3ef7454c | ||
|
|
5f946b728b | ||
|
|
9cc03ff81b | ||
|
|
89d4db174e | ||
|
|
f5bbc0a7fb | ||
|
|
9da0d1d94b | ||
|
|
fafaaafdbf | ||
|
|
38f4107b19 | ||
|
|
cbefdab4bb | ||
|
|
bcd0c46e8b | ||
|
|
f25bb73e58 | ||
|
|
ea3584e048 | ||
|
|
85473610a4 | ||
|
|
f9f0b307fc | ||
|
|
d17fa4530b | ||
|
|
3806495e2d | ||
|
|
15f58d5738 | ||
|
|
4de7da1c05 | ||
|
|
93229c61f2 | ||
|
|
3f0e8956b8 | ||
|
|
b82670b643 | ||
|
|
64800dbd3f | ||
|
|
2d9d9fbd9f | ||
|
|
f0ba5d17f4 | ||
|
|
e51c988222 | ||
|
|
0be3900beb | ||
|
|
f60ce0320a | ||
|
|
77008b8622 | ||
|
|
a7617002c5 | ||
|
|
bc73616bde | ||
|
|
d6b9b054c2 | ||
|
|
9eed4be97c | ||
|
|
2519927178 | ||
|
|
0fec33b38e | ||
|
|
dc2b6d2b2d | ||
|
|
bc63edc595 | ||
|
|
6241a3093c | ||
|
|
fb53a464d7 | ||
|
|
aba26b75a2 | ||
|
|
775ec6f91b | ||
|
|
95bc7063a0 | ||
|
|
731d3ecf1a | ||
|
|
0d1817e7ca | ||
|
|
1a5b428bfb | ||
|
|
bd49e31f3b | ||
|
|
2dba83e3c5 | ||
|
|
75e9766da9 | ||
|
|
d2f8aa1c0d | ||
|
|
4aa4b7693f | ||
|
|
d50b450927 | ||
|
|
5674cdbfc5 | ||
|
|
3641829198 | ||
|
|
10a759b09e | ||
|
|
b5a3b36c1b | ||
|
|
b0c3839f2b | ||
|
|
3aa3e95e4c | ||
|
|
87f1e53e13 | ||
|
|
d7b45cc220 | ||
|
|
d8142a9764 | ||
|
|
8780f58739 | ||
|
|
e352104df8 | ||
|
|
cbb2b452bb | ||
|
|
6e947c6262 | ||
|
|
18f04da4ec | ||
|
|
3dad6ef65c | ||
|
|
41c4f5fe5c | ||
|
|
cfeedf19f8 | ||
|
|
2ab410bd6a | ||
|
|
aefbc5b2f5 | ||
|
|
abec9c37fa | ||
|
|
442b0e7cea | ||
|
|
0b853c6d52 | ||
|
|
cc7fc66899 | ||
|
|
6b994c2928 | ||
|
|
e6fe36d3cd | ||
|
|
f45ededf8b | ||
|
|
ed27bedcb4 | ||
|
|
eb1a7a0435 | ||
|
|
de00fdc5f7 | ||
|
|
8febe12c5c | ||
|
|
1368b201eb | ||
|
|
4ca166b0b9 | ||
|
|
c13533cf21 | ||
|
|
9fdf0f76e7 | ||
|
|
308f513edc | ||
|
|
900bcc3819 | ||
|
|
b6e0994dfc | ||
|
|
121339d948 | ||
|
|
c5bb84013a | ||
|
|
65b49268d3 | ||
|
|
ecebd62f86 | ||
|
|
6a8c9a703d | ||
|
|
ad05ae9aa5 | ||
|
|
abffe201e5 | ||
|
|
ee2bc27bda | ||
|
|
14b94865b7 | ||
|
|
6e1ceafcc2 | ||
|
|
58746560e9 | ||
|
|
082adca3e6 | ||
|
|
ee1dc2a8e8 | ||
|
|
92e2d835bd | ||
|
|
22aba04b47 | ||
|
|
399c615915 | ||
|
|
cbdba0941a | ||
|
|
90c54a48d0 | ||
|
|
22b18830f7 | ||
|
|
dab085e3a7 | ||
|
|
66fac10a98 | ||
|
|
e5fb5ddde1 | ||
|
|
dcf20fbbd6 | ||
|
|
5d659877fe | ||
|
|
a30dd69aaa | ||
|
|
b1f698bb7b | ||
|
|
2323420a87 | ||
|
|
7e120a3615 | ||
|
|
804db294ca | ||
|
|
d12aa6c263 | ||
|
|
d59e87d2bf | ||
|
|
8f3c0af548 | ||
|
|
1f3013c445 | ||
|
|
f13e99ab1a | ||
|
|
fb8ad84675 | ||
|
|
12608afe10 | ||
|
|
f97e92b4cb | ||
|
|
a74e26e3de | ||
|
|
a30b783692 | ||
|
|
e64a6a22e7 | ||
|
|
76892afa13 | ||
|
|
dcb1eb0d94 | ||
|
|
950ea224ff | ||
|
|
b22a844007 | ||
|
|
502756c731 | ||
|
|
e38dc19ea1 | ||
|
|
2bebb2b4a1 | ||
|
|
5b7be93c1a | ||
|
|
d04270ae3f | ||
|
|
1bef7c1977 | ||
|
|
ae037ff7af | ||
|
|
a4267d60df | ||
|
|
47e32ab2b3 | ||
|
|
5ac08e42d8 | ||
|
|
9c59684b61 | ||
|
|
f26e1e5a12 | ||
|
|
1cde4633e6 | ||
|
|
1393f8e9aa | ||
|
|
bfffa1d245 | ||
|
|
3a6b568ccc | ||
|
|
453a920af8 | ||
|
|
1fd86ffc2e | ||
|
|
96a0639a8a | ||
|
|
c12d0a3f23 | ||
|
|
cac8790405 | ||
|
|
ccd9726e01 | ||
|
|
5516b50b3a | ||
|
|
b5a3e010d8 | ||
|
|
2d7d267252 | ||
|
|
bd5d7aaada | ||
|
|
18b6be8e00 | ||
|
|
958abfef93 | ||
|
|
198be1062b | ||
|
|
0cfee02641 | ||
|
|
48dc38508a | ||
|
|
e763204bf7 | ||
|
|
370baf56ab | ||
|
|
4fd6bcbf99 | ||
|
|
59d1e23dea | ||
|
|
cb173f2f81 | ||
|
|
d047174c2f | ||
|
|
df25159d03 | ||
|
|
99618a687e | ||
|
|
a1b226e185 | ||
|
|
e93df4332a | ||
|
|
5a1f768b03 | ||
|
|
e854bc8fc9 | ||
|
|
9ab958708d | ||
|
|
85ea92d83b | ||
|
|
22a406ac51 | ||
|
|
58eed79413 | ||
|
|
e83dea8212 | ||
|
|
c829827f48 | ||
|
|
b47cf05a59 | ||
|
|
22a93514ff | ||
|
|
154865f0f1 | ||
|
|
71151770fd | ||
|
|
72623ce13e | ||
|
|
94f20d56e9 | ||
|
|
9e8ad9bfd9 | ||
|
|
e51a5be776 | ||
|
|
7d647340c6 | ||
|
|
c6ea3c0616 | ||
|
|
9ab90be6d4 | ||
|
|
10440320d1 | ||
|
|
fc7e93403a | ||
|
|
b0c4418584 | ||
|
|
5f73eb7788 | ||
|
|
a554312573 | ||
|
|
8a1fd391d1 | ||
|
|
95b104ee48 | ||
|
|
c3df69d011 | ||
|
|
73468a3e24 | ||
|
|
f254f98e42 | ||
|
|
d37076dd37 | ||
|
|
5ef9376148 | ||
|
|
d8abda7583 | ||
|
|
892c755389 | ||
|
|
aba2f90c9d | ||
|
|
dc487c7e64 | ||
|
|
18b1bd9518 | ||
|
|
845ab1fef0 | ||
|
|
94bfac3f75 | ||
|
|
bd5c9ce2a7 | ||
|
|
f5934a6274 | ||
|
|
c6f71fddc7 | ||
|
|
74764e2d6f | ||
|
|
9b00a8c54e | ||
|
|
66735e99c3 | ||
|
|
80acbb4343 | ||
|
|
2fb912d43d | ||
|
|
8c8dc6de7c | ||
|
|
677acdd14e | ||
|
|
6caeea98b9 | ||
|
|
c5d37ce028 | ||
|
|
112b405df6 | ||
|
|
47385d58e5 | ||
|
|
c8275c8f63 | ||
|
|
0c1e888a78 | ||
|
|
6a1ff3e080 | ||
|
|
6d41eba5ed | ||
|
|
c0abcc6d60 | ||
|
|
da71c81195 | ||
|
|
8e0d17e85c | ||
|
|
6d98c273c1 | ||
|
|
85f6ff34aa | ||
|
|
759c24be63 | ||
|
|
d85955ef60 | ||
|
|
3a53044198 | ||
|
|
4d5cd9c635 | ||
|
|
57b88160ae | ||
|
|
33ba602aef | ||
|
|
3632388315 | ||
|
|
6ee82e885b | ||
|
|
2f92cee416 | ||
|
|
9269473e10 | ||
|
|
c8611ce708 | ||
|
|
d8fd43e9e9 | ||
|
|
a2e471620d | ||
|
|
ffa3821acf | ||
|
|
5c98d47d8c | ||
|
|
0875eaac03 | ||
|
|
60734bdb2b | ||
|
|
e71b19424b | ||
|
|
daac0169d5 | ||
|
|
baacc0df52 | ||
|
|
c6921536f7 | ||
|
|
4abf0ad2b2 | ||
|
|
379d555d35 | ||
|
|
8c01acb8d2 | ||
|
|
2c2c3c21ba | ||
|
|
50fd27e07b | ||
|
|
3309035814 | ||
|
|
b691758fa9 | ||
|
|
7c9afcec8b | ||
|
|
06ac05526a | ||
|
|
69cef8249a | ||
|
|
473df16a5a | ||
|
|
e1abf0528c | ||
|
|
ef0b335f67 | ||
|
|
1a866a3dc4 | ||
|
|
ed437b9e05 | ||
|
|
eea85872fd | ||
|
|
9d33e4cd5a | ||
|
|
530cc8d2a2 | ||
|
|
9baca84825 | ||
|
|
58538e4822 | ||
|
|
e31a8dc407 | ||
|
|
7875263092 | ||
|
|
de3b8509bf | ||
|
|
a19e1acfff | ||
|
|
e613b5c624 | ||
|
|
ccfddb0685 | ||
|
|
b8cd679679 | ||
|
|
fc26e472ab | ||
|
|
fc8c7349d6 | ||
|
|
a4d9b8df17 | ||
|
|
f26da68aa4 | ||
|
|
144182b540 | ||
|
|
a834ca4921 | ||
|
|
d1fc216836 | ||
|
|
5e57338928 | ||
|
|
f3376b6f0e | ||
|
|
5e001fdd9d | ||
|
|
9fda06276c | ||
|
|
df79c306d9 | ||
|
|
e4955e6851 | ||
|
|
0fec9e7ac4 | ||
|
|
5be8bb435b | ||
|
|
35b915ab10 | ||
|
|
80c57e996d | ||
|
|
511293d580 | ||
|
|
fe2b816447 | ||
|
|
093b7dc1e8 | ||
|
|
811fa57cbc | ||
|
|
359ad20a6a | ||
|
|
ac9989e4ff | ||
|
|
7268551737 | ||
|
|
823b1974bb | ||
|
|
382f636206 | ||
|
|
9a1b4abcf9 | ||
|
|
a0fc57687b | ||
|
|
02897f982f | ||
|
|
07a5d0ed0a | ||
|
|
017995ade6 | ||
|
|
9711b2280c | ||
|
|
619331916f | ||
|
|
d7909f7312 | ||
|
|
22674f2b46 | ||
|
|
845736c489 | ||
|
|
501f9db465 | ||
|
|
8dd440a582 | ||
|
|
dd7f090b4b | ||
|
|
dc14a2677b | ||
|
|
8b1ed7f0ae | ||
|
|
19b01b404d | ||
|
|
ec780d2d4d | ||
|
|
07790f6711 | ||
|
|
f72d2b6c67 | ||
|
|
e35d631012 | ||
|
|
3499a08207 | ||
|
|
0ac23e512e | ||
|
|
1852fabcd2 | ||
|
|
7b6bfac7cb | ||
|
|
e72aa5fb79 | ||
|
|
f4b02b92cc | ||
|
|
39edcc560f | ||
|
|
50669a320c | ||
|
|
d22c0b05ef | ||
|
|
689be30803 | ||
|
|
b393a83d38 | ||
|
|
1a1339da6b | ||
|
|
9926b51da0 | ||
|
|
761447dea3 | ||
|
|
829c20ba8a | ||
|
|
9ac734e191 | ||
|
|
5420fc6c51 | ||
|
|
62c8ac3e5d | ||
|
|
1d7e93251c | ||
|
|
92fa4691d1 | ||
|
|
a20fdf4713 | ||
|
|
570dedf1c3 | ||
|
|
59e5c873ad | ||
|
|
8dbcdf9991 | ||
|
|
cd43b50068 | ||
|
|
c0413a26f9 | ||
|
|
b2d3d86e0c | ||
|
|
bc7552f4a8 | ||
|
|
28ae13092f | ||
|
|
1f561da43f | ||
|
|
ef8dcda196 | ||
|
|
cf9eb892cf | ||
|
|
ffa1e2e59c | ||
|
|
9549e82b04 | ||
|
|
50261e390e | ||
|
|
618fc99cda | ||
|
|
a9fc7e15f8 | ||
|
|
6b064870f5 | ||
|
|
d78c50be3b | ||
|
|
c96cea5a13 | ||
|
|
51d4e930f5 | ||
|
|
e650addfe4 | ||
|
|
30afcb45d8 | ||
|
|
e10c3586a3 | ||
|
|
836d892832 | ||
|
|
826d251ffe | ||
|
|
510cd062ba | ||
|
|
2695cd6f3e | ||
|
|
f6e3cbbb65 | ||
|
|
f172bbaad2 | ||
|
|
9176953a8e | ||
|
|
ae6b87d646 | ||
|
|
f719b2387a | ||
|
|
5bfa8321d0 | ||
|
|
e99fd23e69 | ||
|
|
5057366fb2 | ||
|
|
44801b8b91 | ||
|
|
9eabc86bdd | ||
|
|
fbc8f407eb | ||
|
|
09a8b93634 | ||
|
|
2caa7b77e7 | ||
|
|
c057247126 | ||
|
|
0899be21c3 | ||
|
|
c29c9f9ccd | ||
|
|
c12f698f32 | ||
|
|
d6a8a6d159 | ||
|
|
7bf325f91a | ||
|
|
fdfff0c5c5 | ||
|
|
4409f613e0 | ||
|
|
9de644b0f3 | ||
|
|
3e36363d28 | ||
|
|
4f1d1a949c | ||
|
|
e52f3b8b30 | ||
|
|
36916e7b3d | ||
|
|
ba778e9bd2 | ||
|
|
df7112489a | ||
|
|
d9c203736f | ||
|
|
2b61ffa784 | ||
|
|
ba85640172 | ||
|
|
4d21ad5050 | ||
|
|
aae14de62b | ||
|
|
70fa621745 | ||
|
|
e97f4f7f41 | ||
|
|
7a08ddce9e | ||
|
|
e19c9d31a8 | ||
|
|
51ae5f9f0c | ||
|
|
22e8133f95 | ||
|
|
c2e19fed01 | ||
|
|
274afc9978 | ||
|
|
0c337836ca | ||
|
|
1a3e694e20 | ||
|
|
a0572b63b1 | ||
|
|
1765d8ef06 | ||
|
|
1e00a102e8 | ||
|
|
61f8dcdbae | ||
|
|
39eeb3aec7 | ||
|
|
2178dcfcab | ||
|
|
f8b4f44105 | ||
|
|
9c2468c2b7 | ||
|
|
3d5cc55d0a | ||
|
|
5b9cccd2dd | ||
|
|
103b2ab79b | ||
|
|
05f1cd784c | ||
|
|
6e6754f84e | ||
|
|
33ef448a86 | ||
|
|
8ce59c2e9d | ||
|
|
85a363d325 | ||
|
|
7dc1a9dc0e | ||
|
|
983d90b731 | ||
|
|
f307762801 | ||
|
|
7924798e7a | ||
|
|
e46bbaffb9 | ||
|
|
0171c49413 | ||
|
|
a79cd9da97 | ||
|
|
408959c927 | ||
|
|
ac4d93fe29 | ||
|
|
82d224fa66 | ||
|
|
a5b6d8e391 | ||
|
|
7f79abec3f | ||
|
|
ca8d4aa97a | ||
|
|
690cef561c | ||
|
|
16ac4c556b | ||
|
|
3c175b9199 | ||
|
|
a3827cc384 | ||
|
|
353daecbd1 | ||
|
|
368392fb8f | ||
|
|
57441b2fc1 | ||
|
|
b225600238 | ||
|
|
6b361e0d0c | ||
|
|
08668aa02b | ||
|
|
3d3eb6f1d2 | ||
|
|
9bd820c652 | ||
|
|
0e960ec23f | ||
|
|
ca65d81b60 | ||
|
|
23624a1d73 | ||
|
|
3ac08b0395 | ||
|
|
dedb79dbc5 | ||
|
|
154b503bc6 | ||
|
|
5c612ce521 | ||
|
|
80582ac5ce | ||
|
|
8e6af3bfeb | ||
|
|
61671d1b18 | ||
|
|
aa3ad973d0 | ||
|
|
a19a010d1e | ||
|
|
36003b6bb3 | ||
|
|
3c83e4088c | ||
|
|
357feb9532 | ||
|
|
7e234cba65 | ||
|
|
0535ceeaeb | ||
|
|
e688f0b1df | ||
|
|
a950e15625 | ||
|
|
cf8b198dac | ||
|
|
c75d5da02d | ||
|
|
cdffb15066 | ||
|
|
cd0ad0dba9 | ||
|
|
d3be5dba96 | ||
|
|
cb94a26a9f | ||
|
|
3c8b238e75 | ||
|
|
74202d52b3 | ||
|
|
603c92cd0e | ||
|
|
e514d74f43 | ||
|
|
970161464a | ||
|
|
3e7de27c00 | ||
|
|
e28d403216 | ||
|
|
fdeb9f1322 | ||
|
|
76fad21103 | ||
|
|
5d4fa31083 | ||
|
|
c3858f4e63 | ||
|
|
2e0fc21878 | ||
|
|
4b71bbec7e | ||
|
|
052989a5a2 | ||
|
|
60cfc63c4e | ||
|
|
60ef4c7f06 | ||
|
|
58fc40d0f1 | ||
|
|
3d7e9e7c03 | ||
|
|
52e745f905 | ||
|
|
8433fc178c | ||
|
|
59807baa18 | ||
|
|
9b5b15e8cb | ||
|
|
2c54b63c51 | ||
|
|
e4d1167274 | ||
|
|
2f10aba390 | ||
|
|
a044fadec8 | ||
|
|
0edb6165b5 | ||
|
|
7d262f2450 | ||
|
|
fa30328572 | ||
|
|
b0cff7c6ac | ||
|
|
50da9e803c | ||
|
|
26252fedf5 | ||
|
|
2dcda90c7b | ||
|
|
b7d79c0a83 | ||
|
|
ae285c0a01 | ||
|
|
07db846f3b | ||
|
|
3b6907b743 | ||
|
|
82e49c6214 | ||
|
|
8e9aa9cac4 | ||
|
|
5cd6c1dd36 | ||
|
|
a98ce5ea91 | ||
|
|
a4bb0fab8f | ||
|
|
7b2e242c94 | ||
|
|
5fd6352a4e | ||
|
|
a82f2ba065 | ||
|
|
3377acd9e6 | ||
|
|
709168652a | ||
|
|
e25e9ba29b | ||
|
|
ed5eac6e9d | ||
|
|
651768f012 | ||
|
|
88c0a881da | ||
|
|
5b9dd504e5 | ||
|
|
165ec09061 | ||
|
|
6cc972bab2 | ||
|
|
333047fc4c | ||
|
|
3e4a5932c2 | ||
|
|
e2f6b81a03 | ||
|
|
0231aad947 | ||
|
|
6636800c5b | ||
|
|
d1f41de0cb | ||
|
|
c4d339cb62 | ||
|
|
56b2adc57d | ||
|
|
a73bee2650 | ||
|
|
517da1b999 | ||
|
|
25497bd96f | ||
|
|
d12b1edc39 | ||
|
|
0515cfd068 | ||
|
|
e84bc9fc0d | ||
|
|
d85df43329 | ||
|
|
16e2e07d41 | ||
|
|
57fcb4012b | ||
|
|
5be981def3 | ||
|
|
493e38abfc | ||
|
|
6e006d216b | ||
|
|
da613ad188 | ||
|
|
3dad326bea | ||
|
|
480a791f4c | ||
|
|
753c46ef14 | ||
|
|
f2d5de252b | ||
|
|
0cb1a8054f | ||
|
|
07eb5697ab | ||
|
|
e4dc06a0e2 | ||
|
|
cd2012f33d | ||
|
|
9eba30648d | ||
|
|
7e70371197 | ||
|
|
527f6d8d9a | ||
|
|
9ebc12a98f | ||
|
|
bb21d9a6ad | ||
|
|
ad39cdd393 | ||
|
|
0de771036b | ||
|
|
6d6afa4cfd | ||
|
|
7546cbedd2 | ||
|
|
8d5962eefd | ||
|
|
8597b0b8c0 | ||
|
|
c625c39883 | ||
|
|
bce86460fe | ||
|
|
f002eebc83 | ||
|
|
139da2e49f |
No files matched your search
@@ -11,14 +11,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: CPU Information
|
||||
run: lscpu || sysctl -a|grep cpu || echo "CPU information not available"
|
||||
- name: make check C99
|
||||
run: make clean check CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="cc -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="cc -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="cc -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C++
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="c++ -std=c++11"
|
||||
run: make clean && make check -j 2 CC="c++ -std=c++11"
|
||||
|
||||
build_linux32:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -28,19 +30,29 @@ jobs:
|
||||
- name: update package list
|
||||
run: sudo apt-get update
|
||||
- name: install multilib
|
||||
run: sudo apt-get install gcc-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 check CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c99 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C11 (32bits)
|
||||
working-directory: ./tests
|
||||
run: make clean check CC="gcc -m32 -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
run: make clean && make check -j 2 CC="gcc -m32 -std=c11 -Wno-unknown-warning-option -Werror"
|
||||
- name: make check C++ (32 bits)
|
||||
working-directory: ./tests
|
||||
run: make clean && make check -j 2 CC="g++ -m32 -std=c++11 -Wno-unknown-warning-option "
|
||||
- name: make check against C++ STL
|
||||
working-directory: ./tests
|
||||
run: make clean && make check-stl -j 2
|
||||
|
||||
build_linux_tcc:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: CPU Information
|
||||
run: lscpu || echo "CPU information not available"
|
||||
- name: Clone TCC
|
||||
shell: bash
|
||||
run: git clone https://repo.or.cz/tinycc.git
|
||||
@@ -54,6 +66,15 @@ jobs:
|
||||
shell: bash
|
||||
run: make CC="/tmp/tcc/bin/tcc -std=c99" check
|
||||
|
||||
build_linux_sanitize:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make sanitize
|
||||
working-directory: ./tests
|
||||
run: make sanitize -j 2
|
||||
|
||||
build_windows_mingw:
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -61,7 +82,7 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- name: make check
|
||||
shell: bash
|
||||
run: mingw32-make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
run: mingw32-make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_msys2:
|
||||
runs-on: windows-latest
|
||||
@@ -76,7 +97,7 @@ jobs:
|
||||
update: true
|
||||
install: git mingw-w64-x86_64-toolchain make
|
||||
- name: make check
|
||||
run: make CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
run: make -j 2 CC="gcc -std=c99 -D__USE_MINGW_ANSI_STDIO=1" check
|
||||
|
||||
build_windows_visual:
|
||||
runs-on: windows-latest
|
||||
|
||||
@@ -34,11 +34,6 @@ jobs:
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
|
||||
@@ -42,3 +42,4 @@ config
|
||||
.vscode
|
||||
.vs
|
||||
tmp-serial.*
|
||||
*~
|
||||
@@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017-2021, Patrick Pelissier
|
||||
Copyright (c) 2017-2022, 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-2022, 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.5.0
|
||||
VERSION=0.7.0
|
||||
|
||||
# Define the contain of the distribution tarball
|
||||
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tuple.h m-variant.h m-worker.h
|
||||
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-tree.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
|
||||
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/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt
|
||||
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c
|
||||
TEST=tests/test-malgo.c tests/test-marray.c tests/test-mbitset.c tests/test-mbptree.c tests/test-mbuffer.c tests/test-mcmempool.c tests/test-mconcurrent.c tests/test-mcore.c tests/test-mdeque.c tests/test-mdict.c tests/test-mfuncobj.c tests/test-mgenint.c tests/test-milist.c tests/test-mlist.c tests/test-mmempool.c tests/test-mmutex.c tests/test-mprioqueue.c tests/test-mrbtree.c tests/test-mserial-bin.c tests/test-mserial-json.c tests/test-mshared.c tests/test-msnapshot.c tests/test-mstring.c tests/test-mtuple.c tests/test-mvariant.c tests/test-mworker.c tests/tgen-bitset.c tests/tgen-marray.c tests/tgen-mdict.c tests/tgen-mlist.c tests/tgen-mstring.c tests/tgen-openmp.c tests/tgen-queue.c tests/tgen-shared.c tests/tgen-mserial.c tests/Makefile tests/coverage.h tests/test-obj.h tests/dict.txt tests/fail-chain-oplist.c tests/fail-incompatible.c tests/fail-no-oplist.c tests/test-mishared.c tests/check-array.cpp tests/check-deque.cpp tests/check-dplist.cpp tests/check-list.cpp tests/check-rbtree.cpp tests/check-uset.cpp tests/check-generic.hpp tests/test-mtree.c tests/check-bptree-map.cpp tests/check-bptree-set.cpp tests/check-prioqueue.cpp tests/check-umap.cpp
|
||||
|
||||
.PHONY: all test check doc clean distclean depend install uninstall dist
|
||||
|
||||
@@ -58,17 +58,18 @@ checkall:
|
||||
cd tests && $(MAKE) checkall
|
||||
cd example && $(MAKE) all
|
||||
|
||||
html: doc
|
||||
doc: README.md doc/depend.png
|
||||
html: README.md
|
||||
markdown < README.md > README.html
|
||||
|
||||
doc: html doc/depend.png
|
||||
|
||||
clean:
|
||||
cd tests && $(MAKE) clean
|
||||
cd example && $(MAKE) clean
|
||||
cd bench && $(MAKE) clean
|
||||
$(RM) README.html depend.dot
|
||||
$(RM) -r 'm*lib-$(VERSION)'
|
||||
$(RM) 'm*lib-$(VERSION).tar.bz2'
|
||||
$(RM) -r 'm_lib-$(VERSION)'
|
||||
$(RM) 'm_lib-$(VERSION).tar.bz2'
|
||||
|
||||
distclean: clean
|
||||
cd tests && $(MAKE) distclean
|
||||
@@ -81,7 +82,7 @@ doc/depend.png: $(HEADER)
|
||||
dot -Tpng depend.dot -o doc/depend.png
|
||||
optipng -o7 doc/depend.png
|
||||
|
||||
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean
|
||||
dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean versioncheck
|
||||
$(MKDIR) '$(PACKAGE)'
|
||||
$(MKDIR) '$(PACKAGE)/doc'
|
||||
$(MKDIR) '$(PACKAGE)/tests'
|
||||
@@ -96,6 +97,14 @@ dist: $(HEADER) $(DOC1) $(DOC2) $(EXAMPLE) $(TEST) Makefile clean
|
||||
distcheck: dist
|
||||
cd '$(PACKAGE)' && make check
|
||||
|
||||
versioncheck:
|
||||
@if test "$(VERSION)." != `grep M_CORE_VERSION m-core.h |awk '{printf "%d.",$$3 } END {printf "\n"}'` ; then echo "ERROR: Version mismatch between Makefile & HEADERS" ; exit 2 ; fi
|
||||
@for i in *.h ; do echo $(HEADER) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing header $$i in Makefile" ; exit 3 ; fi ; done
|
||||
@for i in doc/* ; do echo $(DOC2) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing document $$i in Makefile" ; exit 4 ; fi ; done
|
||||
@for i in tests/*.c tests/*.txt tests/*.h ; do echo $(TEST) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing test $$i in Makefile" ; exit 5 ; fi ; done
|
||||
@for i in example/*.c example/*.json ; do echo $(EXAMPLE) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing example $$i in Makefile" ; exit 6 ; fi ; done
|
||||
@for i in tests/*.cpp tests/*.hpp ; do echo $(TEST) | grep -q $$i ; if test $$? -ne 0 ; then echo "ERROR: Missing test $$i in Makefile" ; exit 7 ; fi ; done
|
||||
|
||||
install:
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
$(INSTALL_DATA) $(HEADER) $(DESTDIR)$(PREFIX)/include/m-lib
|
||||
|
||||
+62
-9
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2022, 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
|
||||
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
|
||||
@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
|
||||
|
||||
@@ -339,6 +350,44 @@ bench-rigtorp-mpmc-queue0:
|
||||
$(CXX) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I "$${RIGTORP_MPMC_QUEUE}" bench-rigtorp-mpmcqueue.cpp common.c -DMULTI_THREAD_MEASURE -o bench-mpmcqueue.exe -lpthread
|
||||
@./bench-mpmcqueue.exe 60
|
||||
|
||||
# CTL shall point to the source directory (not where the headers are)
|
||||
bench-ctl:
|
||||
@if test -n "$${CTL}" ; then $(MAKE) bench-ctl0 ; else echo "Nothing to be done for CTL." ; fi
|
||||
|
||||
bench-ctl0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${CTL} bench-ctl.c common.c -o bench-ctl.exe
|
||||
@./bench-ctl.exe 10
|
||||
@./bench-ctl.exe 20
|
||||
@./bench-ctl.exe 30
|
||||
@./bench-ctl.exe 40
|
||||
@./bench-ctl.exe 50
|
||||
|
||||
# STC shall point to the source directory (not where the headers are)
|
||||
bench-stc:
|
||||
@if test -n "$${STC}" ; then $(MAKE) bench-stc0 ; else echo "Nothing to be done for STC." ; fi
|
||||
|
||||
bench-stc0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -I $${STC}/include bench-stc.c common.c -o bench-stc.exe
|
||||
@./bench-stc.exe 10
|
||||
@./bench-stc.exe 20
|
||||
@./bench-stc.exe 30
|
||||
@./bench-stc.exe 40
|
||||
@./bench-stc.exe 41
|
||||
@./bench-stc.exe 50
|
||||
|
||||
# POTTERY shall point to the source directory (not where the headers are)
|
||||
bench-pottery:
|
||||
@if test -n "$${POTTERY}" ; then $(MAKE) bench-pottery0 ; else echo "Nothing to be done for POTTERY." ; fi
|
||||
|
||||
bench-pottery0:
|
||||
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -DPOTTERY_AVAILABLE=1 -I $${POTTERY}/include bench-pottery.c common.c -o bench-pottery.exe
|
||||
@./bench-pottery.exe 10
|
||||
@./bench-pottery.exe 20
|
||||
@./bench-pottery.exe 30
|
||||
@./bench-pottery.exe 40
|
||||
@./bench-pottery.exe 41
|
||||
@./bench-pottery.exe 50
|
||||
|
||||
############################################################################
|
||||
|
||||
bench-mlib-json: bench-mlib
|
||||
@@ -377,12 +426,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:
|
||||
@@ -392,6 +441,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
|
||||
@@ -399,6 +451,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,183 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "m-core.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/********************************************************************************************/
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_array(size_t n)
|
||||
{
|
||||
vec_uint a1 = vec_uint_init();
|
||||
vec_uint a2 = vec_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_uint_push_back(&a1, rand_get() );
|
||||
vec_uint_push_back(&a2, rand_get() );
|
||||
}
|
||||
unsigned int s = 0;
|
||||
for(unsigned long i = 0; i < n; i++) {
|
||||
s += *vec_uint_at(&a1, i ) * *vec_uint_at(&a2, i );
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
vec_uint_free(&a1);
|
||||
vec_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T uint
|
||||
#include "ctl/forward_list.h"
|
||||
|
||||
static void test_list (size_t n)
|
||||
{
|
||||
slist_uint a1 = slist_uint_init();
|
||||
slist_uint a2 = slist_uint_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
slist_uint_push_front(&a1, rand_get());
|
||||
slist_uint_push_front(&a2, rand_get());
|
||||
}
|
||||
unsigned int s = 0;
|
||||
slist_uint_it it1 = slist_uint_begin(&a1);
|
||||
slist_uint_it it2 = slist_uint_begin(&a2);
|
||||
for( ; !slist_uint_it_done(&it1) ;
|
||||
slist_uint_it_next(&it1), slist_uint_it_next(&it2)) {
|
||||
s += *slist_uint_it_ref(&it1) * *slist_uint_it_ref(&it2);
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
slist_uint_free(&a1);
|
||||
slist_uint_free(&a2);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T ulong
|
||||
#include "ctl/set.h"
|
||||
|
||||
static inline int
|
||||
int_cmp(ulong *a, ulong *b) {
|
||||
return *a < *b;
|
||||
}
|
||||
|
||||
static void test_rbtree(size_t n)
|
||||
{
|
||||
set_ulong tree = set_ulong_init (int_cmp);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
set_ulong_insert (&tree, rand_get() );
|
||||
}
|
||||
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long j = rand_get();
|
||||
if (set_ulong_find_node(&tree, j) != NULL)
|
||||
s+= j;
|
||||
}
|
||||
g_result = s;
|
||||
set_ulong_free(&tree);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
unsigned long key;
|
||||
unsigned long value;
|
||||
} pair_ulong;
|
||||
|
||||
// Use of M*LIB hash function
|
||||
static inline size_t
|
||||
pair_ulong_hash(pair_ulong *a)
|
||||
{
|
||||
return M_HASH_DEFAULT(a->key);
|
||||
}
|
||||
|
||||
static inline int
|
||||
pair_ulong_equal(pair_ulong *a, pair_ulong *b)
|
||||
{
|
||||
return a->key == b->key;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pair_ulong_free(pair_ulong *a) {
|
||||
(void) a;
|
||||
}
|
||||
|
||||
static inline pair_ulong
|
||||
pair_ulong_copy(pair_ulong *self) {
|
||||
return (pair_ulong) { .key = self->key, .value = self->value };
|
||||
}
|
||||
|
||||
#define T pair_ulong
|
||||
#include <ctl/unordered_map.h>
|
||||
|
||||
static void
|
||||
test_dict(size_t n)
|
||||
{
|
||||
umap_pair_ulong dict = umap_pair_ulong_init(pair_ulong_hash, pair_ulong_equal);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
unsigned long value = rand_get();
|
||||
unsigned long key = rand_get();
|
||||
umap_pair_ulong_insert(&dict, (pair_ulong) { key, value });
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
umap_pair_ulong_it it = umap_pair_ulong_find(&dict, (pair_ulong) { rand_get() , 0 } );
|
||||
if (!umap_pair_ulong_it_done(&it) )
|
||||
s += it.ref->value;
|
||||
}
|
||||
g_result = s;
|
||||
|
||||
umap_pair_ulong_free(&dict);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
#define POD
|
||||
#define T float
|
||||
#include "ctl/vector.h"
|
||||
|
||||
static void test_sort(size_t n)
|
||||
{
|
||||
vec_float a1 = vec_float_init();
|
||||
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
vec_float_push_back(&a1, rand_get());
|
||||
}
|
||||
vec_float_sort(&a1);
|
||||
g_result = *vec_float_at(&a1, 0);
|
||||
vec_float_free(&a1);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 10, "List", 10000000, 0, test_list, 0},
|
||||
{ 20, "Array", 100000000, 0, test_array, 0},
|
||||
{ 30, "Rbtree", 1000000, 0, test_rbtree, 0},
|
||||
{ 40, "dict", 1000000, 0, test_dict, 0},
|
||||
{ 50, "Sort", 10000000, 0, test_sort, 0},
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("CTL", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
#define NDEBUG
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hash_table7.hpp"
|
||||
|
||||
using namespace emhash7;
|
||||
using namespace std;
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
static void
|
||||
test_dict2(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[rand_get()] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(rand_get());
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict2_linear(size_t n)
|
||||
{
|
||||
HashMap<unsigned long, unsigned long> dict;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
dict[i] = rand_get();
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
HashMap<unsigned long, unsigned long>::iterator it = dict.find(i);
|
||||
if (it != dict.end())
|
||||
s += it->second;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
struct char_array_s {
|
||||
char a[256];
|
||||
char_array_s () { a[0] = 0 ; }
|
||||
char_array_s ( const char_array_s & other) { strcpy(a, other.a); }
|
||||
bool operator==(const char_array_s &other) const { return strcmp(a, other.a) == 0; }
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <> struct hash<char_array_s> {
|
||||
std::size_t operator()(const char_array_s &k) const {
|
||||
size_t hash = 0;
|
||||
const char *s = k.a;
|
||||
while (*s) hash = hash * 31421 + (*s++) + 6927;
|
||||
return hash;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
test_dict_big(size_t n)
|
||||
{
|
||||
HashMap<char_array_s, char_array_s> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1, s2;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
sprintf(s2.a, "%u", rand_get());
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
char_array_s s1;
|
||||
sprintf(s1.a, "%u", rand_get());
|
||||
HashMap<char_array_s, char_array_s>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
static void
|
||||
test_dict_str(size_t n)
|
||||
{
|
||||
HashMap<string, string> dict;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
string s2 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
dict[s1] = s2;
|
||||
}
|
||||
rand_init();
|
||||
unsigned int s = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
string s1 = static_cast<ostringstream*>( &(ostringstream() << rand_get()) )->str();
|
||||
HashMap<string, string>::iterator it = dict.find(s1);
|
||||
if (it != dict.end())
|
||||
s ++;
|
||||
}
|
||||
g_result = s;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
const config_func_t table[] = {
|
||||
{ 41, "dictBig", 1000000, 0, test_dict_big, 0},
|
||||
{ 42,"dict", 1000000, 0, test_dict2, 0},
|
||||
{ 43, "DictStr", 1000000, 0, test_dict_str, 0},
|
||||
{ 46, "DictLinear", 1000000, 0, test_dict2_linear, 0}
|
||||
};
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
test("EMHASH", numberof(table), table, argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
+24
-28
@@ -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);
|
||||
}
|
||||
+77
-12
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - String Bench
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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);
|
||||
|
||||
+197
-48
@@ -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-2022 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;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - common functions for bench module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MLIB - TEST module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -35,10 +35,9 @@ static inline size_t my_hash(uint64_t key)
|
||||
{
|
||||
return ((key) ^ (key)>>7);
|
||||
}
|
||||
static inline void update_val(uint32_t *p, uint32_t v) { *p += v;}
|
||||
DICT_OA_DEF2(dict_oligonucleotide,
|
||||
uint64_t, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)),
|
||||
uint32_t, M_OPEXTEND(M_DEFAULT_OPLIST, UPDATE(update_val M_IPTR)))
|
||||
uint32_t, M_DEFAULT_OPLIST)
|
||||
#define M_OPL_dict_oligonucleotide_t() DICT_OPLIST(dict_oligonucleotide, M_OPEXTEND(M_DEFAULT_OPLIST, HASH(my_hash), OOR_EQUAL(my_oor_equal_p), OOR_SET(my_oor_set M_IPTR)), M_DEFAULT_OPLIST)
|
||||
|
||||
// Define a B*TREE-21 of uint32_t --> uint64_t and register its oplist
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../common.c"
|
||||
#define DICTI_OA_PROBING(s) 1
|
||||
#define M_USE_DICT_OA_PROBING(s) 1
|
||||
#include "m-dict.h"
|
||||
|
||||
static inline bool oor_equal_p(unsigned int k, unsigned char n)
|
||||
|
||||
+24
@@ -57,3 +57,27 @@ V0.4.*: * The order of a list initialized using M_LET is reversed
|
||||
* Rename TUPLE _init_set2 in _init_emplace & _set2 in _emplace.
|
||||
* Rename Priority Queue method _update_further in _update.
|
||||
|
||||
V0.5.*: * M_INVERT is renamed into M_REVERSE to be more coherent with the REVERSE operator.
|
||||
M_INVERT is marked as obsolete.
|
||||
* Remove _it_to_p method of B+TREE / RB-TREE as it has been deprecated.
|
||||
* Remove ALGO_INIT_VA & M_ALG0_LET_INIT_VAI of m-algo as it has been deprecated (Use of M_LET instead).
|
||||
* Some Internal name of user modifiable macros have been renamed to be properly
|
||||
customizable by the user.
|
||||
* Rename M_HASH_SEED into M_USE_HASH_SEED (as it is a user macro).
|
||||
* M_LET: for initialization of variable with arguments, if there is only one argument,
|
||||
it will default to use INIT_SET instead of INIT_WITH.
|
||||
==> Encapsulate the argument between () to force use of INIT_WITH.
|
||||
* Remove of UPDATE operator. Use of SET for RBTREE or ADD for DICT instead.
|
||||
* Make the _clean suffix for reseting the container to empty deprecated. Use new _reset suffix instead.
|
||||
* Make the _get_at suffix for always getting a value deprecated. Use new _safe_get suffix instead.
|
||||
* Rename CLEAN operator in RESET operator.
|
||||
* Rename GET_SET_KEY operator in SAFE_GET_KEY operator.
|
||||
|
||||
V0.6.*: * Rename M_DEFAULT_OPLIST in M_BASIC_OPLIST
|
||||
* Remove experimental macro M_IF_DEFAULT1.
|
||||
* Remove M_INVERT
|
||||
* String functions with _str suffix for C strings have been renamed with _cstr suffix (like string_cat_str ==> m_string_cat_cstr)
|
||||
Note: the compatible layer still keeps the old naming,
|
||||
so except if you are using the prefixed version of the strings
|
||||
or the bounded strings API, you won't need to upgrade your code.
|
||||
|
||||
Binary file not shown.
+61
-16
@@ -17,23 +17,31 @@ How to make a release?
|
||||
In case of problem, open a problem report.
|
||||
|
||||
|
||||
List of tested systems
|
||||
=======================
|
||||
List of automatically tested systems
|
||||
====================================
|
||||
|
||||
* gcc 4.9, 7 & 8 on linux/x86-64
|
||||
* clang 3.5, 4 & 6 on linux/x86-64
|
||||
* g++ 7 & 8 on linux/x86-64
|
||||
* gcc on linux/x86-64 (32 bits and 64 bits)
|
||||
* g++ on linux/x86-64 (32 bits and 64 bits)
|
||||
* clang on macos/x86-64
|
||||
* clang++ on macos/x86-64
|
||||
* tcc on linux/x86-64
|
||||
* gcc 7 on windows/x86-64
|
||||
* gcc 4.9 on linux/powerpc
|
||||
* gcc 6 on linux/armv7l
|
||||
* clang 3.8 on linux/armv7l
|
||||
* gcc on windows/x86-64 (mingw)
|
||||
* msvc on windows/x86-64
|
||||
* clang on windows/x86-64
|
||||
|
||||
List of manually tested systems
|
||||
===============================
|
||||
|
||||
* clang on linux/x86-64
|
||||
* clang on linux/armv7l
|
||||
* gcc on linux/powerpc
|
||||
* gcc on linux/armv7l
|
||||
|
||||
Atomic library
|
||||
==============
|
||||
|
||||
For target, armel m68k mips mipsel powerpc powerpcspe sh4, you may need to run the test suite:
|
||||
For the targets armel, m68k, mips, mipsel, powerpc, powerpcspe or sh4,
|
||||
you may need to run the test suite by adding the atomic library:
|
||||
|
||||
make check LDFLAGS="-pthread -latomic"
|
||||
|
||||
@@ -45,7 +53,7 @@ Cross compilation
|
||||
|
||||
There is no need to cross compile the library as it is a header only library.
|
||||
|
||||
However if you want to run the test with a cross-compiler, do like the following
|
||||
However if you want to run the tests with a cross-compiler, do like the following
|
||||
command. It performs a cross-compilation of the test suite from linux to windows
|
||||
and run the test suite with wine:
|
||||
|
||||
@@ -57,9 +65,8 @@ Handling issues
|
||||
|
||||
Issues are opened in the bug tracker of the project (typically https://github.com/P-p-H-d/mlib/issues )
|
||||
|
||||
If the issue cannot be closed and taken into account in less than (typically) one month,
|
||||
or before a release,
|
||||
it shall be moved into the long term issues included in the repository:
|
||||
If the issue cannot be taken into account quickly and are long term,
|
||||
it should be moved into the long term issues included in the repository:
|
||||
https://github.com/P-p-H-d/mlib/blob/master/doc/ISSUES.org
|
||||
This is a file in ORG mode: the issues are created with the proper tags.
|
||||
|
||||
@@ -75,7 +82,7 @@ its state shall be changed to DONE (the issue shall not be removed).
|
||||
|
||||
|
||||
Debugging
|
||||
===============
|
||||
=========
|
||||
|
||||
Debugging the library can be quite difficult
|
||||
as it performs heavy preprocessing expansion
|
||||
@@ -86,7 +93,7 @@ Different strategy for debugging the library itself are still possible:
|
||||
Add printf of interresting values in the debugged function.
|
||||
|
||||
|
||||
2) Preprocess the library and then compile the preprocessed file:
|
||||
2) Preprocess the library and then compile the preprocessed file like this:
|
||||
|
||||
cc -std=c99 -E test-file.c > test-file.i
|
||||
perl -pi -e 's/;/;\n/g' test-file.i
|
||||
@@ -109,3 +116,41 @@ Run the wave driver:
|
||||
./wave ex-array01.c -I .. --c99 -t test.trace
|
||||
|
||||
The different expansion performed by the library are described in test.trace
|
||||
|
||||
Coding rules
|
||||
============
|
||||
|
||||
* Use of non standard C shall be protected under a specific compiler test,
|
||||
so that the library remains compatible with a strict C99 compiler.
|
||||
|
||||
* C11 features shall be optional.
|
||||
|
||||
* Use 'make format' to format the header files properly.
|
||||
|
||||
* External types shall be suffixed by _t and in lower case
|
||||
but shall be optional if the user doesn't want then.
|
||||
|
||||
* Internal types shall be suffixed by _ct and in lower case
|
||||
(as confidential types)
|
||||
|
||||
* External / Internal functions shall be in lower case.
|
||||
|
||||
* External / Internal macros shall be in upper case.
|
||||
|
||||
* Internal macros / functions shall be prefixed by m_<container>
|
||||
with container is the name of the container with one letter transformed:
|
||||
o --> 0
|
||||
e --> 3
|
||||
i --> 1
|
||||
y --> 4
|
||||
This prevents the automatic completion to work when the user starts writing its function.
|
||||
|
||||
* Test functions shall be predicated and be suffixed by '_p'
|
||||
|
||||
|
||||
Misc
|
||||
====
|
||||
|
||||
To put a breakpoint for the thread sanitizer in case of error, in gdb add:
|
||||
|
||||
$ set env TSAN_OPTIONS=halt_on_error=1,abort_on_error=1
|
||||
+46
-34
@@ -5,17 +5,34 @@
|
||||
|
||||
Specialize Hashmap for huge objects on supported hardware:
|
||||
|
||||
based on OA hash map with taggued pointer (needs space for tagging):
|
||||
low bits = low bits of hash
|
||||
Based on OA hash map with taggued pointer (needs space for tagging):
|
||||
low bits = high bits of hash
|
||||
pointer to object { key, hash, value }
|
||||
|
||||
Can detect collision without dereferencing object with 1/2^lowbits chances.
|
||||
Can solve collision without dereferencing object with 1/2^lowbits chances.
|
||||
NB: hash may be uneeded due to the small chances of collision.
|
||||
Reduce cache usage ==> Should be faster.
|
||||
Increase cache usage for very small object (integer).
|
||||
|
||||
Use of pointer to avoid moving object on GC.
|
||||
|
||||
On AMD64, only 48 bits of 64 bits are really used for addressing data.
|
||||
==> lowbits= 16
|
||||
Empty representation= 0 (hash can be 0. pointer cannot be it).
|
||||
Deleted representation = 1 (pointer cannot be zero)
|
||||
|
||||
<---- PTR ----><-HASH->
|
||||
|
||||
#+BEGIN_SRC C
|
||||
#define LOW_BITS 16
|
||||
#define ALIGNED_BITS 2
|
||||
void *get_ptr(int64_t x) {
|
||||
return (void*) ((x >> LOW_BITS) << ALIGNED_BITS);
|
||||
}
|
||||
unsigned get_small_hash(int64_t x) {
|
||||
return x & ((1<<LOW_BITS)-1);
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
* TODO #25 : Support of error code model for error handling. :ENHANCEMENT:
|
||||
|
||||
@@ -85,7 +102,7 @@ Open points:
|
||||
- What about M_LET/ M_EACH?
|
||||
|
||||
|
||||
* TODO #24 : Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
* TODO #24 : New: Add MIN-MAX-HEAP container :ENHANCEMENT:
|
||||
|
||||
See https://en.wikipedia.org/wiki/Min-max_heap
|
||||
as DPRIORITY_QUEUE_DEF ?
|
||||
@@ -93,7 +110,7 @@ as DPRIORITY_QUEUE_DEF ?
|
||||
NOTE: Needs for such container?
|
||||
|
||||
|
||||
* TODO #23: Force MOVE semantic :ENHANCEMENT:
|
||||
* TODO #23: Strict MOVE semantic to clarify :ENHANCEMENT:
|
||||
|
||||
Some type may need to have a force MOVE semantic (for example, they can store
|
||||
pointer to themselves). Currently the INIT_MOVE & MOVE operators are more
|
||||
@@ -128,7 +145,7 @@ operators as it uses MOVE_DEFAULT which is not (fully compatible).
|
||||
==> Analyse limitation and possible constraint usages.
|
||||
|
||||
|
||||
* TODO #20: Bucket priority queue :ENHANCEMENT:
|
||||
* TODO #20: New: Bucket priority queue :ENHANCEMENT:
|
||||
|
||||
Add a new kind of priority queue.
|
||||
See https://en.wikipedia.org/wiki/Bucket_queue
|
||||
@@ -145,7 +162,7 @@ Check if we can use BITSET, or introduce fixed size BITSET or use ad-hock
|
||||
implementation.
|
||||
|
||||
|
||||
* TODO #19: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
* TODO #19: New: Intrusive Red Black Tree :ENHANCEMENT:
|
||||
|
||||
Add intrusive red black tree.
|
||||
Look also for AVL tree (NOTE: Is there a performance difference between the two?)
|
||||
@@ -158,9 +175,9 @@ 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: Ressource handler :ENHANCEMENT:
|
||||
* TODO #17: New: Ressource handler :ENHANCEMENT:
|
||||
|
||||
A ressouce handler which shall associated a unique handle to a ressource.
|
||||
A global 'ressouce handler' which shall associated a unique handle to a ressource.
|
||||
The handle shall be unique for the ressource and shall not be reused.
|
||||
It is typically a 64 bits integers always incremented (even if the program
|
||||
creates one billion ressources per second, the counter won't overflow
|
||||
@@ -189,7 +206,7 @@ http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Co
|
||||
* embedded the type in the ressource handler: more work, API more complex. Memory usage seems better.
|
||||
|
||||
|
||||
* TODO #16: Lock Free List :ENHANCEMENT:
|
||||
* TODO #16: New: Lock Free List :ENHANCEMENT:
|
||||
|
||||
Implement a lock free list. Most of the difficulty is the memory reclamation part.
|
||||
Typically this lock free list shall be compatible with RCU method.
|
||||
@@ -271,7 +288,7 @@ 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.
|
||||
|
||||
|
||||
* TODO #12: Atomic shared pointer :ENHANCEMENT:
|
||||
* TODO #12: New: Atomic shared pointer :ENHANCEMENT:
|
||||
|
||||
Add an extension to the SHARED_PTR API:
|
||||
|
||||
@@ -347,11 +364,14 @@ Other implementation seems to have it hard to be lock-free: cf. https://github.c
|
||||
|
||||
|
||||
|
||||
* TODO #5: Concurrent dictionary Container :ENHANCEMENT:
|
||||
* TODO #5: New: Concurrent dictionary Container :ENHANCEMENT:
|
||||
|
||||
Implement a more efficient dictionary than lock + std dictionary for all operations when dealing with threads.
|
||||
See https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx
|
||||
|
||||
The best parallel algorithm is still when there is as few synchronization as possible. A concurrent dictionary will fail at this and will result in average performance at best.
|
||||
The typical best case will be in RCU context (a lot of readers, few writers), so the interface shall be compatible with such structure.
|
||||
|
||||
** Multiple locks within the dictionnary
|
||||
|
||||
A potential implementation may be to request at initialization time the number of concurrent thread N.
|
||||
@@ -372,33 +392,25 @@ See also https://github.com/simonhf/sharedhashfile
|
||||
** Lock Free dictionnary
|
||||
|
||||
Evaluate also lock-free dictionary (easier with open addressing).
|
||||
It needs a complete rewrite of the inner loop through. The hard part is the dynamic resizing of the internal array (see http://preshing.com/20160222/a-resizable-concurrent-map/ for a potential solution and http://www.cs.toronto.edu/~tomhart/papers/tomhart_thesis.pdf for memory reclamation techniques). See also https://www.research.ibm.com/people/m/michael/spaa-2002.pdf
|
||||
https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2017.11.22a.pdf persents different techniques used by linux kernel.
|
||||
It needs a complete rewrite of the inner loop through. The hard part is the dynamic resizing of the internal array.
|
||||
Ssee http://preshing.com/20160222/a-resizable-concurrent-map/ for a potential solution
|
||||
and http://www.cs.toronto.edu/~tomhart/papers/tomhart_thesis.pdf for memory reclamation techniques).
|
||||
and https://www.research.ibm.com/people/m/michael/spaa-2002.pdf
|
||||
https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.2017.11.22a.pdf presents different techniques used by linux kernel.
|
||||
It needs before lock-free list: http://www.cse.yorku.ca/~ruppert/papers/lfll.pdf http://www.cse.yorku.ca/~ruppert/Mikhail.pdf
|
||||
|
||||
** Context
|
||||
|
||||
The best parallel algorithm is still when there is as few synchronization as possible. A concurrent dictionary will fail at this and will result in average performance at best.
|
||||
The typical best case will be in RCU context (a lot of readers, few writers), so the interface shall be compatible with such structure.
|
||||
|
||||
** Linked list
|
||||
|
||||
Another solution is to create a huge list of items which is:
|
||||
|
||||
- atomically updated,
|
||||
- in reverse order of the hash (bit 0 is highest bit, Bit 63 is the lowest bit).
|
||||
|
||||
Hash table will only give quick access to items to this list. Expanding the table won't change the order of the list (so the items will remain at the same place and always accessible by other threads) but just add sentinel in the sentinel at the right place (there won't be any reallocation of the list). Inserting will need to insert an item at the right place.
|
||||
Not sure it will really help. To analyse.
|
||||
|
||||
Concurrent dictionary is possible now with CONCURRENT_DEF + DICT_DEF.
|
||||
But it uses a global lock for all dictionary access.
|
||||
|
||||
** Open Addressing Indirect Table with a lock free node pool used as transaction pool.
|
||||
|
||||
A good way maybe Open Addessing table used only for indirection and a freelist memory reclamation container for handle the entries
|
||||
(like a transaction).
|
||||
|
||||
Solution?
|
||||
--------
|
||||
|
||||
Use of the concurrent pool (m-c-mempool) to allocate items.
|
||||
The big table will only store pointers (+ part of hash in unused bits?) to such allocate items.
|
||||
Atomic update is done by allocating a new node, update it, and atomicaly store it in the dict, putting the old one as logically deleted and to reclaim later.
|
||||
(Other threads may still read its data so we cannot free immediatly).
|
||||
|
||||
|
||||
* DONE #22: Enhanced services for SPSC Queue :ENHANCEMENT:
|
||||
|
||||
Add services:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 113 KiB |
+6
-3
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2022, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -23,6 +23,7 @@
|
||||
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
|
||||
GMP_DIR=
|
||||
MPFR_DIR=$(GMP_DIR)
|
||||
CPPFLAGS=-I..
|
||||
LDFLAGS=-pthread
|
||||
RM=rm -f
|
||||
@@ -30,7 +31,7 @@ RM=rm -f
|
||||
.SUFFIXES: .c .exe
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) `cat config` $< -o $@
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ `cat config`
|
||||
|
||||
all: config
|
||||
$(MAKE) `ls ex-*.c|sed -e 's/\.c/\.exe/g'`
|
||||
@@ -38,7 +39,9 @@ all: config
|
||||
|
||||
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) $(LDFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe 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) $(LDFLAGS) -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 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"
|
||||
$(RM) config-test.c config-test.exe
|
||||
|
||||
clean:
|
||||
|
||||
+3
-3
@@ -3,11 +3,11 @@
|
||||
#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)
|
||||
@@ -23,7 +23,7 @@ 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
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ int main(void)
|
||||
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;
|
||||
int sum = 0, product = 0;
|
||||
|
||||
// Compute the sum of theses integers.
|
||||
ALGO_REDUCE(sum, v, vector_int_t, add);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/* 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.
|
||||
*/
|
||||
ARRAY_DEF(r_bool, bool)
|
||||
|
||||
@@ -105,7 +105,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 +180,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)
|
||||
@@ -231,7 +231,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
|
||||
@@ -478,7 +478,7 @@ 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.
|
||||
|
||||
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,
|
||||
@@ -486,7 +486,7 @@ test_rockme2b(int n)
|
||||
*/
|
||||
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 +520,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 +533,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 +612,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,
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// -- An A* pathfinder inspired by the tutorial at Red Blob Games --
|
||||
// https://www.redblobgames.com/pathfinding/a-star/introduction.html
|
||||
// Code based on:
|
||||
// https://github.com/glouw/ctl/blob/master/examples/astar.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "m-array.h"
|
||||
#include "m-string.h"
|
||||
#include "m-tuple.h"
|
||||
#include "m-prioqueue.h"
|
||||
#include "m-dict.h"
|
||||
|
||||
// Create a tuple of point, but don't use its priority field for comparison.
|
||||
TUPLE_DEF2( point, (x, int), (y, int), (priority, int, M_OPEXTEND( M_OPL_int(), CMP(0), HASH(0), EQUAL(0) ) ) )
|
||||
#define M_OPL_point_t() TUPLE_OPLIST(point, M_OPL_int(), M_OPL_int(), M_OPL_int())
|
||||
static inline int point_cmp_prio(const point_t a, const point_t b)
|
||||
{
|
||||
return a->priority < b->priority ? -1 : a->priority > b->priority;
|
||||
}
|
||||
PRIOQUEUE_DEF(prio_point, point_t, M_OPEXTEND(M_OPL_point_t(), CMP(point_cmp_prio) ) )
|
||||
#define M_OPL_prio_point_t() PRIOQUEUE_OPLIST(prio_point, M_OPL_point_t() )
|
||||
ARRAY_DEF(array_point, point_t)
|
||||
#define M_OPL_array_point_t() ARRAY_OPLIST(array_point, M_OPL_point_t() )
|
||||
DICT_DEF2(cost_point, point_t, int)
|
||||
#define M_OPL_cost_point_t() DICT_OPLIST(cost_point, M_OPL_point_t(), M_OPL_int())
|
||||
DICT_DEF2(step_point, point_t, point_t)
|
||||
#define M_OPL_step_point_t() DICT_OPLIST(step_point, M_OPL_point_t(), M_OPL_point_t())
|
||||
|
||||
static inline int point_index(const point_t p, int width)
|
||||
{
|
||||
return p->x + width * p->y;
|
||||
}
|
||||
|
||||
static inline void point_set_from(point_t p, const string_t maze, int width, const char pattern[])
|
||||
{
|
||||
size_t s = string_search_str(maze, pattern);
|
||||
point_emplace(p, s % width, s / width , 0);
|
||||
}
|
||||
|
||||
static void astar(array_point_t path, const string_t maze, int width)
|
||||
{
|
||||
M_LET(front, prio_point_t)
|
||||
M_LET(from, step_point_t)
|
||||
M_LET(costs, cost_point_t)
|
||||
M_LET(start, goal, current, next, point_t)
|
||||
{
|
||||
point_set_from(start, maze, width, "@");
|
||||
point_set_from(goal, maze, width, "!");
|
||||
cost_point_set_at(costs, start, 0);
|
||||
prio_point_push(front, start);
|
||||
while (!prio_point_empty_p(front)) {
|
||||
prio_point_pop(¤t, front);
|
||||
if (point_equal_p(current, goal))
|
||||
break;
|
||||
const struct { int x; int y; } deltas[] = {
|
||||
{ -1, +1 }, { 0, +1 }, { 1, +1 },
|
||||
{ -1, 0 }, /* ~ ~ */ { 1, 0 },
|
||||
{ -1, -1 }, { 0, -1 }, { 1, -1 },
|
||||
};
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
point_emplace(next, current->x + deltas[i].x, current->y + deltas[i].y, 0);
|
||||
if (string_get_char(maze, point_index(next, width)) != '#') {
|
||||
int *new_cost = cost_point_get(costs, current);
|
||||
int *cost = cost_point_get(costs, next);
|
||||
if (cost == NULL || *new_cost < *cost) {
|
||||
cost_point_set_at(costs, next, *new_cost);
|
||||
next->priority = *new_cost + abs(goal->x - next->x) + abs(goal->y - next->y);
|
||||
prio_point_push(front, next);
|
||||
step_point_set_at(from, next, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
point_set(current, goal);
|
||||
while (!point_equal_p(current, start)) {
|
||||
array_point_push_back(path, current);
|
||||
point_set(current, *step_point_get(from, current));
|
||||
}
|
||||
array_point_push_back(path, start);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
M_LET( (maze,
|
||||
("#########################################################################\n"
|
||||
"# # # # # # #\n"
|
||||
"# # ######### # ##### ######### ##### ##### ##### # ! #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"######### # ######### ######### ##### # # # ######### #\n"
|
||||
"# # # # # # # # # # #\n"
|
||||
"# # ############# # # ######### ##### # ######### # #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ############# ##### ##### # ##### ######### # ##### #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ##### ##### # ##### # ######### # # # #############\n"
|
||||
"# # # # # # # # # # # #\n"
|
||||
"############# # # # ######### # ##### # ##### ##### #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# ##### # ######### ##### # ##### ##### ############# #\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# # ######### # ##### ######### # # ############# # #\n"
|
||||
"# # # # # # # # # # #\n"
|
||||
"# ######### # # # ##### ######### ######### # #########\n"
|
||||
"# # # # # # # # # #\n"
|
||||
"# @ # ##### ##### ##### ######### ##### # ######### # #\n"
|
||||
"# # # # # # #\n"
|
||||
"#########################################################################\n")), string_t)
|
||||
M_LET(path, array_point_t)
|
||||
{
|
||||
int width = string_search_str(maze, "\n") + 1;
|
||||
astar(path, maze, width);
|
||||
for M_EACH(it, path, array_point_t) {
|
||||
string_set_char(maze, point_index(*it, width), 'x');
|
||||
}
|
||||
printf("%s", string_get_cstr(maze));
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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; };
|
||||
|
||||
+1
-1
@@ -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)
|
||||
{
|
||||
|
||||
+3
-3
@@ -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)) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ int main(int argc, const char *argv[])
|
||||
// While it reads some word from the file
|
||||
while (string_fget_word(word, " \t\n\r\"(),=", f)) {
|
||||
// Get the reference to the array of this word in the dictionnary (or create it if needed)
|
||||
array_size_t *array = map_pos_get_at(positions, word);
|
||||
array_size_t *array = map_pos_safe_get(positions, word);
|
||||
// Push the new offset to this word in the associated array
|
||||
array_size_push_back(*array, (size_t)ftell(f) - string_size(word));
|
||||
}
|
||||
|
||||
+3
-2
@@ -28,11 +28,11 @@ int main(void)
|
||||
M_LET (grow, list_string_t)
|
||||
M_LET (tmpstr, string_t) { // And let's create also a string_t
|
||||
|
||||
// add string elements to the list
|
||||
// add string elements to the list in different ways
|
||||
list_string_push_back (grow, STRING_CTE("AB"));
|
||||
string_printf(tmpstr, "%d", 12);
|
||||
list_string_push_back (grow, tmpstr);
|
||||
list_string_push_back (grow, STRING_CTE("CD"));
|
||||
list_string_emplace_back (grow, "CD");
|
||||
|
||||
// Serialize the list of string into a big string.
|
||||
list_string_get_str (tmpstr, grow, false);
|
||||
@@ -75,6 +75,7 @@ int main(void)
|
||||
// Split a string into a list.
|
||||
string_set_str(tmpstr, "HELLO;JOHN;HOW;ARE;YOU");
|
||||
astring_split(grow, tmpstr, ';');
|
||||
// Iterate over the splitted list
|
||||
for M_EACH (item, grow, list_string_t) {
|
||||
printf ("Split Item = %s\n", string_get_cstr(*item) );
|
||||
}
|
||||
|
||||
+3
-3
@@ -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'
|
||||
@@ -124,7 +124,7 @@ CreateMinimalPerfectHash2(array_seed_t seed, array_value_t value,
|
||||
enought. */
|
||||
for(bool cont = true; cont ; ) {
|
||||
cont = false;
|
||||
array_seed_clean(slots);
|
||||
array_seed_reset(slots);
|
||||
for M_EACH(it, *b, array_cstr_t) {
|
||||
size_t s = hash(d, *it) % size;
|
||||
if (*array_value_get(value, s) != 0 || array_seed_contain_p(slots, s)){
|
||||
|
||||
@@ -48,8 +48,8 @@ static void program_init(program_t p, string_t text) {
|
||||
int left;
|
||||
array_int_pop_back(&left, leftstack);
|
||||
int right = pc;
|
||||
*array_int_get_at (p->bracket_map, left) = right;
|
||||
*array_int_get_at (p->bracket_map, right) = left;
|
||||
*array_int_safe_get (p->bracket_map, left) = right;
|
||||
*array_int_safe_get (p->bracket_map, right) = left;
|
||||
}
|
||||
|
||||
pc++;
|
||||
|
||||
@@ -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
|
||||
@@ -4,7 +4,7 @@
|
||||
/* Register a dynamic seed to M*LIB hash function.
|
||||
This shall be done before any M*LIB header inclusion. */
|
||||
unsigned long long rand_seed;
|
||||
#define M_HASH_SEED rand_seed
|
||||
#define M_USE_HASH_SEED rand_seed
|
||||
|
||||
#include "m-array.h"
|
||||
#include "m-dict.h"
|
||||
@@ -84,8 +84,8 @@ DICT_DEF2(dict_json, string_t, STRING_OPLIST, json_t, JSON_OPLIST)
|
||||
ARRAY_DEF(array_json, json_t, JSON_OPLIST)
|
||||
|
||||
VARIANT_DEF2(variant_json,
|
||||
(boolean, bool, M_OPEXTEND(M_DEFAULT_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
|
||||
(real, float, M_OPEXTEND (M_DEFAULT_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
|
||||
(boolean, bool, M_OPEXTEND(M_BASIC_OPLIST, OUT_STR(boolean_out_str), IN_STR(boolean_in_str M_IPTR)) ),
|
||||
(real, float, M_OPEXTEND (M_BASIC_OPLIST, OUT_STR(real_out_str), IN_STR(real_in_str M_IPTR))),
|
||||
(array, array_json_t, ARRAY_OPLIST(array_json, JSON_OPLIST)),
|
||||
(dict, dict_json_t, DICT_OPLIST(dict_json, STRING_OPLIST, JSON_OPLIST)))
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
order to show/test the good chaining of the structures */
|
||||
|
||||
TUPLE_DEF2(symbol, (type, int), (name, string_t))
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_DEFAULT_OPLIST, STRING_OPLIST)
|
||||
#define M_OPL_symbol_t() TUPLE_OPLIST(symbol, M_BASIC_OPLIST, STRING_OPLIST)
|
||||
|
||||
ARRAY_DEF(symbol_list, symbol_t)
|
||||
#define M_OPL_symbol_list_t() ARRAY_OPLIST(symbol_list, M_OPL_symbol_t())
|
||||
@@ -19,13 +19,13 @@ TUPLE_DEF2(record, (fields, symbol_list_t))
|
||||
#define M_OPL_record_t() TUPLE_OPLIST(record, M_OPL_symbol_list_t())
|
||||
|
||||
TUPLE_DEF2(my_tuple, (name, string_t), (value, int))
|
||||
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple)
|
||||
#define M_OPL_my_tuple_t() TUPLE_OPLIST(my_tuple, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
ARRAY_DEF(my_list_of_tuple, my_tuple_t)
|
||||
#define M_OPL_my_list_of_tuple_t() ARRAY_OPLIST(my_list_of_tuple)
|
||||
|
||||
TUPLE_DEF2(my_tuple_of_tuple, (name, string_t), (inner_tuple, my_tuple_t))
|
||||
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple)
|
||||
#define M_OPL_my_tuple_of_tuple_t() TUPLE_OPLIST(my_tuple_of_tuple, STRING_OPLIST, M_OPL_my_tuple_t() )
|
||||
|
||||
LIST_DEF(list_of_tuple_of_tuple, my_tuple_of_tuple_t)
|
||||
#define M_OPL_list_of_tuple_of_tuple_t() LIST_OPLIST(list_of_tuple_of_tuple, M_OPL_my_tuple_of_tuple_t() )
|
||||
@@ -37,11 +37,11 @@ BUFFER_DEF(trbuff, my_triple_tuple_t, 100, BUFFER_QUEUE)
|
||||
#define M_OPL_trbuff_t() BUFFER_OPLIST(trbuff, M_OPL_my_triple_tuple_t())
|
||||
|
||||
TUPLE_DEF2(my_junction, (active, bool), (buffer, trbuff_t))
|
||||
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_DEFAULT_OPLIST, M_OPL_trbuff_t())
|
||||
#define M_OPL_my_junction_t() TUPLE_OPLIST(my_junction, M_BASIC_OPLIST, M_OPL_trbuff_t())
|
||||
|
||||
TUPLE_DEF2(mlib_point, (x, int), (y, int))
|
||||
#define M_OPL_mlib_point_t() \
|
||||
TUPLE_OPLIST(mlib_point, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
TUPLE_OPLIST(mlib_point, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
TUPLE_DEF2(mlib_points, (first_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
(second_ref, mlib_point_ptr, M_PTR_OPLIST),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -20,6 +20,9 @@ static void main_macrofree(void)
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Finaly rewrite 1 element of the array
|
||||
string_set_str(*str_array_get(tab_name, 1), "BLU-RAY");
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
string_t format;
|
||||
string_init_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
@@ -54,6 +57,9 @@ static void main_macro(void)
|
||||
// Overwrite element 1 of the array.
|
||||
str_array_set_at(tab_name, 1, STRING_CTE("DVD"));
|
||||
|
||||
// Finaly rewrite 1 element of the array
|
||||
string_set_str(*str_array_get(tab_name, 1), "BLU-RAY");
|
||||
|
||||
// Format some strings and push them back in the array
|
||||
M_LET(format, string_t) {
|
||||
string_printf(format, "There are %d elements", str_array_size(tab_name));
|
||||
@@ -67,7 +73,7 @@ static void main_macro(void)
|
||||
// Set format to a formated string
|
||||
// In C11, we can mix string_t and char *.
|
||||
// We can also use M_CSTR to create a printf formated string.
|
||||
string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%d.txt", str_array_size(tab_name) ));
|
||||
string_sets(format, "FILE=", getenv("PWD"), "/", *str_array_get(tab_name, 2), M_CSTR("-%zu.txt", str_array_size(tab_name) ));
|
||||
str_array_push_back(tab_name, format);
|
||||
#endif
|
||||
} // beyond this point format is cleared
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <stdio.h>
|
||||
#include "m-string.h"
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
|
||||
/* Definition of an associative map string_t --> size_t */
|
||||
DICT_DEF2(dict_str, string_t, size_t)
|
||||
#define M_OPL_dict_str_t() DICT_OPLIST(dict_str, STRING_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
/* Definition of an array of string_t */
|
||||
ARRAY_DEF(vector_str, string_t)
|
||||
#define M_OPL_vector_str_t() ARRAY_OPLIST(vector_str, STRING_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Construct an array of string, performing a convertion of the C const char *
|
||||
// into a proper string_t at real time and push then into a dynamic array
|
||||
// that is declared, initialized and cleared.
|
||||
M_LET( (words, ("This"), ("is"), ("a"), ("useless"), ("sentence"), ("."),
|
||||
("It"), ("is"), ("used"), ("a"), ("bit"), ("to"), ("count"), ("words"), (".") ),
|
||||
vector_str_t) {
|
||||
// Print the arrays.
|
||||
printf("The words are: ");
|
||||
vector_str_out_str(stdout, words);
|
||||
printf("\n");
|
||||
|
||||
// Count the words.
|
||||
M_LET(map, dict_str_t) {
|
||||
// Count the words into the dictionnary 'map'
|
||||
for M_EACH(w, words, vector_str_t) {
|
||||
(*dict_str_safe_get(map, *w)) ++;
|
||||
}
|
||||
|
||||
// Print the count:
|
||||
for M_EACH(p, map, dict_str_t) {
|
||||
// In C11 version we can use the M_PRINT macro that simplifies formatting.
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
|
||||
M_PRINT(p->value, " occurences of ", p->key, "\n");
|
||||
#else
|
||||
printf ("%zu occurences of %s\n", p->value, string_get_cstr(p->key));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-10
@@ -5,20 +5,21 @@
|
||||
#include "m-serial-json.h"
|
||||
#include "m-string.h"
|
||||
|
||||
/* Define the employee */
|
||||
/* Define the employee class */
|
||||
TUPLE_DEF2(employee,
|
||||
(name, string_t),
|
||||
(age, int),
|
||||
(idnum, int))
|
||||
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
/* Register globaly the employee_t oplist */
|
||||
#define M_OPL_employee_t() TUPLE_OPLIST(employee, STRING_OPLIST, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
/* Define an array of employee and some algorithms on it */
|
||||
/* Define an array of employee, register the oplist and define further algorithms on it */
|
||||
ARRAY_DEF(vector_employee, employee_t)
|
||||
#define M_OPL_vector_employee_t() ARRAY_OPLIST(vector_employee, M_OPL_employee_t())
|
||||
ALGO_DEF(vector_employee, vector_employee_t)
|
||||
|
||||
/* Define the function object to select the sort order
|
||||
* named 'compare_by' which is an instance of the interface
|
||||
/* Define the function object to select the sort order.
|
||||
* It is named 'compare_by' and is an instance of the interface
|
||||
* 'vector_employee_cmp_obj' created by ALGO_DEF.
|
||||
*/
|
||||
FUNC_OBJ_INS_DEF(compare_by /* name of the instance */,
|
||||
@@ -75,15 +76,12 @@ int main(void)
|
||||
// Sort the database by employee ID number
|
||||
M_LET( (cmp, STRING_CTE("idnum")), compare_by_t )
|
||||
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
|
||||
printf("Employees sorted by idnum are: ");
|
||||
vector_employee_out_str(stdout, emps);
|
||||
M_PRINT("Employees sorted by idnum are: ", (emps, vector_employee_t), "\n" );
|
||||
|
||||
// Sort the database by employee name
|
||||
M_LET( (cmp, STRING_CTE("name")), compare_by_t )
|
||||
vector_employee_sort_fo(emps, compare_by_as_interface(cmp));
|
||||
printf("\nEmployees sorted by name are: ");
|
||||
vector_employee_out_str(stdout, emps);
|
||||
printf("\n");
|
||||
M_PRINT("Employees sorted by name are: ", (emps, vector_employee_t), "\n" );
|
||||
|
||||
// End
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#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"
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* Disable HASH for atomic as the default hash method won't work */
|
||||
#define M_OPL_atomic_uint() M_OPEXTEND(M_BASIC_OPLIST, HASH(0), CMP(API_6(atomic_uint_cmp)))
|
||||
|
||||
/* Define a directory as the number of lines of the files in this directory
|
||||
and the name of the directory
|
||||
(Only sort with the number value by disable the sort compare for the string).
|
||||
*/
|
||||
TUPLE_DEF2( dir, (nlines, atomic_uint), (name, string_t, M_OPEXTEND(STRING_OPLIST, CMP(0))))
|
||||
#define M_OPL_dir_t() TUPLE_OPLIST(dir, M_BASIC_OPLIST, M_STRING_OPLIST)
|
||||
|
||||
/* A hierarchical tree of directory */
|
||||
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
|
||||
|
||||
static tree_it_t
|
||||
add_directory(tree_it_t parent, const string_t dirname)
|
||||
{
|
||||
// TODO: return dir_emplace_child(parent, 0, dirname); to simplify this function.
|
||||
// which is too complex for what she does.
|
||||
dir_t data;
|
||||
tree_it_t it;
|
||||
dir_init_emplace(data, 0, dirname);
|
||||
if (tree_end_p(parent)) {
|
||||
it = tree_set_root( tree_tree(parent), data);
|
||||
} else {
|
||||
it = tree_insert_child(parent, data);
|
||||
}
|
||||
dir_clear(data);
|
||||
return it;
|
||||
}
|
||||
|
||||
/* count the number of end of line character in the buffer */
|
||||
static unsigned
|
||||
count_eol(const char buffer[], size_t num)
|
||||
{
|
||||
unsigned count = 0;
|
||||
for(size_t i = 0; i < num; i++) {
|
||||
count += buffer[i] == '\n';
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_a_c_file(const string_t filename)
|
||||
{
|
||||
return (string_end_with_str_p(filename, ".c")
|
||||
|| string_end_with_str_p(filename, ".h")
|
||||
|| string_end_with_str_p(filename, ".cpp")
|
||||
|| string_end_with_str_p(filename, ".hpp"));
|
||||
}
|
||||
|
||||
static void
|
||||
scan_file(tree_it_t parent, const string_t filename)
|
||||
{
|
||||
if (!is_a_c_file(filename)) return;
|
||||
|
||||
FILE *f = fopen(string_get_cstr(filename), "rt");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a text file.\n", 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(buffer, num);
|
||||
} while (num == MAX_READ_BUFFER);
|
||||
fclose(f);
|
||||
|
||||
/* Adding the number of lines to the parent directory */
|
||||
dir_t *d = tree_ref(parent);
|
||||
atomic_fetch_add( &(*d)->nlines, count );
|
||||
}
|
||||
|
||||
static void
|
||||
scan_directories(tree_it_t parent, const string_t dirname)
|
||||
{
|
||||
tree_it_t it = add_directory(parent, dirname);
|
||||
|
||||
string_t filename;
|
||||
string_init(filename);
|
||||
DIR *dir = opendir(string_get_cstr(dirname));
|
||||
if (dir == NULL) {
|
||||
fprintf(stderr, "ERROR: Cannot open %s as a directory.\n", 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
|
||||
string_sets(filename, dirname, "/", entry->d_name);
|
||||
// Get the property of this filename
|
||||
struct stat buf;
|
||||
int err = stat(string_get_cstr(filename), &buf);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ERROR: Cannot stat %s\n", 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 {
|
||||
scan_file(it, filename);
|
||||
}
|
||||
}
|
||||
// Next entry in the directory
|
||||
entry = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
string_clear(filename);
|
||||
}
|
||||
|
||||
static void
|
||||
consolidate_directories(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the childreen, 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 childreen by the number of lines
|
||||
tree_sort_child(it);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_result(tree_t directories)
|
||||
{
|
||||
// Scan all entries, first the parent, then the childreen
|
||||
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, string_get_cstr( (*d)->name ) );
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
tree_t directories;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
string_init_set_str(str, argv[1]);
|
||||
tree_it_t it = tree_it_end(directories);
|
||||
|
||||
/* Main processing */
|
||||
scan_directories(it, str);
|
||||
consolidate_directories(directories);
|
||||
print_result(directories);
|
||||
|
||||
/* Clear everything & quit */
|
||||
string_clear(str);
|
||||
tree_clear(directories);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// 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;
|
||||
|
||||
string_init(buffer);
|
||||
/* Encode our message */
|
||||
{
|
||||
SimpleMessage_t message;
|
||||
SimpleMessage_init(message);
|
||||
|
||||
/* Create a stream that will write to our 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
|
||||
* 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,241 @@
|
||||
#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 over three kind of numbers named my_number_t
|
||||
Notice than mpz_t/mpfr_t has special init & clear functions.
|
||||
This is handle by the library.
|
||||
*/
|
||||
VARIANT_DEF2(my_number,
|
||||
(n, long long),
|
||||
(z, mpz_t),
|
||||
(fr, mpfr_t) )
|
||||
/* Define the oplist associated to this variant and register it */
|
||||
#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)
|
||||
/* Define the oplist associated to this dictionary and register it */
|
||||
#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)
|
||||
/* Define the oplist associated to this array of dictionary of variant and register it */
|
||||
#define M_OPL_my_array_t() ARRAY_OPLIST(my_array, M_OPL_my_dict_t())
|
||||
|
||||
|
||||
// Show how to define an array of mpz_t & mpfr_t and some algorithms on then
|
||||
// (Not needed for the sequel of this example)
|
||||
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)
|
||||
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'
|
||||
// & clear then once the brackets end.
|
||||
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 results
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
printf ("It is a long long, value = %lld\n",
|
||||
*my_number_cget_n(p->value));
|
||||
}
|
||||
if (my_number_z_p(p->value)) {
|
||||
printf ("It is a mpz_t, value = ");
|
||||
mpz_out_str(stdout, 10, *my_number_cget_z(p->value));
|
||||
printf("\n");
|
||||
}
|
||||
if (my_number_fr_p(p->value)) {
|
||||
printf ("It is a mpfr_t, value = ");
|
||||
mpfr_out_str(stdout, 10, 0, *my_number_cget_fr(p->value), MPFR_RNDN);
|
||||
printf("\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)
|
||||
// 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,106 @@
|
||||
#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)
|
||||
{
|
||||
tree_cstr_t tree;
|
||||
|
||||
tree_cstr_init(tree);
|
||||
|
||||
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");
|
||||
|
||||
printf("\nUsing C string, the generated (sorted) tree is ");
|
||||
tree_cstr_out_str(stdout, tree);
|
||||
printf ("\n");
|
||||
|
||||
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);
|
||||
|
||||
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.
|
||||
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.
|
||||
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"));
|
||||
tree_str_push (tree, STRING_CTE("You"));
|
||||
|
||||
printf("\nUsing M*LIB string_t, the generated (sorted) tree is ");
|
||||
tree_str_out_str(stdout, tree);
|
||||
printf ("\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);
|
||||
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Based on the example of STC https://github.com/tylov/STC */
|
||||
#include "m-dict.h"
|
||||
#include "m-array.h"
|
||||
#include "m-deque.h"
|
||||
#include "m-list.h"
|
||||
#include "m-rbtree.h"
|
||||
#include "m-algo.h"
|
||||
#include "m-tuple.h"
|
||||
|
||||
// NOTE: After each definition of a container, we register its oplist
|
||||
// It is not mandatory, but it makes the code easier to write and read.
|
||||
|
||||
// Define a basic structure (POD structure) using a tuple to get the default functions
|
||||
TUPLE_DEF2(Point, (x, float), (y, float))
|
||||
#define M_OPL_Point_t() TUPLE_OPLIST(Point, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
// NOTE: array, list, deque don't have a native find function.
|
||||
// We'll use the algorithm header to create a find function for such containers.
|
||||
|
||||
// Define a set of int & register its oplist
|
||||
DICT_SET_DEF(cset_i, int)
|
||||
#define M_OPL_cset_i_t() DICT_SET_OPLIST(cset_i, M_BASIC_OPLIST)
|
||||
|
||||
// Define an array of Point, register its oplist & include some basic algorithms
|
||||
ARRAY_DEF(cvec_p, Point_t)
|
||||
#define M_OPL_cvec_p_t() ARRAY_OPLIST(cvec_p, M_OPL_Point_t())
|
||||
ALGO_DEF(cvec_p, cvec_p_t)
|
||||
|
||||
// Define a deque of int, including some basic algorithms
|
||||
DEQUE_DEF(cdeq_i, int)
|
||||
#define M_OPL_cdeq_i_t() DEQUE_OPLIST(cdeq_i, M_BASIC_OPLIST)
|
||||
ALGO_DEF(cdeq_i, cdeq_i_t)
|
||||
|
||||
// Define a backward list, including some basic algorithms
|
||||
LIST_DEF(clist_i, int)
|
||||
#define M_OPL_clist_i_t() LIST_OPLIST(clist_i, M_BASIC_OPLIST)
|
||||
ALGO_DEF(clist_i, clist_i_t)
|
||||
|
||||
// Define an unordered map of int to int
|
||||
DICT_DEF2(csmap_i, int, int)
|
||||
#define M_OPL_csmap_i_t() DICT_OPLIST(csmap_i, M_BASIC_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Define, init & set the different containers.
|
||||
M_LET( (set, 10, 20, 30), cset_i_t)
|
||||
M_LET( (vec, (10, 1), (20, 2), (30, 3) ), cvec_p_t)
|
||||
M_LET( (deq, 10, 20, 30), cdeq_i_t)
|
||||
M_LET( (lst, 10, 20, 30), clist_i_t)
|
||||
M_LET( (map, (20, 2), (10, 1), (30,3) ), csmap_i_t) {
|
||||
|
||||
// add one more element to each container
|
||||
cset_i_push(set, 40);
|
||||
cvec_p_push_back(vec, (Point_t) {{40, 4}} );
|
||||
cdeq_i_push_front(deq, 5);
|
||||
clist_i_push_back(lst, 5);
|
||||
csmap_i_set_at(map, 40, 4);
|
||||
|
||||
M_PRINT("vec= ", (vec, cvec_p_t));
|
||||
|
||||
// Find an element (either native or through the algo header)
|
||||
int *i1 = cset_i_get(set, 20);
|
||||
cvec_p_it_t i2; cvec_p_find(i2, vec, (Point_t) {{20, 2}});
|
||||
cdeq_i_it_t i3; cdeq_i_find(i3, deq, 20);
|
||||
clist_i_it_t i4; clist_i_find(i4, lst, 20);
|
||||
int *i5 = csmap_i_get(map, 20);
|
||||
printf("\nFound: %d, (%g, %g), %d, %d, [%d: %d]\n",
|
||||
*i1,
|
||||
(*cvec_p_ref(i2))->x, (*cvec_p_ref(i2))->y,
|
||||
*cdeq_i_ref(i3),
|
||||
*clist_i_ref(i4),
|
||||
20, *i5);
|
||||
|
||||
// Erase the elements found (through key or through iterators)
|
||||
cset_i_erase(set, *i1);
|
||||
cvec_p_remove(vec, i2);
|
||||
cdeq_i_remove(deq, i3);
|
||||
clist_i_remove(lst, i4);
|
||||
csmap_i_erase(map, *i5);
|
||||
|
||||
// Display everything in one call by using the registered print functions of the different types.
|
||||
M_PRINT("After erasing elements found:\n",
|
||||
"set: ", (set, cset_i_t), "\n",
|
||||
"vec: ", (vec, cvec_p_t), "\n",
|
||||
"deq: ", (deq, cdeq_i_t), "\n",
|
||||
"map: ", (map, csmap_i_t), "\n");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - ALGO module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,143 +28,127 @@
|
||||
#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', as static inline functions.
|
||||
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 \
|
||||
ALGOI_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
M_ALG0_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* 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__) \
|
||||
(ALGOI_FOR_EACH(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__), \
|
||||
ALGOI_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__) \
|
||||
(ALGOI_TRANSFORM(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__), \
|
||||
ALGOI_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__) \
|
||||
(ALGOI_EXTRACT(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(ALGOI_EXTRACT_FUNC(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
ALGOI_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, ...) \
|
||||
M_IF(M_PARENTHESIS_P(dest)) \
|
||||
(ALGOI_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__), \
|
||||
ALGOI_REDUCE_DISPATCH(dest, M_GET_OPLIST M_GLOBAL_OPLIST(contOp), M_GET_SUBTYPE M_GLOBAL_OPLIST(contOp), cont, contOp, __VA_ARGS__)) \
|
||||
|
||||
|
||||
/* Initialize & set a container with a variable array list.
|
||||
USAGE:
|
||||
ALGO_INIT_VA(container, containerOplist, param1[, param2[, ...]]).
|
||||
OBSOLETE: WILL BE DELETED.
|
||||
*/
|
||||
#define ALGO_INIT_VA(dest, contOp, ...) \
|
||||
ALGO_INIT_VAI(dest, M_GLOBAL_OPLIST(contOp), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define, initialize, set & clear a container with a variable array list.
|
||||
USAGE:
|
||||
ALGO_LET_INIT_VA(container, containerOplist|type, param1[, param2[, ...]]) {
|
||||
// Stuff with container
|
||||
}
|
||||
OBSOLETE: WILL BE DELETED.
|
||||
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 ALGO_LET_INIT_VA(dest, contOp, ...) \
|
||||
ALGO_LET_INIT_VAI(dest, M_GLOBAL_OPLIST(contOp), __VA_ARGS__)
|
||||
|
||||
#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__)) \
|
||||
|
||||
|
||||
/* 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) \
|
||||
ALGOI_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(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 ************************************/
|
||||
|
||||
/* Try to expand the algorithms */
|
||||
#define ALGOI_DEF_P1(name, cont_oplist) \
|
||||
ALGOI_DEF_P2(name, M_GET_TYPE cont_oplist, cont_oplist, \
|
||||
#define M_ALG0_DEF_P1(name, cont_oplist) \
|
||||
M_ALG0_DEF_P2(name, M_GET_TYPE cont_oplist, cont_oplist, \
|
||||
M_GET_SUBTYPE cont_oplist, M_GET_OPLIST cont_oplist, \
|
||||
M_GET_IT_TYPE cont_oplist)
|
||||
|
||||
/* First validate the first oplist */
|
||||
#define ALGOI_DEF_P2(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(cont_oplist)(ALGOI_DEF_P3, ALGOI_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
#define M_ALG0_DEF_P2(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(cont_oplist)(M_ALG0_DEF_P3, M_ALG0_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
|
||||
/* Then validate the second oplist */
|
||||
#define ALGOI_DEF_P3(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(type_oplist)(ALGOI_DEF_P4, ALGOI_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
#define M_ALG0_DEF_P3(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_OPLIST(type_oplist)(M_ALG0_DEF_P4, M_ALG0_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure if an oplist was invalid */
|
||||
#define ALGOI_DEF_FAILURE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_FAILURE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ALGO_DEF): one of the given argument is not a valid oplist: " M_AS_STR(cont_oplist) " / " M_AS_STR(type_oplist) )
|
||||
|
||||
|
||||
/* Expand all algorithms */
|
||||
#define ALGOI_DEF_P4(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_DEF_P4(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 10, container_t, cont_oplist) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 11, type_t, type_oplist) \
|
||||
\
|
||||
ALGOI_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_IF_FUNCOBJ(ALGOI_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
|
||||
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_IF_METHOD(EQUAL, type_oplist)( \
|
||||
ALGOI_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
, /* NO EQUAL */) \
|
||||
\
|
||||
ALGOI_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(ALGOI_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_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))) \
|
||||
\
|
||||
ALGOI_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
ALGOI_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(ALGOI_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_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)) ) \
|
||||
\
|
||||
/* If there is a IT_REF method, we consider the container as modifiable through iterator */ \
|
||||
/* If there is a IT_REF method, we consider the container as modifiable through iterator */ \
|
||||
M_IF_METHOD(IT_REF, cont_oplist)( \
|
||||
ALGOI_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
ALGOI_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
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_IF_METHOD(CMP, type_oplist)( \
|
||||
ALGOI_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
ALGOI_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
|
||||
ALGOI_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
|
||||
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_IF_METHOD(IT_REMOVE, cont_oplist)( \
|
||||
ALGOI_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
, /* No IT_REMOVE method */) \
|
||||
, /* No CMP method */) \
|
||||
\
|
||||
M_IF_FUNCOBJ(ALGOI_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, _sort_fo, ALGOI_SORT_CALL_OBJ_P4, ALGOI_SORT_PARAM_OBJ_P4, ALGOI_SORT_ARG_OBJ_P4) ) \
|
||||
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) ) \
|
||||
, /* No IT_REF method */) \
|
||||
\
|
||||
M_IF_METHOD(EXT_ALGO, type_oplist)( \
|
||||
@@ -174,7 +158,7 @@
|
||||
|
||||
/* Define the types of the callbacks associated to the algorithms.
|
||||
* Types remain internal */
|
||||
#define ALGOI_CALLBACK_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_CALLBACK_P5(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); \
|
||||
@@ -185,7 +169,7 @@
|
||||
|
||||
/* Define the function objects associated to the algorithms.
|
||||
* Created Function objects are part of the public interface */
|
||||
#define ALGOI_FUNCOBJ_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_FUNCOBJ_P5(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 ) \
|
||||
@@ -195,7 +179,7 @@
|
||||
|
||||
|
||||
/* Define the sort functions with the CMP operator using the order selected */
|
||||
#define ALGOI_SORT_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
|
||||
#define M_ALG0_SORT_DEF_P5(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) \
|
||||
@@ -203,19 +187,19 @@
|
||||
return order M_CALL_CMP(type_oplist, *a, *b); \
|
||||
} \
|
||||
\
|
||||
ALGOI_SORT_DEF_P6(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, ALGOI_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
|
||||
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*/ )
|
||||
|
||||
// Call the comparaison function of the type oplist (Using CMP operator)
|
||||
#define ALGOI_SORT_CALL_CMP_P4(name, sort_name, ref1, ref2) \
|
||||
#define M_ALG0_SORT_CALL_CMP_P4(name, sort_name, ref1, ref2) \
|
||||
M_C3(name, sort_name,_cmp)(ref1, ref2)
|
||||
|
||||
|
||||
// Call the created function object
|
||||
#define ALGOI_SORT_CALL_OBJ_P4(name, sort_name, ref1, ref2) \
|
||||
#define M_ALG0_SORT_CALL_OBJ_P4(name, sort_name, ref1, ref2) \
|
||||
M_C(name, _cmp_obj_call)(funcobj, *ref1, *ref2)
|
||||
// Adding a parameter named 'funcobj' to the algorithm functions
|
||||
#define ALGOI_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_C(name, _cmp_obj_t) funcobj
|
||||
#define ALGOI_SORT_ARG_OBJ_P4 M_DEFERRED_COMMA funcobj
|
||||
#define M_ALG0_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_C(name, _cmp_obj_t) funcobj
|
||||
#define M_ALG0_SORT_ARG_OBJ_P4 M_DEFERRED_COMMA funcobj
|
||||
|
||||
|
||||
/* Define the sort funtions using either the CMP operator or a function object
|
||||
@@ -231,7 +215,7 @@
|
||||
It is needed to add another argument to the function.
|
||||
- cmp_arg: Name of such argument.
|
||||
*/
|
||||
#define ALGOI_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_SORT_DEF_P6(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 \
|
||||
@@ -246,7 +230,7 @@
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2)) { \
|
||||
type_t const *ref1 = M_CALL_IT_CREF(cont_oplist, it1); \
|
||||
type_t const *ref2 = M_CALL_IT_CREF(cont_oplist, it2); \
|
||||
if (!(cmp_func(name, sort_name, ref1, ref2) <= 0)) { \
|
||||
if (!(cmp_func(name, sort_name, ref1, ref2) <= 0)) { \
|
||||
return false; \
|
||||
} \
|
||||
M_CALL_IT_SET(cont_oplist, it1, it2); \
|
||||
@@ -260,11 +244,11 @@
|
||||
/* - an unstable merge sort (need 'splice_back' method) */ \
|
||||
/* - an insertion sort (need 'previous' method) */ \
|
||||
/* - a selection sort */ \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(SORT, cont_oplist), M_EMPTY_P(cmp_arg)))( \
|
||||
/******** OPTIMIZED SORT FOR CONTAINER *********/ \
|
||||
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_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
|
||||
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
|
||||
} \
|
||||
, \
|
||||
\
|
||||
@@ -279,7 +263,7 @@
|
||||
{ \
|
||||
it_t it; \
|
||||
bool b = false; \
|
||||
/* Split 'l' into 'l1' and 'l2' */ \
|
||||
/* Split 'l' into 'l1' and 'l2' */ \
|
||||
for (M_CALL_IT_FIRST(cont_oplist,it, l); \
|
||||
!M_CALL_IT_END_P(cont_oplist, it);) { \
|
||||
M_CALL_SPLICE_BACK(cont_oplist, (b ? l1 : l2), l, it); \
|
||||
@@ -300,14 +284,14 @@
|
||||
M_CALL_IT_FIRST(cont_oplist,it1, l1); \
|
||||
M_CALL_IT_FIRST(cont_oplist,it2, l2); \
|
||||
while (true) { \
|
||||
/* Compare current elements of the containers l1 and l2 */ \
|
||||
/* Compare current elements of the containers l1 and l2 */ \
|
||||
int c = cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
if (c <= 0) { \
|
||||
/* Move the element of l1 in the new container */ \
|
||||
/* Move the element of l1 in the new container */ \
|
||||
M_CALL_SPLICE_AT(cont_oplist, l, it, l1, it1); \
|
||||
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it1))) { \
|
||||
/* Move all remaining elements of l2 in 'l' */ \
|
||||
/* Move all remaining elements of l2 in 'l' */ \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2)) { \
|
||||
M_CALL_SPLICE_AT(cont_oplist, l, it, l2, it2); \
|
||||
} \
|
||||
@@ -330,7 +314,7 @@
|
||||
\
|
||||
/* Sort the container 'l' */ \
|
||||
static inline void \
|
||||
M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
{ \
|
||||
container_t l1; \
|
||||
container_t l2; \
|
||||
@@ -350,8 +334,8 @@
|
||||
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it))) { \
|
||||
/* Two elements */ \
|
||||
int c = cmp_func(name, sort_name, \
|
||||
M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
if (c > 0) { \
|
||||
/* SWAP */ \
|
||||
M_CALL_SPLICE_BACK(cont_oplist, l, l, it2); \
|
||||
@@ -391,8 +375,8 @@
|
||||
M_CALL_IT_SET(cont_oplist, it2p1, it1); \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2) \
|
||||
&& !(cmp_func(name, sort_name, \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CONST_CAST(type_t, &x)) <= 0)) { \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CONST_CAST(type_t, &x)) <= 0)) { \
|
||||
/* TAB[jp1=j+1] := TAB[j] */ \
|
||||
memcpy(M_CALL_IT_REF(cont_oplist, it2p1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), sizeof (type_t) ); \
|
||||
@@ -422,8 +406,8 @@
|
||||
for(M_CALL_IT_NEXT(cont_oplist, it2) ; \
|
||||
!M_CALL_IT_END_P(cont_oplist, it2); \
|
||||
M_CALL_IT_NEXT(cont_oplist, it2)) { \
|
||||
if (cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CALL_IT_CREF(cont_oplist, it_min)) < 0) { \
|
||||
if (cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CALL_IT_CREF(cont_oplist, it_min)) < 0) { \
|
||||
M_CALL_IT_SET(cont_oplist, it_min, it2); \
|
||||
} \
|
||||
} \
|
||||
@@ -463,23 +447,23 @@
|
||||
if (cmp <= 0) { \
|
||||
/* The element of dst is before. Go to next element of dst */ \
|
||||
M_CALL_IT_SET(cont_oplist, itIns, itDst); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst); \
|
||||
if (cmp == 0) { \
|
||||
/* Skip same arguments in both lists */ \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} else { \
|
||||
/* The element of src is before. */ \
|
||||
/* insert objSrc before */ \
|
||||
/* insert objSrc before */ \
|
||||
/* NOTE: IT_INSERT insert after ==> Need of another iterator */ \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, itSrc)) { \
|
||||
/* Finish inserting the element of src in dst */ \
|
||||
type_t *objSrc = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} \
|
||||
@@ -501,7 +485,7 @@
|
||||
&& !M_CALL_IT_END_P(cont_oplist, itDst)) { \
|
||||
type_t const *objSrc = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
type_t const *objDst = M_CALL_IT_CREF(cont_oplist, itDst); \
|
||||
int cmp = cmp_func(name, sort_name, objDst, objSrc); \
|
||||
int cmp = cmp_func(name, sort_name, objDst, objSrc); \
|
||||
if (cmp == 0) { \
|
||||
/* Keep it */ \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
@@ -523,9 +507,9 @@
|
||||
TODO: Define _find_sorted that find in a sorted random access container
|
||||
(binary search)
|
||||
*/
|
||||
#define ALGOI_FIND_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_FIND_DEF_P5(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 */ \
|
||||
/* Find the next occurrence from it (included) of data */ \
|
||||
static inline void \
|
||||
M_C(name, _find_again) (it_t it, type_t const data) \
|
||||
{ \
|
||||
@@ -536,7 +520,7 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Find the first occurence of data */ \
|
||||
/* Find the first occurrence of data */ \
|
||||
static inline void \
|
||||
M_C(name, _find) (it_t it, container_t const l, type_t const data) \
|
||||
{ \
|
||||
@@ -553,7 +537,7 @@
|
||||
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) \
|
||||
@@ -570,7 +554,7 @@
|
||||
} \
|
||||
} \
|
||||
, \
|
||||
/* Otherwise search forward, but don't stop on the first occurence */ \
|
||||
/* Otherwise search forward, but don't stop on the first occurrence */ \
|
||||
static inline void \
|
||||
M_C(name, _find_last) (it_t it, container_t const l, type_t const data) \
|
||||
{ \
|
||||
@@ -586,7 +570,7 @@
|
||||
} \
|
||||
) /* End of alternative of _find_last */ \
|
||||
\
|
||||
/* Count the number of occurence of data in the container */ \
|
||||
/* Count the number of occurrence of data in the container */ \
|
||||
static inline size_t \
|
||||
M_C(name, _count) (container_t const l, type_t const data) \
|
||||
{ \
|
||||
@@ -631,9 +615,9 @@
|
||||
TODO: Define _find_sorted that find in a sorted random access container
|
||||
(binary search)
|
||||
*/
|
||||
#define ALGOI_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_FIND_IF_DEF_P5(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 */ \
|
||||
/* Find the next occurrence that matches the condition */ \
|
||||
static inline void \
|
||||
M_C3(name, _find_again_, suffix) (it_t it, test_t func) \
|
||||
{ \
|
||||
@@ -644,7 +628,7 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Find the first occurence that matches the condition */ \
|
||||
/* Find the first occurrence that matches the condition */ \
|
||||
static inline void \
|
||||
M_C3(name, _find_, suffix) (it_t it, container_t l, test_t func) \
|
||||
{ \
|
||||
@@ -652,7 +636,7 @@
|
||||
M_C3(name, _find_again_, suffix)(it, func); \
|
||||
} \
|
||||
\
|
||||
/* Count the number of occurence that matches the condition */ \
|
||||
/* Count the number of occurrence that matches the condition */ \
|
||||
static inline size_t \
|
||||
M_C3(name, _count_, suffix) (container_t const l, test_t func) \
|
||||
{ \
|
||||
@@ -677,7 +661,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, it1), \
|
||||
M_CALL_IT_NEXT(cont_oplist, it2)) { \
|
||||
if (!call_eq(func, *M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
*M_CALL_IT_CREF(cont_oplist, it2))) \
|
||||
*M_CALL_IT_CREF(cont_oplist, it2))) \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
@@ -694,7 +678,7 @@
|
||||
|
||||
|
||||
/* Define the FILL algorithms */
|
||||
#define ALGOI_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
/* Fill all the container with value (overwritten) */ \
|
||||
static inline void \
|
||||
@@ -705,12 +689,12 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* 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_CALL_CLEAN(cont_oplist, l); \
|
||||
M_CALL_RESET(cont_oplist, l); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_PUSH(cont_oplist, l, value); \
|
||||
} \
|
||||
@@ -738,7 +722,7 @@
|
||||
{ \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT_SET(type_oplist, tmp, value); \
|
||||
M_CALL_CLEAN(cont_oplist, l); \
|
||||
M_CALL_RESET(cont_oplist, l); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_PUSH(cont_oplist, l, tmp); \
|
||||
M_CALL_ADD(type_oplist, tmp, tmp, inc); \
|
||||
@@ -750,7 +734,7 @@
|
||||
|
||||
|
||||
/* Define MAP algorithms */
|
||||
#define ALGOI_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_MAP_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
/* Apply func for all elements of the container */ \
|
||||
static inline void \
|
||||
@@ -771,7 +755,7 @@
|
||||
M_C(name, _transform_cb_ct) func) \
|
||||
{ \
|
||||
M_ASSERT(dst != src); \
|
||||
M_CALL_CLEAN(cont_oplist, dst); \
|
||||
M_CALL_RESET(cont_oplist, dst); \
|
||||
for M_EACH(item, src, cont_oplist) { \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT(type_oplist, tmp); \
|
||||
@@ -806,7 +790,7 @@
|
||||
void M_C(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_C(name, _transform_cb_ct) mapFunc) \
|
||||
{ \
|
||||
bool initDone = false; \
|
||||
type_t tmp; \
|
||||
@@ -826,7 +810,7 @@
|
||||
|
||||
|
||||
/* Define ALL_OF algorithms */
|
||||
#define ALGOI_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
|
||||
#define M_ALG0_ALL_OF_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
|
||||
\
|
||||
static inline bool \
|
||||
M_C4(name, _any_of, suffix, p) (container_t const l, \
|
||||
@@ -841,7 +825,7 @@
|
||||
\
|
||||
static inline bool \
|
||||
M_C4(name, _all_of, suffix, p) (container_t const l, \
|
||||
func_t func ) \
|
||||
func_t func ) \
|
||||
{ \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
if (!call(func, *item)) \
|
||||
@@ -863,7 +847,7 @@
|
||||
|
||||
|
||||
/* Define MIN / MAX algorithms */
|
||||
#define ALGOI_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_MINMAX_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline type_t * \
|
||||
M_C(name, _min) (const container_t l) \
|
||||
@@ -912,7 +896,7 @@
|
||||
} \
|
||||
|
||||
|
||||
#define ALGOI_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_REMOVE_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _uniq)(container_t l) \
|
||||
@@ -967,7 +951,7 @@
|
||||
} \
|
||||
|
||||
|
||||
#define ALGOI_VECTOR_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
#define M_ALG0_VECTOR_DEF_P5(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) \
|
||||
@@ -981,7 +965,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_ADD(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -999,7 +983,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_SUB(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -1017,7 +1001,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_MUL(type_oplist, *dstItem, *dstItem, *srcItem); \
|
||||
} \
|
||||
} \
|
||||
@@ -1035,7 +1019,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); \
|
||||
} \
|
||||
} \
|
||||
@@ -1051,21 +1035,21 @@
|
||||
// _flatten (takes a set of containers and returns a new container containing all flatten objects)
|
||||
|
||||
|
||||
#define ALGOI_FOR_EACH(container, cont_oplist, func) do { \
|
||||
#define M_ALG0_FOR_EACH(container, cont_oplist, func) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(*_item); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_FOR_EACH_ARG(container, cont_oplist, func, ...) do { \
|
||||
#define M_ALG0_FOR_EACH_ARG(container, cont_oplist, func, ...) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(__VA_ARGS__, *_item); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_TRANSFORM(contD, contDop, contS, contSop, func) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
#define M_ALG0_TRANSFORM(contD, contDop, contS, contSop, func) do { \
|
||||
M_CALL_RESET(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
@@ -1075,8 +1059,8 @@
|
||||
M_IF_METHOD(REVERSE, contDop) (M_CALL_REVERSE(contDop, contD);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_TRANSFORM_ARG(contD, contDop, contS, contSop, func, ...) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
#define M_ALG0_TRANSFORM_ARG(contD, contDop, contS, contSop, func, ...) do { \
|
||||
M_CALL_RESET(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
@@ -1087,9 +1071,10 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_EXTRACT(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
#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)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
@@ -1100,10 +1085,11 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_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_CLEAN(contDstOplist, contDst); \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (*_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
@@ -1116,10 +1102,13 @@
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_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_CLEAN(contDstOplist, contDst); \
|
||||
M_CALL_RESET(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (__VA_ARGS__, *_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
@@ -1133,41 +1122,41 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
|
||||
#define M_ALG0_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
(M_ALG0_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
ALGOI_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, contOp, __VA_ARGS__) ) )
|
||||
(M_ALG0_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
M_ALG0_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, contOp, __VA_ARGS__) ) )
|
||||
|
||||
/* The special functions handled by ALGO_REDUCE */
|
||||
#define ALGOI_REDUCE_AND(a,b) ((a) &= (b))
|
||||
#define ALGOI_REDUCE_OR(a,b) ((a) |= (b))
|
||||
#define ALGOI_REDUCE_SUM(a,b) ((a) += (b))
|
||||
#define ALGOI_REDUCE_PRODUCT(a,b) ((a) *= (b))
|
||||
#define M_ALG0_REDUCE_AND(a,b) ((a) &= (b))
|
||||
#define M_ALG0_REDUCE_OR(a,b) ((a) |= (b))
|
||||
#define M_ALG0_REDUCE_SUM(a,b) ((a) += (b))
|
||||
#define M_ALG0_REDUCE_PRODUCT(a,b) ((a) *= (b))
|
||||
|
||||
/* Return the method associated to a reduce operation.
|
||||
It returns the special function handler if function is and, or, sum or add.
|
||||
Otherwise it returns the original function */
|
||||
#define ALGOI_REDUCE_FUNC(reduceFunc) \
|
||||
#define M_ALG0_REDUCE_FUNC(reduceFunc) \
|
||||
M_IF(M_KEYWORD_P(and, reduceFunc)) \
|
||||
(ALGOI_REDUCE_AND, \
|
||||
(M_ALG0_REDUCE_AND, \
|
||||
M_IF(M_KEYWORD_P(or, reduceFunc)) \
|
||||
(ALGOI_REDUCE_OR, \
|
||||
(M_ALG0_REDUCE_OR, \
|
||||
M_IF(M_KEYWORD_P(sum, reduceFunc)) \
|
||||
(ALGOI_REDUCE_SUM, \
|
||||
(M_ALG0_REDUCE_SUM, \
|
||||
M_IF(M_KEYWORD_P(product, reduceFunc)) \
|
||||
(ALGOI_REDUCE_PRODUCT, \
|
||||
(M_ALG0_REDUCE_PRODUCT, \
|
||||
reduceFunc) \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define ALGOI_REDUCE_BASIC(dest, dest_t, destOp, cont, cont_oplist, reduceFunc) do { \
|
||||
#define M_ALG0_REDUCE_BASIC(dest, dest_t, destOp, cont, cont_oplist, reduceFunc) do { \
|
||||
bool _init_done = false; \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, *_item); \
|
||||
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, *_item); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, *_item); \
|
||||
_init_done = true; \
|
||||
@@ -1175,14 +1164,14 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc) do { \
|
||||
#define M_ALG0_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc) do { \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
@@ -1191,14 +1180,14 @@
|
||||
M_CALL_CLEAR(destOp, _tmp); \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc, ...) do { \
|
||||
#define M_ALG0_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc, ...) do { \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, __VA_ARGS__, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
@@ -1208,26 +1197,7 @@
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_INIT_VA_FUNC(d, a) \
|
||||
M_RET_ARG2 d (M_RET_ARG1 d, a) M_DEFERRED_COMMA
|
||||
|
||||
#define ALGO_INIT_VAI(dest, contOp, ...) \
|
||||
(void)(M_CALL_INIT(contOp, dest) M_DEFERRED_COMMA \
|
||||
M_MAP2(ALGOI_INIT_VA_FUNC, (dest, M_GET_PUSH contOp, ) , __VA_ARGS__) \
|
||||
true)
|
||||
|
||||
|
||||
#define ALGO_LET_INIT_VAI(dest, ...) \
|
||||
ALGOI_LET_INIT_VAI(M_C3(m_cont_, __LINE__, dest), dest, __VA_ARGS__)
|
||||
|
||||
#define ALGOI_LET_INIT_VAI(cont, dest, contOp, ...) \
|
||||
for(bool cont = true; cont ; /* unused */) \
|
||||
for(M_GET_TYPE contOp dest; \
|
||||
cont && (ALGO_INIT_VAI (dest, contOp, __VA_ARGS__), true); \
|
||||
(M_CALL_CLEAR(contOp, dest), cont = false))
|
||||
|
||||
|
||||
#define ALGOI_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) do { \
|
||||
#define M_ALG0_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) do { \
|
||||
M_GET_IT_TYPE contSrcOp _itSrc; \
|
||||
M_GET_IT_TYPE contDstOp _itDst; \
|
||||
M_CALL_IT_SET(contDstOp, _itDst, position); \
|
||||
@@ -1239,4 +1209,14 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#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 - dynamic ARRAY module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,34 +29,36 @@
|
||||
|
||||
/* Define a dynamic array of the given type and its associated functions.
|
||||
USAGE: ARRAY_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define ARRAY_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ARRAYI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_ARRAY_DEF(name, ...) \
|
||||
M_ARRAY_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a dynamic array of the given type and its associated functions
|
||||
as the provided type name_t with the iterator named it_t
|
||||
USAGE: ARRAY_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define ARRAY_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_ARRAY_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ARRAYI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_ARRA4_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a dynamic array given its name and its oplist.
|
||||
If no oplist is given it is assumed to be M_DEFAULT_OPLIST
|
||||
If no oplist is given it is assumed to be M_BASIC_OPLIST
|
||||
USAGE: ARRAY_OPLIST(name[, oplist of the type]) */
|
||||
#define ARRAY_OPLIST(...) \
|
||||
ARRAYI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define M_ARRAY_OPLIST(...) \
|
||||
M_ARRA4_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define an init value to init global variables of type array.
|
||||
USAGE:
|
||||
array_t global_variable = ARRAY_INIT_VALUE();
|
||||
*/
|
||||
#define M_ARRAY_INIT_VALUE() \
|
||||
{ { 0, 0, NULL } }
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************** INTERNAL ************************************/
|
||||
@@ -64,29 +66,30 @@
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define ARRAYI_OPLIST_P1(arg) ARRAYI_OPLIST_P2 arg
|
||||
#define M_ARRA4_OPLIST_P1(arg) M_ARRA4_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ARRAYI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ARRAYI_OPLIST_P3, ARRAYI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_ARRA4_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_ARRA4_OPLIST_P3, M_ARRA4_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ARRAYI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_ARRA4_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_ARRAY_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* OPLIST definition of a dynamic array */
|
||||
/* FIXME: Do we want to export some methods as they are slow and
|
||||
are not fit to be used for building other methods (like _it_remove)? */
|
||||
#define ARRAYI_OPLIST_P3(name, oplist) \
|
||||
#define M_ARRA4_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(M_C(name, _init_set)),) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(INIT_WITH(API_1(M_INIT_VAI)),) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(INIT_WITH(API_1(M_INIT_WITH_VAI)),) \
|
||||
,M_IF_METHOD2(INIT_SET,SET, oplist)(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)) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,NAME(name) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,EMPTY_P(M_C(name,_empty_p)) \
|
||||
,IT_TYPE(M_C(name,_it_ct)), \
|
||||
@@ -103,14 +106,14 @@
|
||||
,IT_CREF(M_C(name,_cref)) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(IT_INSERT(M_C(name,_insert)) ,) \
|
||||
,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(IT_REMOVE(M_C(name,_remove)),) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,KEY_TYPE(size_t) \
|
||||
,VALUE_TYPE(M_C(name, _subtype_ct)) \
|
||||
,KEY_OPLIST(M_DEFAULT_OPLIST) \
|
||||
,KEY_OPLIST(M_BASIC_OPLIST) \
|
||||
,VALUE_OPLIST(oplist) \
|
||||
,M_IF_METHOD(SET, oplist)(SET_KEY(M_C(name, _set_at)) ,) \
|
||||
,GET_KEY(M_C(name, _get)) \
|
||||
,M_IF_METHOD(INIT, oplist)(GET_SET_KEY(M_C(name, _get_at)) ,) \
|
||||
,M_IF_METHOD(INIT, oplist)(SAFE_GET_KEY(M_C(name, _safe_get)) ,) \
|
||||
,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(ERASE_KEY(M_C(name, _erase)),) \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(PUSH(M_C(name,_push_back)) ,) \
|
||||
@@ -133,22 +136,27 @@
|
||||
)
|
||||
|
||||
/* Define the internal contract of an array */
|
||||
#define ARRAYI_CONTRACT(a) do { \
|
||||
#define M_ARRA4_CONTRACT(a) do { \
|
||||
M_ASSERT (a != NULL); \
|
||||
M_ASSERT (a->size <= a->alloc); \
|
||||
M_ASSERT (a->size == 0 || a->ptr != NULL); \
|
||||
M_ASSERT (a->alloc == 0 || a->ptr != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Deferred evaluation for the array definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define ARRAYI_DEF_P1(arg) ARRAYI_DEF_P2 arg
|
||||
so that all arguments are fully evaluated before further expansion
|
||||
(ensuring good performance)
|
||||
and performed a final step evaluation of the returning expansion
|
||||
(ensuring delayed evaluation are still expanded)
|
||||
*/
|
||||
#define M_ARRA4_DEF_P1(arg) M_ID( M_ARRA4_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define ARRAYI_DEF_P2(name, type, oplist, array_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(ARRAYI_DEF_P3, ARRAYI_DEF_FAILURE)(name, type, oplist, array_t, it_t)
|
||||
#define M_ARRA4_DEF_P2(name, type, oplist, array_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_ARRA4_DEF_P3, M_ARRA4_DEF_FAILURE)(name, type, oplist, array_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ARRAYI_DEF_FAILURE(name, type, oplist, array_t, it_t) \
|
||||
#define M_ARRA4_DEF_FAILURE(name, type, oplist, array_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ARRAY_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Internal definition:
|
||||
@@ -158,7 +166,7 @@
|
||||
- array_t: alias for the type of the array
|
||||
- it_t: alias for the iterator of the array
|
||||
*/
|
||||
#define ARRAYI_DEF_P3(name, type, oplist, array_t, it_t) \
|
||||
#define M_ARRA4_DEF_P3(name, type, oplist, array_t, it_t) \
|
||||
\
|
||||
/* Define a dynamic array */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
@@ -190,26 +198,27 @@
|
||||
v->size = 0; \
|
||||
v->alloc = 0; \
|
||||
v->ptr = NULL; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(array_t v) \
|
||||
M_C(name, _reset)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
for(size_t i = 0; i < v->size; i++) \
|
||||
M_CALL_CLEAR(oplist, v->ptr[i]); \
|
||||
v->size = 0; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_C(name, _clean)(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_C(name, _reset)(v); \
|
||||
M_CALL_FREE(oplist, v->ptr); \
|
||||
v->alloc = 0; \
|
||||
/* This is so reusing the object implies an assertion failure */ \
|
||||
v->alloc = 1; \
|
||||
v->ptr = NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -217,8 +226,8 @@
|
||||
static inline void \
|
||||
M_C(name, _set)(array_t d, const array_t s) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(d); \
|
||||
ARRAYI_CONTRACT(s); \
|
||||
M_ARRA4_CONTRACT(d); \
|
||||
M_ARRA4_CONTRACT(s); \
|
||||
if (M_UNLIKELY (d == s)) return; \
|
||||
if (s->size > d->alloc) { \
|
||||
const size_t alloc = s->size; \
|
||||
@@ -239,7 +248,7 @@
|
||||
for( ; i < d->size; i++) \
|
||||
M_CALL_CLEAR(oplist, d->ptr[i]); \
|
||||
d->size = s->size; \
|
||||
ARRAYI_CONTRACT(d); \
|
||||
M_ARRA4_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -255,13 +264,14 @@
|
||||
M_C(name, _init_move)(array_t d, array_t s) \
|
||||
{ \
|
||||
M_ASSERT (d != s); \
|
||||
ARRAYI_CONTRACT(s); \
|
||||
M_ARRA4_CONTRACT(s); \
|
||||
d->size = s->size; \
|
||||
d->alloc = s->alloc; \
|
||||
d->ptr = s->ptr; \
|
||||
s->alloc = 0; \
|
||||
/* Robustness */ \
|
||||
s->alloc = 1; \
|
||||
s->ptr = NULL; \
|
||||
ARRAYI_CONTRACT(d); \
|
||||
M_ARRA4_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -276,26 +286,26 @@
|
||||
static inline void \
|
||||
M_C(name, _set_at)(array_t v, size_t i, type const x) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(v->size > 0 && v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
M_CALL_SET(oplist, v->ptr[i], x); \
|
||||
} \
|
||||
, /* No SET */) \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _back)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
return M_CONST_CAST(type, &v->ptr[v->size-1]); \
|
||||
return &v->ptr[v->size-1]; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
if (M_UNLIKELY (v->size >= v->alloc)) { \
|
||||
M_ASSERT(v->size == v->alloc); \
|
||||
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
|
||||
@@ -315,7 +325,7 @@
|
||||
M_ASSERT(v->ptr != NULL); \
|
||||
type *ret = &v->ptr[v->size]; \
|
||||
v->size++; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSUME(ret != NULL); \
|
||||
return ret; \
|
||||
} \
|
||||
@@ -359,7 +369,7 @@
|
||||
static inline void \
|
||||
M_C(name, _push_at)(array_t v, size_t key, type const x) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT_INDEX(key, v->size+1); \
|
||||
if (M_UNLIKELY (v->size >= v->alloc) ) { \
|
||||
M_ASSERT(v->size == v->alloc); \
|
||||
@@ -381,7 +391,7 @@
|
||||
memmove(&v->ptr[key+1], &v->ptr[key], (v->size-key)*sizeof(type)); \
|
||||
v->size++; \
|
||||
M_CALL_INIT_SET(oplist, v->ptr[key], x); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* No INIT_SET */ ) \
|
||||
\
|
||||
@@ -389,7 +399,7 @@
|
||||
static inline void \
|
||||
M_C(name, _resize)(array_t v, size_t size) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
if (v->size > size) { \
|
||||
/* Decrease size of array */ \
|
||||
for(size_t i = size ; i < v->size; i++) \
|
||||
@@ -411,14 +421,14 @@
|
||||
M_CALL_INIT(oplist, v->ptr[i]); \
|
||||
v->size = size; \
|
||||
} \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* No INIT */ ) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reserve)(array_t v, size_t alloc) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
/* NOTE: Reserve below needed size to perform a shrink to fit */ \
|
||||
if (v->size > alloc) { \
|
||||
alloc = v->size; \
|
||||
@@ -436,14 +446,14 @@
|
||||
v->ptr = ptr; \
|
||||
v->alloc = alloc; \
|
||||
} \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
static inline type * \
|
||||
M_C(name, _get_at)(array_t v, size_t idx) \
|
||||
M_C(name, _safe_get)(array_t v, size_t idx) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
const size_t size = idx + 1; \
|
||||
/* resize if needed */ \
|
||||
if (v->size <= size) { \
|
||||
@@ -468,7 +478,7 @@
|
||||
v->size = size; \
|
||||
} \
|
||||
M_ASSERT (idx < v->size); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return &v->ptr[idx]; \
|
||||
} \
|
||||
, /* No INIT */) \
|
||||
@@ -477,7 +487,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *dest, array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
v->size--; \
|
||||
@@ -486,7 +496,7 @@
|
||||
} else { \
|
||||
M_CALL_CLEAR(oplist, v->ptr[v->size]); \
|
||||
} \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* SET | INIT_MOVE */ ) \
|
||||
\
|
||||
@@ -494,13 +504,13 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(type *dest, array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
M_ASSERT (dest != NULL); \
|
||||
v->size--; \
|
||||
M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* INIT_SET | INIT_MOVE */ ) \
|
||||
\
|
||||
@@ -508,7 +518,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_until)(array_t v, it_t pos) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v == pos->array); \
|
||||
M_ASSERT_INDEX(pos->index, v->size+1); \
|
||||
M_C(name, _resize)(v, pos->index); \
|
||||
@@ -518,21 +528,21 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return v->size == 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return v->size; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _capacity)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
return v->alloc; \
|
||||
} \
|
||||
\
|
||||
@@ -540,22 +550,22 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_at)(type *dest, array_t v, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->size > 0 && v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
if (dest) \
|
||||
M_DO_MOVE (oplist, *dest, v->ptr[i]); \
|
||||
else \
|
||||
M_CALL_CLEAR(oplist, v->ptr[i]); \
|
||||
memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size - i) ); \
|
||||
memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size-1-i)); \
|
||||
v->size--; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _erase)(array_t a, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(a); \
|
||||
M_ARRA4_CONTRACT(a); \
|
||||
if (i >= a->size) return false; \
|
||||
M_C(name, _pop_at)(NULL, a, i); \
|
||||
return true; \
|
||||
@@ -566,7 +576,7 @@
|
||||
static inline void \
|
||||
M_C(name, _insert_v)(array_t v, size_t i, size_t num) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT_INDEX(i, v->size+1); \
|
||||
size_t size = v->size + num; \
|
||||
/* Test for overflow of variable size */ \
|
||||
@@ -595,14 +605,14 @@
|
||||
for(size_t k = i ; k < i+num; k++) \
|
||||
M_CALL_INIT(oplist, v->ptr[k]); \
|
||||
v->size = size; \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* No INIT */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove_v)(array_t v, size_t i, size_t j) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(i < j && v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
M_ASSERT_INDEX(j, v->size+1); \
|
||||
@@ -610,32 +620,26 @@
|
||||
M_CALL_CLEAR(oplist, v->ptr[k]); \
|
||||
memmove(&v->ptr[i], &v->ptr[j], sizeof(type)*(v->size - j) ); \
|
||||
v->size -= (j-i); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(array_t v1, array_t v2) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v1); \
|
||||
ARRAYI_CONTRACT(v2); \
|
||||
size_t tmp = v1->size; \
|
||||
v1->size = v2->size; \
|
||||
v2->size = tmp; \
|
||||
tmp = v1->alloc; \
|
||||
v1->alloc = v2->alloc; \
|
||||
v2->alloc = tmp; \
|
||||
type *p = v1->ptr; \
|
||||
v1->ptr = v2->ptr; \
|
||||
v2->ptr = p; \
|
||||
ARRAYI_CONTRACT(v1); \
|
||||
ARRAYI_CONTRACT(v2); \
|
||||
M_ARRA4_CONTRACT(v1); \
|
||||
M_ARRA4_CONTRACT(v2); \
|
||||
M_SWAP(size_t, v1->size, v2->size); \
|
||||
M_SWAP(size_t, v1->alloc, v2->alloc); \
|
||||
M_SWAP(type *, v1->ptr, v2->ptr); \
|
||||
M_ARRA4_CONTRACT(v1); \
|
||||
M_ARRA4_CONTRACT(v2); \
|
||||
} \
|
||||
\
|
||||
M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist) ( \
|
||||
static inline void \
|
||||
M_C(name, _swap_at)(array_t v, size_t i, size_t j) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT(v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
M_ASSERT_INDEX(j, v->size); \
|
||||
@@ -643,14 +647,14 @@
|
||||
M_DO_INIT_MOVE(oplist, tmp, v->ptr[i]); \
|
||||
M_DO_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \
|
||||
M_DO_INIT_MOVE(oplist, v->ptr[j], tmp); \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
} \
|
||||
, /* INIT_SET | INIT_MOVE */ ) \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get)(const array_t v, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
return &v->ptr[i]; \
|
||||
@@ -659,24 +663,24 @@
|
||||
static inline type const * \
|
||||
M_C(name, _cget)(const array_t v, size_t i) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (v->ptr != NULL); \
|
||||
M_ASSERT_INDEX(i, v->size); \
|
||||
return M_CONST_CAST(type, &v->ptr[i]); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _front)(const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT_INDEX(0, v->size); \
|
||||
return M_C(name, _cget)(v, 0); \
|
||||
return M_C(name, _get)(v, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->index = 0; \
|
||||
it->array = v; \
|
||||
@@ -685,7 +689,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
/* If size is 0, index is -1 as unsigned, so it is greater than end */ \
|
||||
it->index = v->size - 1; \
|
||||
@@ -695,7 +699,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const array_t v) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(v); \
|
||||
M_ARRA4_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->index = v->size; \
|
||||
it->array = v; \
|
||||
@@ -707,7 +711,7 @@
|
||||
M_ASSERT (it != NULL && org != NULL); \
|
||||
it->index = org->index; \
|
||||
it->array = org->array; \
|
||||
ARRAYI_CONTRACT(it->array); \
|
||||
M_ARRA4_CONTRACT(it->array); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
@@ -769,8 +773,9 @@
|
||||
M_C(name, _insert)(array_t a, it_t it, type const x) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && a == it->array); \
|
||||
M_C(name, _push_at)(a, it->index + 1, x); \
|
||||
it->index ++; \
|
||||
size_t index = M_C(name, _end_p)(it) ? 0 : it->index+1; \
|
||||
M_C(name, _push_at)(a, index, x); \
|
||||
it->index = index; \
|
||||
} \
|
||||
, /* End of INIT_SET */ ) \
|
||||
\
|
||||
@@ -799,7 +804,7 @@
|
||||
\
|
||||
M_IF_METHOD2(SWAP, SET, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _special_stable_sort_noalloc) (type tab[], size_t size, type tmp[]) \
|
||||
M_C3(m_arra4_,name,_stable_sort_noalloc)(type tab[], size_t size, type tmp[]) \
|
||||
{ \
|
||||
size_t th = 4; \
|
||||
M_IF_DEBUG(type *org_tab = tab;) \
|
||||
@@ -809,10 +814,9 @@
|
||||
if (m_core_clz64(size-1) & 1) \
|
||||
th += th; \
|
||||
\
|
||||
/* Pass 1: insertion sort (stable) */ \
|
||||
/* Pass 1: Partial insertion sort (stable) up to 'th' size */ \
|
||||
for(size_t k = 0 ; k < size; ) { \
|
||||
size_t max = size - k < 2*th ? size - k : th; \
|
||||
M_ASSUME(max >= th); \
|
||||
for(size_t i = 1; i < max; i++) { \
|
||||
size_t j = i; \
|
||||
while (j > 0 && M_CALL_CMP(oplist, tab[k+j-1], tab[k+j]) > 0) { \
|
||||
@@ -826,7 +830,7 @@
|
||||
/* N Pass of merge sort (stable) */ \
|
||||
while (th < size) { \
|
||||
type *dest = tmp; \
|
||||
/* Pass n: Merge */ \
|
||||
/* Pass n: Merge 2 sections of 'th' elements */ \
|
||||
for(size_t k = 0 ; k < size; ) { \
|
||||
type *el1 = &tab[k]; \
|
||||
type *el2 = &tab[k+th]; \
|
||||
@@ -838,10 +842,10 @@
|
||||
k += n1+n2; \
|
||||
for (;;) { \
|
||||
if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \
|
||||
M_CALL_SET(oplist, *dest, *el1); \
|
||||
M_DO_INIT_MOVE(oplist, *dest, *el1); \
|
||||
dest++; \
|
||||
el1++; \
|
||||
if (-- n1 == 0) { \
|
||||
if (M_UNLIKELY(-- n1 == 0)) { \
|
||||
if (n2 > 0) { \
|
||||
memcpy (dest, el2, n2 * sizeof (type)); \
|
||||
dest += n2; \
|
||||
@@ -849,10 +853,10 @@
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
M_CALL_SET(oplist, *dest, *el2); \
|
||||
M_DO_INIT_MOVE(oplist, *dest, *el2); \
|
||||
dest++; \
|
||||
el2++; \
|
||||
if (-- n2 == 0) { \
|
||||
if (M_UNLIKELY(-- n2 == 0)) { \
|
||||
if (n1 > 0) { \
|
||||
memcpy (dest, el1, n1 * sizeof (type)); \
|
||||
dest += n1; \
|
||||
@@ -881,7 +885,7 @@
|
||||
M_MEMORY_FULL(sizeof (type) * l->size); \
|
||||
return ; \
|
||||
} \
|
||||
M_C(name, _special_stable_sort_noalloc)(l->ptr, l->size, temp); \
|
||||
M_C3(m_arra4_,name,_stable_sort_noalloc)(l->ptr, l->size, temp); \
|
||||
M_CALL_FREE(oplist, temp); \
|
||||
} \
|
||||
,) /* IF SWAP & SET methods */ \
|
||||
@@ -891,12 +895,11 @@
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, array_t const array, \
|
||||
M_C(name, _get_str)(m_string_t str, array_t const array, \
|
||||
bool append) \
|
||||
{ \
|
||||
STRINGI_CONTRACT(str); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, array) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
@@ -904,10 +907,9 @@
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_GET_STR(oplist, str, *item, true); \
|
||||
if (!M_C(name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -915,7 +917,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, const array_t array) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
for (size_t i = 0; i < array->size; i++) { \
|
||||
@@ -932,9 +934,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(array_t array, const char str[], const char**endp) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_C(name,_clean)(array); \
|
||||
M_C(name,_reset)(array); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -950,7 +952,7 @@
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_C(name, _push_back)(array, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
@@ -964,9 +966,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(array_t array, FILE *file) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (file != NULL); \
|
||||
M_C(name,_clean)(array); \
|
||||
M_C(name,_reset)(array); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -982,7 +984,7 @@
|
||||
M_C(name, _push_back)(array, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no IN_STR & INIT */ ) \
|
||||
@@ -991,7 +993,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, const array_t array) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
@@ -1012,12 +1014,12 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(array_t array, m_serial_read_t f) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
size_t estimated_size = 0; \
|
||||
M_C(name,_clean)(array); \
|
||||
M_C(name,_reset)(array); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) { \
|
||||
return ret; \
|
||||
@@ -1035,7 +1037,7 @@
|
||||
ret = f->m_interface->read_array_next(local, f); \
|
||||
} while (ret == M_SERIAL_OK_CONTINUE); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
return ret; \
|
||||
} \
|
||||
, /* no IN_SERIAL & INIT */ ) \
|
||||
@@ -1045,8 +1047,8 @@
|
||||
M_C(name, _equal_p)(const array_t array1, \
|
||||
const array_t array2) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array1); \
|
||||
ARRAYI_CONTRACT(array2); \
|
||||
M_ARRA4_CONTRACT(array1); \
|
||||
M_ARRA4_CONTRACT(array2); \
|
||||
if (array1->size != array2->size) return false; \
|
||||
size_t i; \
|
||||
for(i = 0; i < array1->size; i++) { \
|
||||
@@ -1063,7 +1065,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _hash)(const array_t array) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(array); \
|
||||
M_ARRA4_CONTRACT(array); \
|
||||
M_HASH_DECL(hash); \
|
||||
for(size_t i = 0 ; i < array->size; i++) { \
|
||||
size_t hi = M_CALL_HASH(oplist, array->ptr[i]); \
|
||||
@@ -1076,8 +1078,8 @@
|
||||
static inline void \
|
||||
M_C(name, _splice)(array_t a1, array_t a2) \
|
||||
{ \
|
||||
ARRAYI_CONTRACT(a1); \
|
||||
ARRAYI_CONTRACT(a2); \
|
||||
M_ARRA4_CONTRACT(a1); \
|
||||
M_ARRA4_CONTRACT(a2); \
|
||||
if (M_LIKELY (a2->size > 0)) { \
|
||||
size_t newSize = a1->size + a2->size; \
|
||||
if (newSize > a1->alloc) { \
|
||||
@@ -1095,5 +1097,26 @@
|
||||
a1->size = newSize; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, array_t, M_C(name, _emplace_back), oplist, M_ARRA4_EMPLACE_DEF)
|
||||
|
||||
/* Definition of the emplace_back function for arrays */
|
||||
#define M_ARRA4_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
} \
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define ARRAY_DEF M_ARRAY_DEF
|
||||
#define ARRAY_DEF_AS M_ARRAY_DEF_AS
|
||||
#define ARRAY_OPLIST M_ARRAY_OPLIST
|
||||
#define ARRAY_INIT_VALUE M_ARRAY_INIT_VALUE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Thin stdatomic wrapper for C++ compatibility
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
|
||||
+441
-296
File diff suppressed because it is too large.
Load diff
+162
-144
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - B+TREE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,12 +34,8 @@
|
||||
OR
|
||||
BPTREE_DEF2(name, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_DEF2(name, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_BPTREE_DEF2(name, N, key_type, ...) \
|
||||
M_BPTREE_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name, _itref_t), N, key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of size 'N' that maps a 'key' to a 'value'
|
||||
@@ -49,9 +45,9 @@
|
||||
OR
|
||||
BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
#define M_BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -60,20 +56,16 @@
|
||||
/* Define a B+tree of a given type, of size N.
|
||||
with its associated functions
|
||||
USAGE: BPTREE_DEF(name, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_DEF(name, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_BPTREE_DEF(name, N, ...) \
|
||||
M_BPTREE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of a given type, of size N.
|
||||
as the given name name_t with its associated functions
|
||||
USAGE: BPTREE_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
#define M_BPTREE_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -87,12 +79,8 @@
|
||||
OR
|
||||
BPTREE_MULTI_DEF2(name, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_MULTI_DEF2(name, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_BPTREE_MULTI_DEF2(name, N, key_type, ...) \
|
||||
M_BPTREE_MULTI_DEF2_AS(name, M_C(name,_t), M_C(name,_it_t), M_C(name,_itref_t), N, key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of size 'N' that maps a 'key' to a 'value',
|
||||
@@ -103,9 +91,9 @@
|
||||
OR
|
||||
BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t)
|
||||
*/
|
||||
#define BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
#define M_BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \
|
||||
(name, N, key_type, __VA_ARGS__, 1, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -115,42 +103,39 @@
|
||||
allowing multiple equal keys to exist,
|
||||
with its associated functions
|
||||
USAGE: BPTREE_MULTI_DEF(name, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_MULTI_DEF(name, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
#define M_BPTREE_MULTI_DEF(name, N, ...) \
|
||||
M_BPTREE_MULTI_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), N, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a B+tree of a given type, of size N.
|
||||
allowing multiple equal keys to exist,
|
||||
as the given name name_t with its associated functions
|
||||
USAGE: BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */
|
||||
#define BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
#define M_BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_BPTR33_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \
|
||||
(name, N, __VA_ARGS__, __VA_ARGS__, 0, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ))) \
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a B+TREE used as a set of type (from BPTREE_DEF).
|
||||
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define BPTREE_OPLIST(...) \
|
||||
BPTREEI_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
USAGE: BPTREE_OPLIST(name [, oplist_of_the_type])
|
||||
NOTE: IT_REF is not exported so that the container appears as not modifiable
|
||||
by algorithm. */
|
||||
#define M_BPTREE_OPLIST(...) \
|
||||
M_BPTR33_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define the oplist of a B+TREE used as a map of a key type to a value type (from BPTREE_DEF2).
|
||||
USAGE: BPTREE_OPLIST2(name[, key_oplist, value_oplist])
|
||||
NOTE: IT_REF is not exported so that the contained appears as not modifiable
|
||||
by algorithm.
|
||||
*/
|
||||
#define BPTREE_OPLIST2(...) \
|
||||
BPTREEI_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \
|
||||
NOTE: IT_REF is not exported so that the container appears as not modifiable
|
||||
by algorithm. */
|
||||
#define M_BPTREE_OPLIST2(...) \
|
||||
M_BPTR33_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -159,18 +144,18 @@
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BPTREEI_KEY_OPLIST_P1(arg) BPTREEI_KEY_OPLIST_P2 arg
|
||||
#define M_BPTR33_KEY_OPLIST_P1(arg) M_BPTR33_KEY_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplists */
|
||||
#define BPTREEI_KEY_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(BPTREEI_KEY_OPLIST_P3, BPTREEI_KEY_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_BPTR33_KEY_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_BPTR33_KEY_OPLIST_P3, M_BPTR33_KEY_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define BPTREEI_KEY_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_BPTR33_KEY_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* OPLIST definition of a b+tree */
|
||||
#define BPTREEI_KEY_OPLIST_P3(name, oplist) \
|
||||
/* OPLIST definition of a b+tree (global tree) */
|
||||
#define M_BPTR33_KEY_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
@@ -179,6 +164,7 @@
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)), \
|
||||
IT_TYPE(M_C(name, _it_ct)), \
|
||||
@@ -188,9 +174,8 @@
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_REF(M_C(name,_ref)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
PUSH(M_C(name,_push)), \
|
||||
GET_MIN(M_C(name,_min)), \
|
||||
GET_MAX(M_C(name,_max)), \
|
||||
@@ -208,20 +193,20 @@
|
||||
)
|
||||
|
||||
/* Deferred evaluation */
|
||||
#define BPTREEI_OPLIST2_P1(arg) BPTREEI_OPLIST2_P2 arg
|
||||
#define M_BPTR33_OPLIST2_P1(arg) M_BPTR33_OPLIST2_P2 arg
|
||||
|
||||
/* Validation of the given oplists (first the key oplist, then the value oplist) */
|
||||
#define BPTREEI_OPLIST2_P2(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(BPTREEI_OPLIST2_P3, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
#define BPTREEI_OPLIST2_P3(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(BPTREEI_OPLIST2_P4, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
#define M_BPTR33_OPLIST2_P2(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(key_oplist)(M_BPTR33_OPLIST2_P3, M_BPTR33_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
#define M_BPTR33_OPLIST2_P3(name, key_oplist, value_oplist) \
|
||||
M_IF_OPLIST(value_oplist)(M_BPTR33_OPLIST2_P4, M_BPTR33_OPLIST2_FAILURE)(name, key_oplist, value_oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define BPTREEI_OPLIST2_FAILURE(name, key_oplist, value_oplist) \
|
||||
#define M_BPTR33_OPLIST2_FAILURE(name, key_oplist, value_oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)))
|
||||
|
||||
/* Final definition of the oplist */
|
||||
#define BPTREEI_OPLIST2_P4(name, key_oplist, value_oplist) \
|
||||
/* Final definition of the oplist (associative array) */
|
||||
#define M_BPTR33_OPLIST2_P4(name, key_oplist, value_oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_KEY_VAI)), \
|
||||
@@ -230,6 +215,7 @@
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
@@ -241,17 +227,17 @@
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
GET_MIN(M_C(name,_min)), \
|
||||
GET_MAX(M_C(name,_max)), \
|
||||
KEY_TYPE(M_C(name, _key_ct)), \
|
||||
VALUE_TYPE(M_C(name, _value_ct)), \
|
||||
SET_KEY(M_C(name, _set_at)), \
|
||||
GET_KEY(M_C(name, _get)), \
|
||||
SAFE_GET_KEY(M_C(name, _safe_get)) \
|
||||
ERASE_KEY(M_C(name, _erase)), \
|
||||
KEY_OPLIST(key_oplist), \
|
||||
VALUE_OPLIST(value_oplist), \
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),), \
|
||||
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),), \
|
||||
M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),), \
|
||||
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(M_C(name, _in_str)),), \
|
||||
@@ -268,9 +254,9 @@
|
||||
|
||||
/* Internal contract of a B+TREE of size 'N' for a node 'node' or root 'root' */
|
||||
#ifdef NDEBUG
|
||||
# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { } while (0)
|
||||
# define M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { } while (0)
|
||||
#else
|
||||
# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { \
|
||||
# define M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { \
|
||||
M_ASSERT ((node) != NULL); \
|
||||
M_ASSERT ((root) != NULL); \
|
||||
int num2 = (node)->num; \
|
||||
@@ -299,9 +285,9 @@
|
||||
#endif
|
||||
|
||||
/* Contract for a B+TREE of size N named 'b' */
|
||||
#define BPTREEI_CONTRACT(N, isMulti, key_oplist, b) do { \
|
||||
#define M_BPTR33_CONTRACT(N, isMulti, key_oplist, b) do { \
|
||||
M_ASSERT (N >= 3); /* TBC: 2 instead ? */ \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, (b)->root, (b)->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, (b)->root, (b)->root); \
|
||||
M_ASSERT ((b)->root->next == NULL); \
|
||||
if ((b)->root->num <= 0) M_ASSERT (-(b)->root->num == (int) (b)->size); \
|
||||
} while (0)
|
||||
@@ -314,22 +300,22 @@
|
||||
Ceil(Log2(2 ^ (CHAR_BIT*sizeof (size_t)))) + 1
|
||||
"+ 1" due to final line composed of nodes.
|
||||
*/
|
||||
#define BPTREEI_MAX_STACK ((int)(1 + CHAR_BIT*sizeof (size_t)))
|
||||
#define M_BPTR33_MAX_STACK ((int)(1 + CHAR_BIT*sizeof (size_t)))
|
||||
|
||||
/* Deferred evaluation for the b+tree definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define BPTREEI_DEF_P1(arg) BPTREEI_DEF_P2 arg
|
||||
#define M_BPTR33_DEF_P1(arg) M_ID( M_BPTR33_DEF_P2 arg )
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
#define BPTREEI_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
M_IF_OPLIST(key_oplist)(BPTREEI_DEF_P3, BPTREEI_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t)
|
||||
#define M_BPTR33_DEF_P2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
M_IF_OPLIST(key_oplist)(M_BPTR33_DEF_P3, M_BPTR33_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t)
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define BPTREEI_DEF_P3(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
M_IF_OPLIST(value_oplist)(BPTREEI_DEF_P4, BPTREEI_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t)
|
||||
#define M_BPTR33_DEF_P3(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
M_IF_OPLIST(value_oplist)(M_BPTR33_DEF_P4, M_BPTR33_DEF_FAILURE)(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define BPTREEI_DEF_FAILURE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
#define M_BPTR33_DEF_FAILURE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BPTREE*_DEF): one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist))
|
||||
|
||||
/* Internal b+tree definition
|
||||
@@ -347,14 +333,14 @@
|
||||
- pit_t: alias for internal parent iterator
|
||||
- subtype_t: alias for the type referenced by the iterator
|
||||
*/
|
||||
#define BPTREEI_DEF_P4(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
#define M_BPTR33_DEF_P4(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
\
|
||||
M_IF(isMap)( \
|
||||
/* Type returned by the iterator. Due to having key and value \
|
||||
separated in their own array in the node, it is pointers to \
|
||||
the objects, not a global pointer to both objects. */ \
|
||||
typedef struct M_C(name, _pair_s) { \
|
||||
key_t *key_ptr; \
|
||||
key_t *key_ptr; \
|
||||
value_t *value_ptr; \
|
||||
} subtype_t; \
|
||||
, \
|
||||
@@ -393,7 +379,7 @@
|
||||
/* Define the Parent Tree Iterator */ \
|
||||
typedef struct M_C(name, _parent_it_s) { \
|
||||
int num; \
|
||||
node_t parent[BPTREEI_MAX_STACK]; \
|
||||
node_t parent[M_BPTR33_MAX_STACK]; \
|
||||
} pit_t[1]; \
|
||||
\
|
||||
/* Define the Iterator */ \
|
||||
@@ -411,6 +397,8 @@
|
||||
/* TODO: Can be specialized to alloc for leaf or for non leaf */ \
|
||||
static inline node_t M_C(name, _new_node)(void) \
|
||||
{ \
|
||||
M_STATIC_ASSERT(N >= 2, M_LIB_ILLEGAL_PARAM, \
|
||||
"Number of items per node shall be >= 2."); \
|
||||
node_t n = M_CALL_NEW(key_oplist, struct M_C(name, _node_s)); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (node_t)); \
|
||||
@@ -425,7 +413,7 @@
|
||||
{ \
|
||||
b->root = M_C(name, _new_node)(); \
|
||||
b->size = 0; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline bool M_C(name, _is_leaf)(const node_t n) \
|
||||
@@ -444,9 +432,9 @@
|
||||
return num; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _clean)(tree_t b) \
|
||||
static inline void M_C(name, _reset)(tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
node_t next, n = b->root; \
|
||||
pit_t pit; \
|
||||
/* np is the heigh of the tree */ \
|
||||
@@ -454,11 +442,11 @@
|
||||
/* Scan down the nodes to the left down node */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
pit->parent[np++] = n; \
|
||||
M_ASSERT (np <= BPTREEI_MAX_STACK); \
|
||||
M_ASSERT (np <= M_BPTR33_MAX_STACK); \
|
||||
n = n->kind.node[0]; \
|
||||
} \
|
||||
pit->parent[np++] = n; \
|
||||
M_ASSERT (np <= BPTREEI_MAX_STACK); \
|
||||
M_ASSERT (np <= M_BPTR33_MAX_STACK); \
|
||||
/* Clean & free non root */ \
|
||||
for(int i = 0; i < np; i++) { \
|
||||
n = pit->parent[i]; \
|
||||
@@ -484,13 +472,13 @@
|
||||
/* Clean root */ \
|
||||
b->root->num = 0; \
|
||||
b->size = 0; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _clear)(tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_C(name, _clean)(b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_C(name, _reset)(b); \
|
||||
/* Once the tree is clean, only the root remains */ \
|
||||
M_CALL_DEL(key_oplist, b->root); \
|
||||
b->root = NULL; \
|
||||
@@ -539,18 +527,18 @@
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, (o==root) ? n : root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, (o==root) ? n : root); \
|
||||
return n; \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _init_set)(tree_t b, const tree_t o) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, o); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, o); \
|
||||
M_ASSERT (b != NULL); \
|
||||
/* Just copy recursively the root node */ \
|
||||
b->root = M_C(name, _copy_node)(o->root, o->root); \
|
||||
b->size = o->size; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void M_C(name, _set)(tree_t b, const tree_t o) \
|
||||
@@ -563,14 +551,14 @@
|
||||
\
|
||||
static inline bool M_C(name, _empty_p)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
/* root shall be an empty leaf */ \
|
||||
return b->size == 0; \
|
||||
} \
|
||||
\
|
||||
static inline size_t M_C(name, _size)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return b->size; \
|
||||
} \
|
||||
\
|
||||
@@ -578,10 +566,10 @@
|
||||
{ \
|
||||
node_t n = b->root; \
|
||||
int np = 0; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
/* Go down the tree while searching for key */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
M_ASSERT (np <= BPTREEI_MAX_STACK); \
|
||||
M_ASSERT (np <= M_BPTR33_MAX_STACK); \
|
||||
int i, hi = n->num; \
|
||||
M_ASSERT (hi > 0); \
|
||||
/* Linear search is usually faster than binary search for \
|
||||
@@ -597,7 +585,7 @@
|
||||
/* Select the new node to go down to */ \
|
||||
n = n->kind.node[i]; \
|
||||
M_ASSERT (n != NULL); \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
} \
|
||||
pit->num = np; \
|
||||
return n; \
|
||||
@@ -605,12 +593,12 @@
|
||||
\
|
||||
static inline value_t *M_C(name, _get)(const tree_t b, key_t const key) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
pit_t pit; \
|
||||
/* Get the leaf node where the key can be */ \
|
||||
node_t n = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
int cmp = 0; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
/* Search in the leaf for key */ \
|
||||
for(int i = 0; cmp >= 0 && i < -n->num; i++) { \
|
||||
cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \
|
||||
@@ -688,7 +676,7 @@
|
||||
M_IF(isMap)(M_DEFERRED_COMMA value_t const value,)) \
|
||||
{ \
|
||||
pit_t pit; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
/* Insert key into the leaf.*/ \
|
||||
/* NOTE: Even if there is N elements, we can still add one more.*/ \
|
||||
@@ -696,7 +684,7 @@
|
||||
if (i < 0) { \
|
||||
/* Nothing to do anymore. key already exists in the tree. \
|
||||
value has been updated if needed */ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; \
|
||||
} \
|
||||
b->size ++; \
|
||||
@@ -705,7 +693,7 @@
|
||||
M_ASSERT (num > 0); \
|
||||
if (M_LIKELY (num <= N)) { \
|
||||
/* nothing more to do */ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; \
|
||||
} \
|
||||
M_ASSERT (num == N+1); \
|
||||
@@ -722,8 +710,8 @@
|
||||
nleaf->num = -nnum; \
|
||||
nleaf->next = leaf->next; \
|
||||
leaf->next = nleaf; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, leaf, b->root); \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nleaf, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, leaf, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, nleaf, b->root); \
|
||||
/* Update parent to inject *key_ptr that splits between (leaf, nleaf) */ \
|
||||
key_t *key_ptr = &leaf->key[num-1]; \
|
||||
while (true) { \
|
||||
@@ -736,7 +724,7 @@
|
||||
parent->kind.node[0] = leaf; \
|
||||
parent->kind.node[1] = nleaf; \
|
||||
b->root = parent; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; \
|
||||
} \
|
||||
/* Non root node. Get the parent node */ \
|
||||
@@ -747,7 +735,7 @@
|
||||
parent->kind.node[i+1] = nleaf; \
|
||||
/* Test if parent node is full? */ \
|
||||
if (M_LIKELY (parent->num <= N)) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
return; /* No need to split parent.*/ \
|
||||
} \
|
||||
M_ASSERT (parent->num == N+1); \
|
||||
@@ -764,8 +752,8 @@
|
||||
nparent->num = nnp; \
|
||||
nparent->next = parent->next; \
|
||||
parent->next = nparent; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, parent, b->root); \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nparent, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, parent, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, nparent, b->root); \
|
||||
/* Prepare for the next step */ \
|
||||
key_ptr = &parent->key[np]; \
|
||||
leaf = parent; \
|
||||
@@ -773,6 +761,25 @@
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline value_t *M_C(name, _safe_get)(tree_t b, key_t const key) \
|
||||
{ \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
/* Not optimized implementation */ \
|
||||
value_t *ret = M_C(name, _get)(b, key); \
|
||||
if (ret == NULL) { \
|
||||
M_IF(isMap)( \
|
||||
value_t v; \
|
||||
M_CALL_INIT(value_oplist, v); \
|
||||
M_C(name, _set_at)(b, key, v); \
|
||||
M_CALL_CLEAR(value_oplist, v); \
|
||||
, \
|
||||
M_C(name, _push)(b, key); \
|
||||
) \
|
||||
ret = M_C(name, _get)(b, key); \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _search_and_remove_in_leaf)(node_t n, key_t const key) \
|
||||
{ \
|
||||
@@ -912,7 +919,7 @@
|
||||
\
|
||||
static inline bool M_C(name, _erase)(tree_t b, key_t const key) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
pit_t pit; \
|
||||
node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
int k = M_C(name, _search_and_remove_in_leaf)(leaf, key); \
|
||||
@@ -981,7 +988,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (it != NULL); \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
@@ -995,7 +1002,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (it != NULL); \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
@@ -1032,6 +1039,7 @@
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->node != NULL); \
|
||||
M_ASSERT (M_C(name, _is_leaf)(it->node)); \
|
||||
it->idx ++; \
|
||||
if (it->idx >= -it->node->num && it->node->next != NULL) { \
|
||||
it->node = it->node->next; \
|
||||
@@ -1043,6 +1051,7 @@
|
||||
M_C(name, _ref)(it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->node != NULL); \
|
||||
M_ASSERT (M_C(name, _is_leaf)(it->node)); \
|
||||
M_ASSERT (it->idx <= -it->node->num); \
|
||||
M_IF(isMap)( \
|
||||
it->pair.key_ptr = &it->node->key[it->idx]; \
|
||||
@@ -1063,13 +1072,13 @@
|
||||
static inline void \
|
||||
M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (it != NULL); \
|
||||
pit_t pit; \
|
||||
node_t n = M_C(name, _search_for_leaf)(pit, b, key); \
|
||||
it->node = n; \
|
||||
int i; \
|
||||
BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
|
||||
for(i = 0; i < -n->num; i++) { \
|
||||
if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \
|
||||
break; \
|
||||
@@ -1101,17 +1110,11 @@
|
||||
return (cmp <= 0); \
|
||||
} \
|
||||
\
|
||||
static inline bool M_ATTR_DEPRECATED \
|
||||
M_C(name, _it_to_p)(it_t it, key_t const key) \
|
||||
{ \
|
||||
return M_C(name, _it_until_p)(it, key); \
|
||||
} \
|
||||
\
|
||||
static inline value_t * \
|
||||
M_C(name, _min)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_ASSERT (b->size > 0); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
if (M_UNLIKELY (b->size == 0)) return NULL; \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
@@ -1123,7 +1126,8 @@
|
||||
static inline value_t * \
|
||||
M_C(name, _max)(const tree_t b) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
if (M_UNLIKELY (b->size == 0)) return NULL; \
|
||||
node_t n = b->root; \
|
||||
/* Scan down the nodes */ \
|
||||
while (!M_C(name, _is_leaf)(n)) { \
|
||||
@@ -1147,47 +1151,47 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(tree_t b, tree_t ref) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_ASSERT (b != NULL && b != ref); \
|
||||
b->size = ref->size; \
|
||||
b->root = ref->root; \
|
||||
ref->root = NULL; \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(tree_t b, tree_t ref) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \
|
||||
M_ASSERT (b != ref); \
|
||||
M_C(name,_clear)(b); \
|
||||
M_C(name,_init_move)(b, ref); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(tree_t tree1, tree_t tree2) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
M_SWAP(size_t, tree1->size, tree2->size); \
|
||||
M_SWAP(node_t, tree1->root, tree2->root); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, tree1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, tree2); \
|
||||
} \
|
||||
\
|
||||
BPTREEI_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t)
|
||||
M_BPTR33_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t)
|
||||
|
||||
|
||||
/* Define additional functions.
|
||||
Do not used any fields but the already defined methods */
|
||||
#define BPTREEI_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
#define M_BPTR33_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
|
||||
\
|
||||
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)( \
|
||||
static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t2); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t2); \
|
||||
if (t1->size != t2->size) return false; \
|
||||
if (t1->size == 0) return true; \
|
||||
/* Slow comparaison */ \
|
||||
@@ -1222,7 +1226,7 @@
|
||||
\
|
||||
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)( \
|
||||
static inline size_t M_C(name,_hash)(const tree_t t1) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_HASH_DECL(hash); \
|
||||
/* NOTE: We can't compute the hash directly for the same reason \
|
||||
than for EQUAL operator. */ \
|
||||
@@ -1243,11 +1247,11 @@
|
||||
, /* NO HASH METHOD */ ) \
|
||||
\
|
||||
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
static inline void M_C(name, _get_str)(m_string_t str, \
|
||||
const tree_t t1, bool append) { \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, 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 it; \
|
||||
@@ -1255,18 +1259,18 @@
|
||||
!M_C(name, _end_p)(it); \
|
||||
M_C(name, _next)(it)) { \
|
||||
if (commaToPrint) \
|
||||
string_push_back (str, M_GET_SEPARATOR key_oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR key_oplist); \
|
||||
commaToPrint = true; \
|
||||
subtype_t const *ref1 = M_C(name, _cref)(it); \
|
||||
M_IF(isMap)( \
|
||||
M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \
|
||||
string_cat_str(str, ":"); \
|
||||
m_string_cat_cstr(str, ":"); \
|
||||
M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \
|
||||
, \
|
||||
M_CALL_GET_STR(key_oplist, str, *ref1, true); \
|
||||
); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* NO GET_STR */ ) \
|
||||
\
|
||||
@@ -1274,7 +1278,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, tree_t const t1) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
bool commaToPrint = false; \
|
||||
@@ -1302,9 +1306,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(tree_t t1, const char str[], const char **endp) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_C(name,_clean)(t1); \
|
||||
M_C(name,_reset)(t1); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -1344,9 +1348,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(tree_t t1, FILE *file) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (file != NULL); \
|
||||
M_C(name,_clean)(t1); \
|
||||
M_C(name,_reset)(t1); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -1382,7 +1386,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
@@ -1426,13 +1430,13 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \
|
||||
{ \
|
||||
BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
key_t key; \
|
||||
M_C(name,_clean)(t1); \
|
||||
M_C(name,_reset)(t1); \
|
||||
M_IF(isMap)( \
|
||||
value_t value; \
|
||||
ret = f->m_interface->read_map_start(local, f, &estimated_size); \
|
||||
@@ -1465,5 +1469,19 @@
|
||||
} \
|
||||
, /* no in_serial */ ) \
|
||||
\
|
||||
M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(M_INV(isMap), name, tree_t, key_oplist, value_oplist)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define BPTREE_DEF2 M_BPTREE_DEF2
|
||||
#define BPTREE_DEF2_AS M_BPTREE_DEF2_AS
|
||||
#define BPTREE_DEF M_BPTREE_DEF
|
||||
#define BPTREE_DEF_AS M_BPTREE_DEF_AS
|
||||
#define BPTREE_MULTI_DEF2 M_BPTREE_MULTI_DEF2
|
||||
#define BPTREE_MULTI_DEF2_AS M_BPTREE_MULTI_DEF2_AS
|
||||
#define BPTREE_MULTI_DEF M_BPTREE_MULTI_DEF
|
||||
#define BPTREE_MULTI_DEF_AS M_BPTREE_MULTI_DEF_AS
|
||||
#define BPTREE_OPLIST M_BPTREE_OPLIST
|
||||
#define BPTREE_OPLIST2 M_BPTREE_OPLIST2
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+410
-271
File diff suppressed because it is too large.
Load diff
+42
-38
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Concurrent memory pool allocator
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,19 +32,19 @@
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Minimum number of nodes per group of nodes */
|
||||
#define C_MEMPOOL_MIN_NODE_PER_GROUP 16
|
||||
#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 \
|
||||
C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
|
||||
M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
|
||||
M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/* Classic internal Singly List without allocation */
|
||||
#define C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
#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; \
|
||||
@@ -123,7 +123,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
*/
|
||||
/* TODO: Optimize alignement to reduce memory consumption. NIL object can use []
|
||||
to reduce memory consumption too (non compatible with C++ ...) */
|
||||
#define C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
#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; \
|
||||
@@ -304,7 +304,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* System node allocator: request memory to the system.
|
||||
As such it is a non Lock-Free path. */
|
||||
#define C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
#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) \
|
||||
@@ -386,7 +386,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
As such it won't support more than ULONG_MAX sleep for all threads.
|
||||
*/
|
||||
#define C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
#define M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lfmp_thread_s) { \
|
||||
M_C(name, _slist_ct) free; \
|
||||
@@ -410,7 +410,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
|
||||
/* NOTE: once a node is deleted, its data are kept readable until the future GC */
|
||||
#define C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
#define M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
unsigned initial; \
|
||||
@@ -418,18 +418,18 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _lflist_ct) free; \
|
||||
M_C(name, _lflist_ct) to_be_reclaimed; \
|
||||
M_C(name, _lflist_ct) empty; \
|
||||
m_gc_mempool_list_ct mempool_node; \
|
||||
m_cmemp00l_list_ct mempool_node; \
|
||||
struct m_gc_s *gc_mem; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
/* Garbage collect of the nodes of the mempool on sleep */ \
|
||||
static inline void \
|
||||
M_C(name, _int_gc_on_sleep)(m_gc_t gc_mem, m_gc_mempool_list_ct *data, \
|
||||
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_gc_mempool_list_ct, mempool_node); \
|
||||
M_TYPE_FROM_FIELD(struct M_C(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)) { \
|
||||
@@ -473,7 +473,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _lfmp_thread_init)(&mem->thread_data[i]); \
|
||||
} \
|
||||
/* Preallocate some group of nodes for the mempool */ \
|
||||
mem->initial = M_MAX(C_MEMPOOL_MIN_NODE_PER_GROUP, init_node_count); \
|
||||
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)); \
|
||||
@@ -484,7 +484,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
} \
|
||||
/* Register the mempool in the GC */ \
|
||||
mem->mempool_node.gc_on_sleep = M_C(name, _int_gc_on_sleep); \
|
||||
mem->mempool_node.gc_on_sleep = M_C3(m_cmemp00l_,name,_gc_on_sleep); \
|
||||
mem->mempool_node.next = gc_mem->mempool_list; \
|
||||
gc_mem->mempool_list = &mem->mempool_node; \
|
||||
mem->gc_mem = gc_mem; \
|
||||
@@ -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_gc_mempool_list_s {
|
||||
struct m_gc_mempool_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_gc_mempool_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_gc_mempool_list_ct;
|
||||
} m_cmemp00l_list_ct;
|
||||
|
||||
/* Define the Garbage collector thread data */
|
||||
typedef struct m_gc_lfmp_thread_s {
|
||||
@@ -574,9 +574,9 @@ 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_gc_mempool_list_ct *mempool_list;
|
||||
m_cmemp00l_list_ct *mempool_list;
|
||||
} m_gc_t[1];
|
||||
|
||||
static inline void
|
||||
@@ -586,7 +586,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread)
|
||||
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) {
|
||||
M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct));
|
||||
@@ -610,7 +610,7 @@ 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
|
||||
@@ -618,7 +618,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -629,7 +629,7 @@ m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
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
|
||||
@@ -644,7 +644,7 @@ m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
}
|
||||
|
||||
static inline m_gc_ticket_ct
|
||||
m_gc_int_min_ticket(m_gc_t gc_mem)
|
||||
m_cmemp00l_gc_min_ticket(m_gc_t gc_mem)
|
||||
{
|
||||
m_gc_ticket_ct min = atomic_load(&gc_mem->thread_data[0].ticket);
|
||||
for(m_gc_tid_t i = 1; i < gc_mem->max_thread; i++) {
|
||||
@@ -660,9 +660,9 @@ m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
/* Increase life time of the thread */
|
||||
m_gc_ticket_ct t = atomic_fetch_add(&gc_mem->ticket, 1UL);
|
||||
atomic_store(&gc_mem->thread_data[id].ticket, t+1);
|
||||
const m_gc_ticket_ct min_ticket = m_gc_int_min_ticket(gc_mem);
|
||||
const m_gc_ticket_ct min_ticket = m_cmemp00l_gc_min_ticket(gc_mem);
|
||||
/* Iterate over all registered mempools */
|
||||
m_gc_mempool_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 */
|
||||
@@ -681,9 +681,9 @@ m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
C_MEMPOOL_DEF_SINGLY_LIST(m_vlapool, char)
|
||||
C_MEMPOOL_DEF_LF_QUEUE(m_vlapool, char)
|
||||
C_MEMPOOL_DEF_SYSTEM_ALLOC(m_vlapool, char)
|
||||
M_CMEMP00L_DEF_SINGLY_LIST(m_vlapool, char)
|
||||
M_CMEMP00L_DEF_LF_QUEUE(m_vlapool, char)
|
||||
M_CMEMP00L_DEF_SYSTEM_ALLOC(m_vlapool, char)
|
||||
|
||||
typedef struct m_vlapool_lfmp_thread_s {
|
||||
m_vlapool_slist_ct 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_gc_mempool_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_vlapool_int_gc_on_sleep(m_gc_t gc_mem, m_gc_mempool_list_ct *data,
|
||||
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_gc_mempool_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)) {
|
||||
@@ -771,7 +771,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
|
||||
m_vlapool_lflist_init(mem->empty, m_vlapool_alloc_node(0));
|
||||
|
||||
/* Register the mempool in the GC */
|
||||
mem->mvla_node.gc_on_sleep = m_vlapool_int_gc_on_sleep;
|
||||
mem->mvla_node.gc_on_sleep = m_cmemp00l_vlapool_on_sleep;
|
||||
mem->mvla_node.next = gc_mem->mempool_list;
|
||||
gc_mem->mempool_list = &mem->mvla_node;
|
||||
mem->gc_mem = gc_mem;
|
||||
@@ -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
|
||||
+108
-106
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Basic Protected Concurrent module over container.
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,43 +32,27 @@
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
based on the given container.
|
||||
USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_CONCURRENT_DEF(name, ...) \
|
||||
M_CONCURRENT_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
based on the given container as the given name name_t
|
||||
USAGE: CONCURRENT_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_DEF_AS(name, name_t, ...) \
|
||||
#define M_CONCURRENT_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_C0NCURRENT_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a protected concurrent container given its name and its oplist.
|
||||
USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */
|
||||
#define CONCURRENT_OPLIST(...) \
|
||||
CONCURRENTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
based on its given container. Operations that perform only read of the container
|
||||
can be done in parallel.
|
||||
USAGE: CONCURRENT_RP_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_RP_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_CONCURRENT_RP_DEF(name, ...) \
|
||||
M_CONCURRENT_RP_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a protected concurrent container and its associated functions
|
||||
@@ -76,26 +60,34 @@
|
||||
based on its given container. Operations that perform only read of the container
|
||||
can be done in parallel.
|
||||
USAGE: CONCURRENT_RP_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define CONCURRENT_RP_DEF_AS(name, name_t, ...) \
|
||||
#define M_CONCURRENT_RP_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
CONCURRENTI_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_C0NCURRENT_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a protected concurrent container given its name and its oplist.
|
||||
USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */
|
||||
#define M_CONCURRENT_OPLIST(...) \
|
||||
M_C0NCURRENT_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_OPLIST_P1(arg) CONCURRENTI_OPLIST_P2 arg
|
||||
#define M_C0NCURRENT_OPLIST_P1(arg) M_C0NCURRENT_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define CONCURRENTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(CONCURRENTI_OPLIST_P3, CONCURRENTI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_C0NCURRENT_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_C0NCURRENT_OPLIST_P3, M_C0NCURRENT_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define CONCURRENTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_C0NCURRENT_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* OPLIST definition
|
||||
@@ -103,7 +95,7 @@
|
||||
container (_get returns a pointer to an internal data, data that may be
|
||||
destroyed by another thread).
|
||||
*/
|
||||
#define CONCURRENTI_OPLIST_P3(name, oplist) \
|
||||
#define M_C0NCURRENT_OPLIST_P3(name, oplist) \
|
||||
(M_IF_METHOD(INIT, oplist)(INIT(M_C(name, _init)),) \
|
||||
,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_C(name, _init_set)),) \
|
||||
,M_IF_METHOD(SET, oplist)(SET(M_C(name, _set)),) \
|
||||
@@ -111,12 +103,13 @@
|
||||
,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(SWAP,oplist)(SWAP(M_C(name, _swap)),) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(EMPTY_P, oplist)(EMPTY_P(M_C(name,_empty_p)),) \
|
||||
,M_IF_METHOD(GET_SIZE, oplist)(GET_SIZE(M_C(name,_size)),) \
|
||||
,M_IF_METHOD(CLEAN, oplist)(CLEAN(M_C(name,_clean)),) \
|
||||
,M_IF_METHOD(RESET, oplist)(RESET(M_C(name,_reset)),) \
|
||||
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_TYPE(M_GET_KEY_TYPE oplist),) \
|
||||
,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_TYPE(M_GET_VALUE_TYPE oplist),) \
|
||||
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_OPLIST(M_GET_KEY_OPLIST oplist),) \
|
||||
@@ -143,21 +136,21 @@
|
||||
/* Internal contract
|
||||
NOTE: Can't check too much without locking the container itself
|
||||
*/
|
||||
#define CONCURRENTI_CONTRACT(c) do { \
|
||||
#define M_C0NCURRENT_CONTRACT(c) do { \
|
||||
M_ASSERT ((c) != NULL); \
|
||||
M_ASSERT ( (c)->self == (c)); \
|
||||
} while (0)
|
||||
|
||||
/* Deferred evaluation for the concurrent definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_DEF_P1(arg) CONCURRENTI_DEF_P2 arg
|
||||
#define M_C0NCURRENT_DEF_P1(arg) M_ID( M_C0NCURRENT_DEF_P2 arg )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define CONCURRENTI_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(CONCURRENTI_DEF_P3, CONCURRENTI_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
#define M_C0NCURRENT_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(M_C0NCURRENT_DEF_P3, M_C0NCURRENT_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define CONCURRENTI_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
/* Internal concurrent definition
|
||||
@@ -166,7 +159,7 @@
|
||||
- oplist: oplist of the type of the sub container
|
||||
- concurrent_t: alias for M_C(name, _t) [ type of the container ]
|
||||
*/
|
||||
#define CONCURRENTI_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
/* Define a concurrent container using a lock */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
@@ -197,7 +190,7 @@
|
||||
m_mutex_init(out->lock); \
|
||||
m_cond_init(out->there_is_data); \
|
||||
out->self = out; \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
\
|
||||
/* Clear the fields of the concurrent object not associated to the \
|
||||
@@ -205,7 +198,7 @@
|
||||
static inline void \
|
||||
M_C(name, _internal_clear)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_clear(out->lock); \
|
||||
m_cond_clear(out->there_is_data); \
|
||||
out->self = NULL; \
|
||||
@@ -218,7 +211,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_lock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -228,7 +221,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_unlock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_unlock (out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -237,7 +230,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_wait)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_cond_wait(out->self->there_is_data, out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -248,7 +241,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_lock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -258,7 +251,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_unlock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_unlock (out->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -267,7 +260,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_wait)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_cond_wait(out->self->there_is_data, out->self->lock); \
|
||||
} \
|
||||
\
|
||||
@@ -276,13 +269,13 @@
|
||||
static inline void \
|
||||
M_C(name, _write_signal)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
/* We need to signal this to ALL waiting threads as multiple threads \
|
||||
may wait on a some data of this container. */ \
|
||||
m_cond_broadcast(out->there_is_data); \
|
||||
} \
|
||||
\
|
||||
CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
|
||||
|
||||
/* Internal definition of the functions commons to concurrent and rp-concurrent
|
||||
@@ -293,7 +286,7 @@
|
||||
A function is defined only if the underlying container exports the needed
|
||||
services. It is usually one service declared per service exported.
|
||||
*/
|
||||
#define CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
static inline void \
|
||||
@@ -301,7 +294,7 @@
|
||||
{ \
|
||||
M_C(name, _internal_init)(out); \
|
||||
M_CALL_INIT(oplist, out->data); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -309,13 +302,13 @@
|
||||
static inline void \
|
||||
M_C(name, _init_set)(concurrent_t out, concurrent_t const src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
M_ASSERT (out != src); \
|
||||
M_C(name, _internal_init)(out); \
|
||||
M_C(name, _read_lock)(src); \
|
||||
M_CALL_INIT_SET(oplist, out->data, src->data); \
|
||||
M_C(name, _read_unlock)(src); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -323,7 +316,7 @@
|
||||
static inline void \
|
||||
M_C(name, _set)(concurrent_t out, concurrent_t const src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
if (M_UNLIKELY (out == src)) return; \
|
||||
/* Need to order the locks in a total way to avoid lock deadlock. \
|
||||
Indeed, two call to _set can be done in two threads with : \
|
||||
@@ -350,7 +343,7 @@
|
||||
M_C(name, _write_unlock)(out); \
|
||||
M_C(name, _read_unlock)(src); \
|
||||
} \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -358,7 +351,7 @@
|
||||
static inline void \
|
||||
M_C(name, _clear)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
/* No need to lock. A clear is supposed to be called when all operations \
|
||||
of the container in other threads are terminated */ \
|
||||
M_CALL_CLEAR(oplist, out->data); \
|
||||
@@ -370,13 +363,13 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(concurrent_t out, concurrent_t src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
M_ASSERT (out != src); \
|
||||
/* No need to lock 'src' ? */ \
|
||||
M_C(name, _internal_init)(out); \
|
||||
M_CALL_INIT_MOVE(oplist, out->data, src->data); \
|
||||
M_C(name, _internal_clear)(src); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -384,14 +377,14 @@
|
||||
static inline void \
|
||||
M_C(name, _move)(concurrent_t out, concurrent_t src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
/* No need to lock 'src' ? */ \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_MOVE(oplist, out->data, src->data); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
M_C(name, _internal_clear)(src); \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
@@ -399,8 +392,8 @@
|
||||
static inline void \
|
||||
M_C(name, _swap)(concurrent_t out, concurrent_t src) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
CONCURRENTI_CONTRACT(src); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(src); \
|
||||
if (M_UNLIKELY (out == src)) return; \
|
||||
/* See comment above */ \
|
||||
if (out < src) { \
|
||||
@@ -421,13 +414,13 @@
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(CLEAN, oplist)( \
|
||||
M_IF_METHOD(RESET, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _clean)(concurrent_t out) \
|
||||
M_C(name, _reset)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_CLEAN(oplist, out->data); \
|
||||
M_CALL_RESET(oplist, out->data); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
} \
|
||||
,) \
|
||||
@@ -436,7 +429,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
bool b = M_CALL_EMPTY_P(oplist, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -448,7 +441,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _size)(concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
size_t r = M_CALL_GET_SIZE(oplist, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -460,7 +453,7 @@
|
||||
static inline void \
|
||||
M_C(name, _set_at)(concurrent_t out, M_GET_KEY_TYPE oplist const key, M_GET_VALUE_TYPE oplist const data) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_SET_KEY(oplist, out->data, key, data); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -472,7 +465,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _get_copy)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (out_data != NULL); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \
|
||||
@@ -484,14 +477,14 @@
|
||||
} \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(GET_SET_KEY, oplist)( \
|
||||
M_IF_METHOD(SAFE_GET_KEY, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_at_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
M_C(name, _safe_get_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (out_data != NULL); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_SET_KEY(oplist, out->data, key); \
|
||||
M_GET_VALUE_TYPE oplist *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \
|
||||
M_ASSERT (p != NULL); \
|
||||
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
@@ -502,7 +495,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _erase)(concurrent_t out, M_GET_KEY_TYPE oplist const key) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
bool b = M_CALL_ERASE_KEY(oplist, out->data, key); \
|
||||
/* We suppose that the container has 'infinite' capacity, so \
|
||||
@@ -516,19 +509,21 @@
|
||||
static inline void \
|
||||
M_C(name, _push)(concurrent_t out, M_GET_SUBTYPE oplist const data) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_PUSH(oplist, out->data, data); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
M_C(name, _write_unlock)(out); \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, concurrent_t, M_C(name, _emplace), M_GET_OPLIST oplist, M_EMPLACE_QUEUE_GENE) \
|
||||
,) \
|
||||
\
|
||||
M_IF_METHOD(POP, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _pop)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_POP(oplist, p, out->data); \
|
||||
/* See comment above */ \
|
||||
@@ -540,7 +535,7 @@
|
||||
static inline void \
|
||||
M_C(name, _push_move)(concurrent_t out, M_GET_SUBTYPE oplist *data) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_PUSH_MOVE(oplist, out->data, data); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -552,7 +547,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
M_CALL_POP_MOVE(oplist, p, out->data); \
|
||||
/* See comment above */ \
|
||||
@@ -562,9 +557,9 @@
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, concurrent_t const out, bool a) \
|
||||
M_C(name, _get_str)(m_string_t str, concurrent_t const out, bool a) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
M_CALL_GET_STR(oplist, str, out->data, a); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -575,7 +570,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *f, concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
M_CALL_OUT_STR(oplist, f, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -586,7 +581,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(concurrent_t out, const char str[], const char **e) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
bool b = M_CALL_PARSE_STR(oplist, out->data, str, e); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -599,7 +594,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(concurrent_t out, FILE *f) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
bool b = M_CALL_IN_STR(oplist, out->data, f); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -612,7 +607,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, f, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -624,7 +619,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(concurrent_t out, m_serial_read_t f) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _write_lock)(out); \
|
||||
m_serial_return_code_t r = M_CALL_IN_SERIAL(oplist, out->data, f); \
|
||||
M_C(name, _write_signal)(out); \
|
||||
@@ -637,8 +632,8 @@
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(concurrent_t const out1, concurrent_t const out2) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out1); \
|
||||
CONCURRENTI_CONTRACT(out2); \
|
||||
M_C0NCURRENT_CONTRACT(out1); \
|
||||
M_C0NCURRENT_CONTRACT(out2); \
|
||||
if (M_UNLIKELY (out1 == out2)) return true; \
|
||||
/* See comment above on mutal mutexs */ \
|
||||
if (out1 < out2) { \
|
||||
@@ -664,7 +659,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _get_blocking)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key, bool blocking) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (out_data != NULL); \
|
||||
bool ret = false; \
|
||||
M_C(name, _read_lock)(out); \
|
||||
@@ -688,7 +683,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _pop_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (p != NULL); \
|
||||
bool ret = false; \
|
||||
M_C(name, _write_lock)(out); \
|
||||
@@ -711,7 +706,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _pop_move_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_ASSERT (p != NULL); \
|
||||
bool ret = false; \
|
||||
M_C(name, _write_lock)(out); \
|
||||
@@ -734,7 +729,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _hash)(concurrent_t const out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
M_C(name, _read_lock)(out); \
|
||||
size_t h = M_CALL_HASH(oplist, out->data); \
|
||||
M_C(name, _read_unlock)(out); \
|
||||
@@ -747,14 +742,14 @@
|
||||
|
||||
/* Deferred evaluation for the RP concurrent definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define CONCURRENTI_RP_DEF_P1(arg) CONCURRENTI_RP_DEF_P2 arg
|
||||
#define M_C0NCURRENT_RP_DEF_P1(arg) M_ID( M_C0NCURRENT_RP_DEF_P2 arg )
|
||||
|
||||
/* Validate the value oplist before going further */
|
||||
#define CONCURRENTI_RP_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(CONCURRENTI_RP_DEF_P3, CONCURRENTI_RP_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
#define M_C0NCURRENT_RP_DEF_P2(name, type, oplist, concurrent_t) \
|
||||
M_IF_OPLIST(oplist)(M_C0NCURRENT_RP_DEF_P3, M_C0NCURRENT_RP_DEF_FAILURE)(name, type, oplist, concurrent_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define CONCURRENTI_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_RP_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
|
||||
|
||||
/* Internal RP concurrent definition
|
||||
@@ -763,7 +758,7 @@
|
||||
- oplist: oplist of the type of the sub container
|
||||
- concurrent_t: alias for M_C(name, _t) [ type of the container ]
|
||||
*/
|
||||
#define CONCURRENTI_RP_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
#define M_C0NCURRENT_RP_DEF_P3(name, type, oplist, concurrent_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
struct M_C(name, _s) *self; \
|
||||
@@ -790,13 +785,13 @@
|
||||
out->self = out; \
|
||||
out->read_count = 0; \
|
||||
out->writer_waiting = false; \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _internal_clear)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_clear(out->lock); \
|
||||
m_cond_clear(out->rw_done); \
|
||||
m_cond_clear(out->there_is_data); \
|
||||
@@ -806,7 +801,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_lock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_C(name, _s) *self = out->self; \
|
||||
m_mutex_lock (self->lock); \
|
||||
while (self->writer_waiting == true) { \
|
||||
@@ -819,7 +814,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_unlock)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_C(name, _s) *self = out->self; \
|
||||
m_mutex_lock (self->lock); \
|
||||
self->read_count --; \
|
||||
@@ -832,7 +827,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_lock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
while (out->writer_waiting == true) { \
|
||||
m_cond_wait(out->rw_done, out->lock); \
|
||||
@@ -847,7 +842,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_unlock)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
out->writer_waiting = false; \
|
||||
m_cond_broadcast (out->rw_done); \
|
||||
@@ -857,7 +852,7 @@
|
||||
static inline void \
|
||||
M_C(name, _read_wait)(const concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
struct M_C(name, _s) *self = out->self; \
|
||||
M_ASSERT (self == out); \
|
||||
m_mutex_lock (out->self->lock); \
|
||||
@@ -876,7 +871,7 @@
|
||||
static inline void \
|
||||
M_C(name, _write_wait)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
out->writer_waiting = false; \
|
||||
m_cond_broadcast (out->rw_done); \
|
||||
@@ -894,13 +889,20 @@
|
||||
static inline void \
|
||||
M_C(name, _write_signal)(concurrent_t out) \
|
||||
{ \
|
||||
CONCURRENTI_CONTRACT(out); \
|
||||
M_C0NCURRENT_CONTRACT(out); \
|
||||
m_mutex_lock (out->lock); \
|
||||
m_cond_broadcast(out->there_is_data); \
|
||||
m_mutex_unlock (out->lock); \
|
||||
} \
|
||||
\
|
||||
CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
M_C0NCURRENT_DEF_FUNC_P3(name, type, oplist, concurrent_t)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define CONCURRENT_DEF M_CONCURRENT_DEF
|
||||
#define CONCURRENT_DEF_AS M_CONCURRENT_DEF_AS
|
||||
#define CONCURRENT_RP_DEF M_CONCURRENT_RP_DEF
|
||||
#define CONCURRENT_RP_DEF_AS M_CONCURRENT_RP_DEF_AS
|
||||
#define CONCURRENT_OPLIST M_CONCURRENT_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - DEQUE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,20 +29,16 @@
|
||||
|
||||
/* Define a deque of a given type and its associated functions.
|
||||
USAGE: DEQUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define DEQUE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
DEQUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t), M_C(name, _node_ct) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_ct)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_DEQUE_DEF(name, ...) \
|
||||
M_DEQUE_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a deque of a given type and its associated functions.
|
||||
as the provided type name_t with the iterator named it_t.
|
||||
USAGE: DEQUE_DEF(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define DEQUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_DEQUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
DEQUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_D3QU3_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, M_C(name, _node_ct) ), \
|
||||
(name, __VA_ARGS__, name_t, it_t, M_C(name, _node_ct)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -50,22 +46,22 @@
|
||||
|
||||
/* Define the oplist of a deque of a type.
|
||||
USAGE: DEQUE_OPLIST(name[, oplist of the type]) */
|
||||
#define DEQUE_OPLIST(...) \
|
||||
DEQUEI_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define M_DEQUE_OPLIST(...) \
|
||||
M_D3QU3_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
/* Default initial size of a bucket of items */
|
||||
#ifndef M_USE_DEQUE_DEFAULT_SIZE
|
||||
#define M_USE_DEQUE_DEFAULT_SIZE 8
|
||||
#endif
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Default initial size of a bucket of items */
|
||||
#ifndef DEQUEUI_DEFAULT_SIZE
|
||||
#define DEQUEUI_DEFAULT_SIZE 8
|
||||
#endif
|
||||
|
||||
/* Define the internal contract of a deque */
|
||||
#define DEQUEI_CONTRACT(d) do { \
|
||||
#define M_D3QU3_CONTRACT(d) do { \
|
||||
M_ASSERT ((d) != NULL); \
|
||||
M_ASSERT ((d)->default_size >= DEQUEUI_DEFAULT_SIZE); \
|
||||
M_ASSERT ((d)->default_size >= M_USE_DEQUE_DEFAULT_SIZE); \
|
||||
M_ASSERT ((d)->front->node != NULL); \
|
||||
M_ASSERT ((d)->front->index <= (d)->front->node->size); \
|
||||
M_ASSERT ((d)->back->node != NULL); \
|
||||
@@ -78,14 +74,14 @@
|
||||
|
||||
/* Deferred evaluation for the deque definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DEQUEI_DEF_P1(arg) DEQUEI_DEF_P2 arg
|
||||
#define M_D3QU3_DEF_P1(arg) M_ID( M_D3QU3_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define DEQUEI_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
|
||||
M_IF_OPLIST(oplist)(DEQUEI_DEF_P3, DEQUEI_DEF_FAILURE)(name, type, oplist, deque_t, it_t, node_t)
|
||||
#define M_D3QU3_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \
|
||||
M_IF_OPLIST(oplist)(M_D3QU3_DEF_P3, M_D3QU3_DEF_FAILURE)(name, type, oplist, deque_t, it_t, node_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define DEQUEI_DEF_FAILURE(name, type, oplist, deque_t, it_t, node_t) \
|
||||
#define M_D3QU3_DEF_FAILURE(name, type, oplist, deque_t, it_t, node_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DEQUE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Internal deque definition
|
||||
@@ -96,7 +92,7 @@
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for node_t [ node ]
|
||||
*/
|
||||
#define DEQUEI_DEF_P3(name, type, oplist, deque_t, it_t, node_t) \
|
||||
#define M_D3QU3_DEF_P3(name, type, oplist, deque_t, it_t, node_t) \
|
||||
\
|
||||
/* It is a linked list of buckets of the types, \
|
||||
each new created bucket size grows compared to the previous one \
|
||||
@@ -129,7 +125,8 @@
|
||||
\
|
||||
/* Define the deque type: \
|
||||
- 'list' if the list of buckets containing the objects. \
|
||||
- 'front' and 'back' are iterators to the first and last elements. \
|
||||
- 'front' is a pseudo-iterator to the first \
|
||||
- 'back' is a pseudo-iterator to the one after last element \
|
||||
- 'default_size' is the size used for the creation of a new bucket \
|
||||
- 'count' is the number of elements in the container. \
|
||||
*/ \
|
||||
@@ -159,8 +156,9 @@
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
/* Allocate a new node for a deque */ \
|
||||
static inline node_t* \
|
||||
M_C(name, _int_new_node)(deque_t d) \
|
||||
M_C3(m_d3qu3_,name,_new_node)(deque_t d) \
|
||||
{ \
|
||||
size_t def = d->default_size; \
|
||||
/* Test for overflow of the size computation */ \
|
||||
@@ -168,7 +166,7 @@
|
||||
M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
/* Alloc a new node */ \
|
||||
/* Alloc a new node with dynamic size */ \
|
||||
node_t*n = (node_t*) (void*) \
|
||||
M_CALL_REALLOC(oplist, char, NULL, \
|
||||
sizeof(node_t) + def * sizeof(type) ); \
|
||||
@@ -191,22 +189,22 @@
|
||||
M_C(name, _init)(deque_t d) \
|
||||
{ \
|
||||
M_C(name, _node_list_init)(d->list); \
|
||||
d->default_size = DEQUEUI_DEFAULT_SIZE; \
|
||||
d->default_size = M_USE_DEQUE_DEFAULT_SIZE; \
|
||||
d->count = 0; \
|
||||
node_t *n = M_C(name, _int_new_node)(d); \
|
||||
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
d->back->node = n; \
|
||||
d->back->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
d->back->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(deque_t d) \
|
||||
M_C(name, _reset)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
node_t *min_node = NULL; \
|
||||
for(node_t *n = d->front->node; \
|
||||
n != NULL ; \
|
||||
@@ -225,14 +223,14 @@
|
||||
d->back->node = min_node; \
|
||||
d->back->index = min_node->size / 2; \
|
||||
d->count = 0; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_C(name, _clean)(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_C(name, _reset)(d); \
|
||||
/* We have registered the delete operator to clear all objects */ \
|
||||
M_C(name, _node_list_clear)(d->list); \
|
||||
/* It is safer to clean some variables */ \
|
||||
@@ -244,7 +242,7 @@
|
||||
static inline type * \
|
||||
M_C(name, _push_back_raw)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
node_t *n = d->back->node; \
|
||||
size_t index = d->back->index; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
@@ -252,7 +250,7 @@
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
if (n == NULL) { \
|
||||
/* No node exists, allocate a new one */ \
|
||||
n = M_C(name, _int_new_node)(d); \
|
||||
n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (M_UNLIKELY (n == NULL)) return NULL; \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
} \
|
||||
@@ -263,10 +261,17 @@
|
||||
index++; \
|
||||
d->count ++; \
|
||||
d->back->index = index; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
/* Internal, for INIT_WITH */ \
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(deque_t d) \
|
||||
{ \
|
||||
return M_C(name, _push_back_raw)(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_back)(deque_t d, type const x) \
|
||||
{ \
|
||||
@@ -301,7 +306,7 @@
|
||||
static inline type* \
|
||||
M_C(name, _push_front_raw)(deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
node_t *n = d->front->node; \
|
||||
size_t index = d->front->index; \
|
||||
index --; \
|
||||
@@ -309,7 +314,7 @@
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
n = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (n == NULL) { \
|
||||
n = M_C(name, _int_new_node)(d); \
|
||||
n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (M_UNLIKELY (n == NULL)) return NULL; \
|
||||
M_C(name, _node_list_push_front)(d->list, n); \
|
||||
} \
|
||||
@@ -319,7 +324,7 @@
|
||||
type *ret = &n->data[index]; \
|
||||
d->count ++; \
|
||||
d->front->index = index; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -357,7 +362,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *ptr, deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT(d->count > 0); \
|
||||
node_t *n = d->back->node; \
|
||||
size_t index = d->back->index; \
|
||||
@@ -386,7 +391,7 @@
|
||||
M_CALL_CLEAR(oplist, n->data[index]); \
|
||||
d->count --; \
|
||||
d->back->index = index; \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
@@ -403,25 +408,10 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_front)(type *ptr, deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT(d->count > 0); \
|
||||
node_t *n = d->front->node; \
|
||||
size_t index = d->front->index; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
/* If there is a previous node, \
|
||||
pop the front node and push it back to the back. This \
|
||||
reduce the used memory if the deque is used as a FIFO queue.*/ \
|
||||
node_t *prev = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (prev != NULL) { \
|
||||
prev = M_C(name, _node_list_pop_front)(d->list); \
|
||||
M_ASSERT (prev != n); \
|
||||
M_C(name, _node_list_push_back)(d->list, prev); \
|
||||
} \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
M_ASSERT (n != NULL); \
|
||||
d->front->node = n; \
|
||||
index = 0; \
|
||||
} \
|
||||
if (ptr != NULL) \
|
||||
M_IF_METHOD(MOVE, oplist) ( \
|
||||
M_CALL_MOVE(oplist, *ptr, n->data[index]); else \
|
||||
@@ -430,8 +420,34 @@
|
||||
) \
|
||||
M_CALL_CLEAR(oplist, n->data[index]); \
|
||||
index++; \
|
||||
if (M_UNLIKELY (n->size <= index)) { \
|
||||
/* If there is a previous node, \
|
||||
pop the front node and push it back to the back. This \
|
||||
recycles the used memory if the deque is used as a FIFO queue.*/ \
|
||||
node_t *prev = M_C(name, _node_list_previous_obj)(d->list, n); \
|
||||
if (prev != NULL) { \
|
||||
prev = M_C(name, _node_list_pop_front)(d->list); \
|
||||
M_ASSERT (prev != n); \
|
||||
M_C(name, _node_list_push_back)(d->list, prev); \
|
||||
} \
|
||||
/* Update front iterator to point to the next object */ \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
if (M_UNLIKELY(n == NULL)) { \
|
||||
/* No next obj. \
|
||||
It is only possible if there was only 1 element */ \
|
||||
M_ASSERT(d->count == 1); \
|
||||
/* Reset the deque to the midle of the current node */ \
|
||||
d->back->node = d->front->node; \
|
||||
index = d->front->node->size/2; \
|
||||
d->back->index = d->front->node->size/2; \
|
||||
} else { \
|
||||
d->front->node = n; \
|
||||
index = 0; \
|
||||
} \
|
||||
} \
|
||||
d->count --; \
|
||||
d->front->index = index; \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
@@ -448,7 +464,7 @@
|
||||
static inline type * \
|
||||
M_C(name, _back)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (d->count > 0); \
|
||||
size_t i = d->back->index; \
|
||||
node_t *n = d->back->node; \
|
||||
@@ -463,29 +479,24 @@
|
||||
static inline type * \
|
||||
M_C(name, _front)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (d->count > 0); \
|
||||
size_t i = d->front->index; \
|
||||
node_t *n = d->front->node; \
|
||||
if (M_UNLIKELY (n->size <= i)) { \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
M_ASSERT (n != NULL); \
|
||||
i = 0; \
|
||||
} \
|
||||
return &n->data[i]; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return d->count; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _capacity_back)(const deque_t v) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(v); \
|
||||
M_D3QU3_CONTRACT(v); \
|
||||
size_t s = 0; \
|
||||
for(node_t *n = M_C(name, _node_list_back)(v->list); \
|
||||
n != NULL ; \
|
||||
@@ -499,7 +510,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _capacity_front)(const deque_t v) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(v); \
|
||||
M_D3QU3_CONTRACT(v); \
|
||||
size_t s = 0; \
|
||||
for(node_t *n = M_C(name, _node_list_front)(v->list); \
|
||||
n != NULL ; \
|
||||
@@ -519,14 +530,14 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
return d->count == 0; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->node = d->front->node; \
|
||||
it->index = d->front->index; \
|
||||
@@ -536,7 +547,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->node = d->back->node; \
|
||||
it->index = d->back->index - 1; \
|
||||
@@ -551,7 +562,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->node = d->back->node; \
|
||||
it->index = d->back->index; \
|
||||
@@ -586,7 +597,7 @@
|
||||
it->index ++; \
|
||||
if (M_UNLIKELY (it->index >= n->size)) { \
|
||||
n = M_C(name, _node_list_next_obj)(it->deque->list, n); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
if (M_UNLIKELY (n == NULL || it->node == it->deque->back->node)) { \
|
||||
/* Point to 'end' (can't undo it) */ \
|
||||
it->node = it->deque->back->node; \
|
||||
it->index = it->deque->back->node->size; \
|
||||
@@ -605,14 +616,14 @@
|
||||
it->index --; \
|
||||
if (M_UNLIKELY (it->index >= n->size)) { \
|
||||
n = M_C(name, _node_list_previous_obj)(it->deque->list, n); \
|
||||
if (M_UNLIKELY (n == NULL)) { \
|
||||
if (M_UNLIKELY (n == NULL || it->node == it->deque->front->node)) { \
|
||||
/* Point to 'end' (can't undo it) */ \
|
||||
it->node = it->deque->back->node; \
|
||||
it->index = it->deque->back->node->size; \
|
||||
return; \
|
||||
} \
|
||||
it->node = n; \
|
||||
it->index = 0; \
|
||||
it->index = n->size - 1; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -653,30 +664,93 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(deque_t d, it_t it) \
|
||||
{ \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT (it != NULL && it->node != NULL); \
|
||||
M_ASSERT (d->count >= 1); \
|
||||
M_ASSERT_INDEX(it->index, it->node->size); \
|
||||
\
|
||||
node_t *n = it->node; \
|
||||
M_CALL_CLEAR(oplist, n->data[it->index]); \
|
||||
if (n == d->back->node) { \
|
||||
/* back index points to the element after the end */ \
|
||||
M_ASSERT (d->back->index != 0); \
|
||||
M_ASSERT (it->index < d->back->index); \
|
||||
/* We cannot have a node deletion in this case */ \
|
||||
memmove(&n->data[it->index], &n->data[it->index+1], \
|
||||
sizeof(type) * (d->back->index - it->index - 1)); \
|
||||
d->back->index --; \
|
||||
/* The iterator points to the next element */ \
|
||||
} else if (n == d->front->node) { \
|
||||
/* front index points to the first element */ \
|
||||
if (M_UNLIKELY (d->front->index == n->size -1)) { \
|
||||
/* Node 'smart' deletion (single element) */ \
|
||||
/* Update front iterator to point to the next object */ \
|
||||
n = M_C(name, _node_list_next_obj)(d->list, n); \
|
||||
/* We must have a next element, as we have a different back node \
|
||||
than the front node. */ \
|
||||
M_ASSERT (n != NULL); \
|
||||
d->front->node = n; \
|
||||
d->front->index = 0; \
|
||||
/* The iterator references this element */ \
|
||||
it->node = n; \
|
||||
it->index = 0; \
|
||||
} else { \
|
||||
memmove(&n->data[d->front->index+1], &n->data[d->front->index], \
|
||||
sizeof(type) * (it->index - d->front->index)); \
|
||||
d->front->index ++; \
|
||||
/* The iterator shall reference the next element */ \
|
||||
M_C(name, _next)(it); \
|
||||
} \
|
||||
} else { \
|
||||
/* Nether front or end node */ \
|
||||
if (M_UNLIKELY(n->size == 1)) { \
|
||||
/* The iterator shall reference the next element */ \
|
||||
M_C(name, _next)(it); \
|
||||
/* Node deletion */ \
|
||||
M_ASSERT(d->count > 1); \
|
||||
M_C(name, _node_list_unlink)(n); \
|
||||
M_CALL_FREE(oplist, n); \
|
||||
} else { \
|
||||
memmove(&n->data[it->index], &n->data[it->index+1], \
|
||||
sizeof(type) * (it->node->size - it->index - 1)); \
|
||||
/* We lose capacity of the node... */ \
|
||||
n->size --; \
|
||||
/* The iterator points to the next element \
|
||||
except if it was the last one*/ \
|
||||
if (M_UNLIKELY(it->index >= n->size)) M_C(name, _next)(it); \
|
||||
} \
|
||||
} \
|
||||
d->count--; \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(deque_t d, const deque_t src) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(src); \
|
||||
M_D3QU3_CONTRACT(src); \
|
||||
M_ASSERT (d != NULL); \
|
||||
M_C(name, _node_list_init)(d->list); \
|
||||
d->default_size = DEQUEUI_DEFAULT_SIZE + src->count; \
|
||||
d->default_size = M_USE_DEQUE_DEFAULT_SIZE + src->count; \
|
||||
d->count = src->count; \
|
||||
node_t *n = M_C(name, _int_new_node)(d); \
|
||||
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
|
||||
if (n == NULL) return; \
|
||||
d->default_size /= 2; \
|
||||
M_C(name, _node_list_push_back)(d->list, n); \
|
||||
d->front->node = n; \
|
||||
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
d->back->node = n; \
|
||||
d->back->index = DEQUEUI_DEFAULT_SIZE/2 + src->count; \
|
||||
d->back->index = M_USE_DEQUE_DEFAULT_SIZE/2 + src->count; \
|
||||
it_t it; \
|
||||
size_t i = DEQUEUI_DEFAULT_SIZE/2; \
|
||||
size_t i = M_USE_DEQUE_DEFAULT_SIZE/2; \
|
||||
for(M_C(name, _it)(it, src); !M_C(name, _end_p)(it) ; M_C(name, _next)(it)) { \
|
||||
type const *obj = M_C(name, _cref)(it); \
|
||||
M_CALL_INIT_SET(oplist, n->data[i], *obj); \
|
||||
i++; \
|
||||
M_ASSERT (i <= d->back->index); \
|
||||
} \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -692,7 +766,7 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(deque_t d, deque_t src) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(src); \
|
||||
M_D3QU3_CONTRACT(src); \
|
||||
M_ASSERT (d!= NULL); \
|
||||
M_C(name,_node_list_init_move)(d->list, src->list); \
|
||||
d->front->node = src->front->node; \
|
||||
@@ -702,24 +776,24 @@
|
||||
d->default_size = src->default_size; \
|
||||
d->count = src->count; \
|
||||
memset(src, 0, sizeof(deque_t)); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(deque_t d, deque_t src) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
DEQUEI_CONTRACT(src); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(src); \
|
||||
M_C(name, _clear)(d); \
|
||||
M_C(name, _init_move)(d, src); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(deque_t d, deque_t e) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
DEQUEI_CONTRACT(e); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(e); \
|
||||
M_C(name, _node_list_swap) (d->list, e->list); \
|
||||
M_SWAP(node_t *, d->front->node, e->front->node); \
|
||||
M_SWAP(node_t *, d->back->node, e->back->node); \
|
||||
@@ -727,14 +801,14 @@
|
||||
M_SWAP(size_t, d->back->index, e->back->index); \
|
||||
M_SWAP(size_t, d->default_size, e->default_size); \
|
||||
M_SWAP(size_t, d->count, e->count); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
DEQUEI_CONTRACT(e); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(e); \
|
||||
} \
|
||||
\
|
||||
static inline type* \
|
||||
M_C(name, _get)(deque_t d, size_t key) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT_INDEX (key, d->count); \
|
||||
const size_t index0 = d->front->index; \
|
||||
size_t count = 0; \
|
||||
@@ -761,19 +835,19 @@
|
||||
static inline void \
|
||||
M_C(name, _set_at)(deque_t d, size_t key, type const x) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT_INDEX (key, d->count); \
|
||||
type *p = M_C(name, _get)(d, key); \
|
||||
M_CALL_SET(oplist, *p, x); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const deque_t d1, const deque_t d2) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d1); \
|
||||
DEQUEI_CONTRACT(d2); \
|
||||
M_D3QU3_CONTRACT(d1); \
|
||||
M_D3QU3_CONTRACT(d2); \
|
||||
if (d1->count != d2->count) \
|
||||
return false; \
|
||||
it_t it1; \
|
||||
@@ -795,7 +869,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _hash)(const deque_t d) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_HASH_DECL(hash); \
|
||||
it_t it; \
|
||||
for(M_C(name, _it)(it, d); !M_C(name, _end_p)(it); M_C(name, _next)(it)) { \
|
||||
@@ -810,23 +884,22 @@
|
||||
static inline void \
|
||||
M_C(name, _swap_at)(deque_t d, size_t i, size_t j) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
M_ASSERT_INDEX (i, d->count); \
|
||||
M_ASSERT_INDEX (j, d->count); \
|
||||
type *obj1 = M_C(name, _get)(d, i); \
|
||||
type *obj2 = M_C(name, _get)(d, j); \
|
||||
M_CALL_SWAP(oplist, *obj1, *obj2); \
|
||||
DEQUEI_CONTRACT(d); \
|
||||
M_D3QU3_CONTRACT(d); \
|
||||
} \
|
||||
, /* NO SWAP */) \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, deque_t const deque, bool append) \
|
||||
M_C(name, _get_str)(m_string_t str, deque_t const deque, bool append) \
|
||||
{ \
|
||||
STRINGI_CONTRACT(str); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, deque) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
@@ -834,10 +907,9 @@
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_GET_STR(oplist, str, *item, true); \
|
||||
if (!M_C(name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
STRINGI_CONTRACT(str); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no GET_STR */ ) \
|
||||
\
|
||||
@@ -845,7 +917,7 @@
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, const deque_t deque) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (file != NULL); \
|
||||
fputc ('[', file); \
|
||||
it_t it; \
|
||||
@@ -865,9 +937,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(deque_t deque, const char str[], const char **endp) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (str != NULL); \
|
||||
M_C(name,_clean)(deque); \
|
||||
M_C(name,_reset)(deque); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -883,7 +955,7 @@
|
||||
if (b == false || c == 0) { goto exit_clear; } \
|
||||
M_C(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
success = (c == ']'); \
|
||||
exit_clear: \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
@@ -897,9 +969,9 @@
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(deque_t deque, FILE *file) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (file != NULL); \
|
||||
M_C(name,_clean)(deque); \
|
||||
M_C(name,_reset)(deque); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -915,7 +987,7 @@
|
||||
M_C(name, _push_back)(deque, item); \
|
||||
} while (c == M_GET_SEPARATOR oplist); \
|
||||
M_CALL_CLEAR(oplist, item); \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
return c == ']'; \
|
||||
} \
|
||||
, /* no IN_STR */ ) \
|
||||
@@ -924,7 +996,7 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, const deque_t deque) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
@@ -949,12 +1021,12 @@
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(deque_t deque, m_serial_read_t f) \
|
||||
{ \
|
||||
DEQUEI_CONTRACT(deque); \
|
||||
M_D3QU3_CONTRACT(deque); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
size_t estimated_size = 0; \
|
||||
M_C(name,_clean)(deque); \
|
||||
M_C(name,_reset)(deque); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
type item; \
|
||||
@@ -970,29 +1042,59 @@
|
||||
} \
|
||||
, /* no IN_SERIAL & INIT */ ) \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, deque_t, M_C(name, _emplace_back), oplist, M_D3QUE_EMPLACE_BACK_DEF) \
|
||||
M_EMPLACE_QUEUE_DEF(name, deque_t, M_C(name, _emplace_front), oplist, M_D3QUE_EMPLACE_FRONT_DEF)
|
||||
|
||||
|
||||
/* Definition of the emplace_back function for deque */
|
||||
#define M_D3QUE_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Definition of the emplace_front function for deque */
|
||||
#define M_D3QUE_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define DEQUEI_OPLIST_P1(arg) DEQUEI_OPLIST_P2 arg
|
||||
#define M_D3QU3_OPLIST_P1(arg) M_D3QU3_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define DEQUEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(DEQUEI_OPLIST_P3, DEQUEI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_D3QU3_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_D3QU3_OPLIST_P3, M_D3QU3_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define DEQUEI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_D3QU3_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_DEQUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* OPLIST definition of a deque */
|
||||
#define DEQUEI_OPLIST_P3(name, oplist) \
|
||||
#define M_D3QU3_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,INIT_WITH(API_1(M_INIT_WITH_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)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,EMPTY_P(M_C(name,_empty_p)) \
|
||||
@@ -1008,7 +1110,8 @@
|
||||
,IT_PREVIOUS(M_C(name,_previous)) \
|
||||
,IT_REF(M_C(name,_ref)) \
|
||||
,IT_CREF(M_C(name,_cref)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,IT_REMOVE(M_C(name,_remove)) \
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,PUSH(M_C(name,_push_back)) \
|
||||
,POP(M_C(name,_pop_back)) \
|
||||
@@ -1026,4 +1129,10 @@
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define DEQUE_DEF M_DEQUE_DEF
|
||||
#define DEQUE_DEF_AS M_DEQUE_DEF_AS
|
||||
#define DEQUE_OPLIST M_DEQUE_OPLIST
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+75
-69
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Function Object module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,10 +32,8 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, M_C(name, _t), __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_FUNC_OBJ_ITF_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object interface of name 'name'
|
||||
@@ -43,9 +41,9 @@
|
||||
* 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__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
|
||||
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
|
||||
|
||||
|
||||
@@ -67,10 +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, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, M_C(name, _t), base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_FUNC_OBJ_INS_DEF_AS(name, M_C(name,_t), base_name, param_list, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a function object instance of name 'name' based on the interface 'base_name'
|
||||
@@ -80,9 +76,9 @@
|
||||
* 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__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
|
||||
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
|
||||
|
||||
|
||||
@@ -90,8 +86,8 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_OPLIST, FUNCOBJI_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
|
||||
#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__)
|
||||
|
||||
|
||||
|
||||
@@ -102,7 +98,7 @@
|
||||
/* 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.
|
||||
@@ -113,7 +109,7 @@
|
||||
*/
|
||||
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) ( \
|
||||
#define M_FUNC0BJ_INS_NO_ATTR_OPLIST(name) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
@@ -121,20 +117,21 @@
|
||||
)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(FUNCOBJI_INS_ATTR_OPLIST_P3, FUNCOBJI_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
#define M_FUNC0BJ_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(M_FUNC0BJ_INS_ATTR_OPLIST_P3, M_FUNC0BJ_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
#define M_FUNC0BJ_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define the oplist of the instance */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
#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)),), \
|
||||
PROPERTIES(( LET_AS_INIT_WITH(1) )) \
|
||||
)
|
||||
|
||||
|
||||
@@ -145,7 +142,7 @@
|
||||
* - M_C(name, _callback_ct): internal type of the callback.
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
#define M_FUNC0BJ_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
@@ -179,7 +176,7 @@
|
||||
* - M_C4(name, _param_, num, _ct) for each parameter defined
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
#define M_FUNC0BJ_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
@@ -187,7 +184,7 @@
|
||||
/* Internal types for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* Define types for all parameters */ \
|
||||
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
|
||||
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__); \
|
||||
\
|
||||
@@ -200,18 +197,18 @@
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj \
|
||||
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
M_MAP3(M_FUNC0BJ_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
/* If the retcode is 'void', don't return the value of the callback */ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj M_MAP3(FUNCOBJI_BASE_ARGCALL, name, __VA_ARGS__) ); \
|
||||
funcobj->callback(funcobj M_MAP3(M_FUNC0BJ_BASE_ARGCALL, name, __VA_ARGS__) ); \
|
||||
}
|
||||
|
||||
|
||||
/* Specialization of the definition a function object instance of name 'name'
|
||||
* with no member attribute.
|
||||
*/
|
||||
#define FUNCOBJI_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
|
||||
#define M_FUNC0BJ_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
} instance_t[1]; \
|
||||
@@ -223,7 +220,7 @@
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
M_MAP3(M_FUNC0BJ_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
@@ -261,74 +258,76 @@
|
||||
* with mandatory member attribute.
|
||||
* First inject oplist in member attributes.
|
||||
*/
|
||||
#define FUNCOBJI_INS_ATTR_DEF(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
M_FUNC0BJ_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, M_FUNC0BJ_INJECT_GLOBAL(__VA_ARGS__) )
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define FUNCOBJI_INJECT_GLOBAL(...) \
|
||||
M_MAP_C(FUNCOBJI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
#define M_FUNC0BJ_INJECT_GLOBAL(...) \
|
||||
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 FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
FUNCOBJI_INJECT_OPLIST_B duo_or_trio
|
||||
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
|
||||
#define M_FUNC0BJ_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_FUNC0BJ_INJECT_OPLIST_B duo_or_trio
|
||||
#define M_FUNC0BJ_INJECT_OPLIST_B( f, ... ) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define FUNCOBJI_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(FUNCOBJI_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
#define M_FUNC0BJ_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(M_FUNC0BJ_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
// Test if the third argument is an oplist. a is a trio (name, type, oplist)
|
||||
#define FUNCOBJI_IS_OPLIST_P(a) \
|
||||
#define M_FUNC0BJ_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
FUNCOBJI_IF_ALL_OPLIST(__VA_ARGS__)(FUNCOBJI_INS_ATTR_DEF_P3, FUNCOBJI_INS_ATTR_DEF_FAILURE)(name, instance_t, base_name, param_list, callback_core, __VA_ARGS__)
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
M_FUNC0BJ_IF_ALL_OPLIST(__VA_ARGS__)(M_FUNC0BJ_INS_ATTR_DEF_P3, M_FUNC0BJ_INS_ATTR_DEF_FAILURE)(name, instance_t, base_name, param_list, callback_core, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_FAILURE(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF_FAILURE(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(FUNC_OBJ_INS_DEF): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
|
||||
|
||||
/* Expand the Function Object with members */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
#define M_FUNC0BJ_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
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_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list) \
|
||||
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_C(name, _s) *self = (struct M_C(name, _s) *)(void*)__self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
M_C(name, _init_with)(instance_t obj M_MAP(M_FUNC0BJ_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
@@ -337,66 +336,73 @@
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
M_IF(M_FUNC0BJ_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
M_MAP(M_FUNC0BJ_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
} \
|
||||
, /* END OF INIT METHOD */ ) \
|
||||
|
||||
|
||||
|
||||
/* Define a numbered type of a parameter of the callback*/
|
||||
#define FUNCOBJI_BASE_TYPE(name, num, type) \
|
||||
#define M_FUNC0BJ_BASE_TYPE(name, num, type) \
|
||||
typedef type M_C4(name, _param_, num, _ct);
|
||||
|
||||
/* Define a list of the type of arguments for a function definition */
|
||||
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
|
||||
#define M_FUNC0BJ_BASE_ARGLIST(name, num, type) \
|
||||
M_DEFERRED_COMMA type M_C(param_, num)
|
||||
|
||||
/* Define a list of arguments for a function call */
|
||||
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
|
||||
#define M_FUNC0BJ_BASE_ARGCALL(name, num, type) \
|
||||
M_DEFERRED_COMMA M_C(param_, num)
|
||||
|
||||
|
||||
/* Helper macros */
|
||||
/* arg = (name, type [, oplist]) */
|
||||
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_STRUCT(arg) \
|
||||
M_RET_ARG2 arg M_RET_ARG1 arg;
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_LIST(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_LIST(arg) \
|
||||
M_DEFERRED_COMMA M_RET_ARG2 arg const M_RET_ARG1 arg
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_INIT(arg) \
|
||||
M_CALL_INIT(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_INIT_SET(arg) \
|
||||
M_CALL_INIT_SET(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg, M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
|
||||
#define M_FUNC0BJ_INS_ATTR_CLEAR(arg) \
|
||||
M_CALL_CLEAR(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
/* Define the list of arguments of the instance of the callback */
|
||||
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
|
||||
#define M_FUNC0BJ_INS_ARGLIST(name, num, param) \
|
||||
M_DEFERRED_COMMA M_C4(name, _param_, num, _ct) param
|
||||
|
||||
|
||||
/* Macros for testing for a method presence in all the attributes */
|
||||
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
|
||||
#define M_FUNC0BJ_TEST_METHOD2_P(method, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
|
||||
M_APPLY(FUNCOBJI_TEST_METHOD2_P, method, M_RET_ARG3 arg)
|
||||
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
|
||||
M_IF(M_REDUCE2(FUNCOBJI_TEST_METHOD1_P, M_AND, method, __VA_ARGS__))
|
||||
#define M_FUNC0BJ_TEST_METHOD1_P(method, arg) \
|
||||
M_APPLY(M_FUNC0BJ_TEST_METHOD2_P, method, M_RET_ARG3 arg)
|
||||
#define M_FUNC0BJ_TEST_METHOD_P(method, ...) \
|
||||
M_IF(M_REDUCE2(M_FUNC0BJ_TEST_METHOD1_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
/* Macro for checking compatible type and oplist for all the attributes */
|
||||
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(FUNCOBJI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
|
||||
#define M_FUNC0BJ_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(M_FUNC0BJ_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define M_FUNC0BJ_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
|
||||
|
||||
#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
|
||||
+77
-79
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Integer Generator (GENINT) module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* GENINT is a container providing unique integers.
|
||||
/* GENINT is an internal container providing unique integers.
|
||||
It has the following properties:
|
||||
- it stores integer from [0..N) (N is fixed).
|
||||
- an integer can have only one occurrence in the container.
|
||||
@@ -39,64 +39,62 @@ M_BEGIN_PROTECTED_CODE
|
||||
- there are no order (like FIFO or stack)
|
||||
|
||||
This can be used to map integers to index of resources in a table.
|
||||
At most we can support N = 2048 with the master limb usage.
|
||||
At most we can support N = 32*64 = 2048 with the master limb usage.
|
||||
For the typical usage of this container
|
||||
(mapping hardware or software limited resources), this should be
|
||||
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
|
||||
#define GENINT_MAX_ALLOC (GENINT_LIMBSIZE * (GENINT_LIMBSIZE - GENINT_ABA_CPT))
|
||||
// Define the max absolute supported value. It should be 2048 on most implementations.
|
||||
#define M_GENINT_MAX_ALLOC (M_GEN1NT_LIMBSIZE * (M_GEN1NT_LIMBSIZE - M_GEN1NT_ABA_CPT))
|
||||
|
||||
// Define the size of a limb in bits.
|
||||
#define GENINT_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 GENINT_CONTRACT(s) do { \
|
||||
#define M_GEN1NT_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
M_ASSERT ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
|
||||
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 GENINT_ONE ((genint_limb_ct)1)
|
||||
#define M_GEN1NT_ONE ((m_genint_limb_ct)1)
|
||||
|
||||
#define GENINT_FULL_MASK ULLONG_MAX
|
||||
#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
|
||||
*/
|
||||
#define GENINT_ABA_CPT 32
|
||||
#define GENINT_ABA_CPT_T uint32_t
|
||||
#define M_GEN1NT_ABA_CPT 32
|
||||
#define M_GEN1NT_ABA_CPT_T uint32_t
|
||||
|
||||
// Set the bit 'i' of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_SET(master, i) \
|
||||
((((master)& (~((GENINT_ONE<< GENINT_ABA_CPT)-1))) | (GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
#define M_GEN1NT_MASTER_SET(master, i) \
|
||||
((((master)& (~((M_GEN1NT_ONE<< M_GEN1NT_ABA_CPT)-1))) | (M_GEN1NT_ONE << (M_GEN1NT_LIMBSIZE - 1 - i))) \
|
||||
|((M_GEN1NT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
// Reset the bit i of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
#define M_GEN1NT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((M_GEN1NT_ONE<< M_GEN1NT_ABA_CPT)-1)) & ~(M_GEN1NT_ONE << (M_GEN1NT_LIMBSIZE - 1 - i))) \
|
||||
|((M_GEN1NT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
/* Initialize an integer generator (CONSTRUCTOR).
|
||||
* Initialy, the container is full of all the integers up to 'n-1'
|
||||
@@ -106,11 +104,11 @@ typedef struct genint_s {
|
||||
* for all threads.
|
||||
*/
|
||||
static inline void
|
||||
genint_init(genint_t s, unsigned int n)
|
||||
m_genint_init(m_genint_t s, unsigned int n)
|
||||
{
|
||||
M_ASSERT (s != NULL && n > 0 && n <= GENINT_MAX_ALLOC);
|
||||
const size_t alloc = (n + GENINT_LIMBSIZE - 1) / GENINT_LIMBSIZE;
|
||||
const unsigned int index = n % GENINT_LIMBSIZE;
|
||||
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)) {
|
||||
M_MEMORY_FULL(alloc);
|
||||
@@ -119,73 +117,73 @@ genint_init(genint_t s, unsigned int n)
|
||||
s->n = n;
|
||||
s->data = ptr;
|
||||
s->max = (unsigned int) (alloc-1);
|
||||
s->mask0 = (index == 0) ? GENINT_FULL_MASK : ~((GENINT_ONE<<(GENINT_LIMBSIZE-index))-1);
|
||||
s->mask_master = (((GENINT_ONE << alloc) - 1) << (GENINT_LIMBSIZE-alloc)) >> GENINT_ABA_CPT;
|
||||
atomic_init (&s->master, (genint_limb_ct)0);
|
||||
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, (m_genint_limb_ct)0);
|
||||
for(unsigned int i = 0; i < alloc; i++)
|
||||
atomic_init(&s->data[i], (genint_limb_ct)0);
|
||||
GENINT_CONTRACT(s);
|
||||
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_genint_clear(m_genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_MEMORY_FREE(s->data);
|
||||
s->data = NULL;
|
||||
}
|
||||
|
||||
/* Return the maximum integer that the generator will provide */
|
||||
static inline size_t
|
||||
genint_size(genint_t s)
|
||||
m_genint_size(m_genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return s->n;
|
||||
}
|
||||
|
||||
/* 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_genint_pop(m_genint_t s)
|
||||
{
|
||||
GENINT_CONTRACT(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 >> GENINT_ABA_CPT) != s->mask_master) {
|
||||
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 < GENINT_LIMBSIZE);
|
||||
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;
|
||||
mask = (i == s->max) ? mask : GENINT_FULL_MASK;
|
||||
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))
|
||||
goto next_element;
|
||||
M_ASSERT (org != GENINT_FULL_MASK);
|
||||
M_ASSERT (org != M_GEN1NT_FULL_MASK);
|
||||
// At least one bit is free in the limb. Find one.
|
||||
bit = GENINT_LIMBSIZE - 1 - m_core_clz64(~org);
|
||||
M_ASSERT (bit < GENINT_LIMBSIZE);
|
||||
M_ASSERT ((org & (GENINT_ONE<<bit)) == 0);
|
||||
M_ASSERT (i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit < s->n);
|
||||
bit = M_GEN1NT_LIMBSIZE - 1 - m_core_clz64(~org);
|
||||
M_ASSERT (bit < M_GEN1NT_LIMBSIZE);
|
||||
M_ASSERT ((org & (M_GEN1NT_ONE<<bit)) == 0);
|
||||
M_ASSERT (i * M_GEN1NT_LIMBSIZE + M_GEN1NT_LIMBSIZE - 1 - bit < s->n);
|
||||
// Set the integer as being used.
|
||||
next = org | (GENINT_ONE << bit);
|
||||
next = org | (M_GEN1NT_ONE << bit);
|
||||
// Try to reserve the integer
|
||||
} while (!atomic_compare_exchange_weak (&s->data[i], &org, next));
|
||||
// We have reserved the integer.
|
||||
// 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 = GENINT_MASTER_SET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
newMaster = GENINT_MASTER_RESET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_RESET(master, i);
|
||||
}
|
||||
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
|
||||
break;
|
||||
@@ -194,46 +192,46 @@ genint_pop(genint_t s)
|
||||
}
|
||||
}
|
||||
// Return the new number
|
||||
GENINT_CONTRACT(s);
|
||||
return i * GENINT_LIMBSIZE + GENINT_LIMBSIZE - 1 - bit;
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
return i * M_GEN1NT_LIMBSIZE + M_GEN1NT_LIMBSIZE - 1 - bit;
|
||||
next_element:
|
||||
// Reload master
|
||||
master = atomic_load(&s->master);
|
||||
}
|
||||
GENINT_CONTRACT(s);
|
||||
return GENINT_ERROR; // No more resource available
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
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_genint_push(m_genint_t s, unsigned int n)
|
||||
{
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
M_ASSERT (n < s->n);
|
||||
const unsigned int i = n / GENINT_LIMBSIZE;
|
||||
const unsigned int bit = GENINT_LIMBSIZE - 1 - (n % GENINT_LIMBSIZE);
|
||||
genint_limb_ct master = atomic_load(&s->master);
|
||||
const unsigned int i = n / M_GEN1NT_LIMBSIZE;
|
||||
const unsigned int bit = M_GEN1NT_LIMBSIZE - 1 - (n % M_GEN1NT_LIMBSIZE);
|
||||
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 & (GENINT_ONE << bit)) != 0);
|
||||
M_ASSERT ((org & (M_GEN1NT_ONE << bit)) != 0);
|
||||
// Reset it
|
||||
next = org & (~(GENINT_ONE << bit));
|
||||
next = org & (~(M_GEN1NT_ONE << bit));
|
||||
// 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;
|
||||
mask = (i == s->max) ? mask : GENINT_FULL_MASK;
|
||||
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 = GENINT_MASTER_SET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_SET(master, i);
|
||||
} else {
|
||||
newMaster = GENINT_MASTER_RESET(master, i);
|
||||
newMaster = M_GEN1NT_MASTER_RESET(master, i);
|
||||
}
|
||||
if (atomic_compare_exchange_weak (&s->master, &master, newMaster))
|
||||
break;
|
||||
@@ -241,7 +239,7 @@ genint_push(genint_t s, unsigned int n)
|
||||
next = atomic_load(&s->data[i]);
|
||||
}
|
||||
}
|
||||
GENINT_CONTRACT(s);
|
||||
M_GEN1NT_CONTRACT(s);
|
||||
}
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
+128
-122
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Intrusive List module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -26,7 +26,7 @@
|
||||
#define MSTARLIB_I_LIST_H
|
||||
|
||||
#include "m-core.h"
|
||||
#include "m-list.h" // For LISTI_ITBASE_DEF
|
||||
#include "m-list.h" // For M_L1ST_ITBASE_DEF
|
||||
|
||||
/* Interface to add to a structure to enable intrusive doubly-linked support.
|
||||
name: name of the intrusive list.
|
||||
@@ -38,20 +38,16 @@
|
||||
...
|
||||
} tmp_str_t;
|
||||
*/
|
||||
#define ILIST_INTERFACE(name, type) \
|
||||
struct 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, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ILISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name, _t), M_C(name, _it_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_ILIST_DEF(name, ...) \
|
||||
M_ILIST_DEF_AS(name, M_C(name,_t), M_C(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a doubly-linked intrusive list of a given type
|
||||
@@ -59,9 +55,9 @@
|
||||
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 \
|
||||
ILISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_IL1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -70,39 +66,40 @@
|
||||
/* Define the oplist of a doubly-linked instrusive list of type.
|
||||
USAGE:
|
||||
ILIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ILIST_OPLIST(...) \
|
||||
ILISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define M_ILIST_OPLIST(...) \
|
||||
M_IL1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Define the basic structure to be added in all objects. */
|
||||
typedef struct ilist_head_s {
|
||||
struct ilist_head_s *next;
|
||||
struct ilist_head_s *prev;
|
||||
} 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 ILISTI_OPLIST_P1(arg) ILISTI_OPLIST_P2 arg
|
||||
#define M_IL1ST_OPLIST_P1(arg) M_IL1ST_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ILISTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ILISTI_OPLIST_P3, ILISTI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_IL1ST_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_IL1ST_OPLIST_P3, M_IL1ST_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ILISTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_IL1ST_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_ILIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* Define the oplist of an ilist of type */
|
||||
#define ILISTI_OPLIST_P3(name, oplist) \
|
||||
#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)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
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)), \
|
||||
@@ -126,7 +123,7 @@ typedef struct ilist_head_s {
|
||||
)
|
||||
|
||||
/* Contract respected by all intrusive lists */
|
||||
#define ILISTI_CONTRACT(name, list) do { \
|
||||
#define M_IL1ST_CONTRACT(name, list) do { \
|
||||
M_ASSERT(list != NULL); \
|
||||
M_ASSERT(list->name.prev != NULL); \
|
||||
M_ASSERT(list->name.next != NULL); \
|
||||
@@ -135,7 +132,7 @@ typedef struct ilist_head_s {
|
||||
M_ASSERT(!(list->name.prev == &list->name) || list->name.prev == list->name.next); \
|
||||
} while (0)
|
||||
|
||||
#define ILISTI_NODE_CONTRACT(node) do { \
|
||||
#define M_IL1ST_NODE_CONTRACT(node) do { \
|
||||
M_ASSERT((node) != NULL); \
|
||||
M_ASSERT((node)->prev != NULL); \
|
||||
M_ASSERT((node)->next != NULL); \
|
||||
@@ -143,15 +140,15 @@ typedef struct ilist_head_s {
|
||||
M_ASSERT((node)->prev->next == node); \
|
||||
} while (0)
|
||||
|
||||
/* Indirection call to allow expanding all arguments (TBC) */
|
||||
#define ILISTI_DEF_P1(arg) ILISTI_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 ILISTI_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(ILISTI_DEF_P3, ILISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
#define M_IL1ST_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_IL1ST_DEF_P3, M_IL1ST_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ILISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
#define M_IL1ST_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ILIST_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Definition of the type and function for an intrusive doubly-linked list.
|
||||
@@ -162,12 +159,12 @@ typedef struct ilist_head_s {
|
||||
list_t: type of the intrusive list (name##_t)
|
||||
it_t: iterator of the intrusive list (name##_it_t)
|
||||
*/
|
||||
#define ILISTI_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
#define M_IL1ST_DEF_P3(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 ilist_head_s name; \
|
||||
struct m_il1st_head_s name; \
|
||||
} list_t[1]; \
|
||||
\
|
||||
/* Define internal types pointers to such a list */ \
|
||||
@@ -176,10 +173,10 @@ typedef struct ilist_head_s {
|
||||
\
|
||||
/* Define iterator of such a list */ \
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
struct ilist_head_s *head; \
|
||||
struct ilist_head_s *previous; \
|
||||
struct ilist_head_s *current; \
|
||||
struct ilist_head_s *next; \
|
||||
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 */ \
|
||||
@@ -195,18 +192,18 @@ typedef struct ilist_head_s {
|
||||
M_ASSERT (list != NULL); \
|
||||
list->name.next = &list->name; \
|
||||
list->name.prev = &list->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t list) \
|
||||
M_C(name, _reset)(list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
for(struct ilist_head_s *it = list->name.next, *next ; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
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 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,14 +214,14 @@ typedef struct ilist_head_s {
|
||||
/* Nothing remains in the list anymore */ \
|
||||
list->name.next = &list->name; \
|
||||
list->name.prev = &list->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t list) \
|
||||
{ \
|
||||
/* Nothing to do more than clean the list itself */ \
|
||||
M_C(name, _clean)(list); \
|
||||
M_C(name, _reset)(list); \
|
||||
/* For safety purpose (create invalid represenation of object) */ \
|
||||
list->name.next = NULL; \
|
||||
list->name.prev = NULL; \
|
||||
@@ -233,7 +230,7 @@ typedef struct ilist_head_s {
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
return list->name.next == &list->name; \
|
||||
} \
|
||||
\
|
||||
@@ -241,7 +238,7 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t ref) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, ref); \
|
||||
M_IL1ST_CONTRACT(name, ref); \
|
||||
M_ASSERT (list != ref); \
|
||||
M_C(name,_init)(list); \
|
||||
if (!M_C(name,_empty_p)(ref)) { \
|
||||
@@ -252,7 +249,7 @@ typedef struct ilist_head_s {
|
||||
} \
|
||||
ref->name.next = NULL; \
|
||||
ref->name.prev = NULL; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -265,12 +262,12 @@ typedef struct ilist_head_s {
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
size_t s = 0; \
|
||||
/* Scan the full list to count the number of elements */ \
|
||||
for(const struct ilist_head_s *it = list->name.next ; \
|
||||
for(const struct m_il1st_head_s *it = list->name.next ; \
|
||||
it != &list->name; it = it->next) { \
|
||||
ILISTI_NODE_CONTRACT(it); \
|
||||
M_IL1ST_NODE_CONTRACT(it); \
|
||||
s++; \
|
||||
} \
|
||||
return s; \
|
||||
@@ -279,27 +276,27 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _push_back)(list_t list, type *obj) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct 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; \
|
||||
prev->next = &obj->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_front)(list_t list, type *obj) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
struct 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; \
|
||||
next->prev = &obj->name; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -307,8 +304,8 @@ typedef struct ilist_head_s {
|
||||
{ \
|
||||
M_ASSERT (obj_pos != NULL && obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
ILISTI_NODE_CONTRACT(&obj_pos->name); \
|
||||
struct ilist_head_s *next = obj_pos->name.next; \
|
||||
M_IL1ST_NODE_CONTRACT(&obj_pos->name); \
|
||||
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; \
|
||||
@@ -329,9 +326,9 @@ typedef struct ilist_head_s {
|
||||
{ \
|
||||
M_ASSERT (obj != NULL); \
|
||||
/* We don't have the list, so we have no contract at list level */ \
|
||||
ILISTI_NODE_CONTRACT(&obj->name); \
|
||||
struct ilist_head_s *next = obj->name.next; \
|
||||
struct ilist_head_s *prev = obj->name.prev; \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
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,53 +339,53 @@ typedef struct ilist_head_s {
|
||||
static inline type * \
|
||||
M_C(name, _back)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.prev, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _front)(const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT(!M_C(name, _empty_p)(list)); \
|
||||
return M_TYPE_FROM_FIELD(type, list->name.next, \
|
||||
struct 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) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
ILISTI_NODE_CONTRACT(&obj->name); \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.next == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.next, \
|
||||
struct 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) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (obj != NULL); \
|
||||
ILISTI_NODE_CONTRACT(&obj->name); \
|
||||
M_IL1ST_NODE_CONTRACT(&obj->name); \
|
||||
return obj->name.prev == &list->name ? NULL : \
|
||||
M_TYPE_FROM_FIELD(type, obj->name.prev, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->head = list->name.next->prev; \
|
||||
it->current = list->name.next; \
|
||||
it->next = list->name.next->next; \
|
||||
it->previous = it->head; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -399,19 +396,19 @@ typedef struct ilist_head_s {
|
||||
it->current = cit->current; \
|
||||
it->next = cit->next; \
|
||||
it->previous = cit->previous; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, list_t const list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->head = list->name.next->prev; \
|
||||
it->current = list->name.prev; \
|
||||
it->next = it->head; \
|
||||
it->previous = list->name.prev->prev; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -422,14 +419,14 @@ typedef struct ilist_head_s {
|
||||
it->current = it->head; \
|
||||
it->next = list->name.next; \
|
||||
it->previous = list->name.prev; \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
return it->current == it->head; \
|
||||
} \
|
||||
\
|
||||
@@ -437,7 +434,7 @@ typedef struct ilist_head_s {
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
return it->next == it->head || it->current == it->head; \
|
||||
} \
|
||||
\
|
||||
@@ -453,7 +450,7 @@ typedef struct ilist_head_s {
|
||||
it->next = it->current->next; \
|
||||
it->previous = it->current->prev; \
|
||||
M_ASSERT (it->next != NULL && it->previous != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -468,7 +465,7 @@ typedef struct ilist_head_s {
|
||||
it->next = it->current->next; \
|
||||
it->previous = it->current->prev; \
|
||||
M_ASSERT (it->next != NULL && it->previous != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
@@ -483,13 +480,13 @@ typedef struct ilist_head_s {
|
||||
M_C(name, _ref)(const it_t it) \
|
||||
{ \
|
||||
M_ASSERT (it != NULL && it->current != NULL); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
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)); \
|
||||
return M_TYPE_FROM_FIELD(type, it->current, \
|
||||
struct ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
@@ -502,23 +499,23 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, it_t it) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
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 ilist_head_s, name); \
|
||||
struct m_il1st_head_s, name); \
|
||||
M_C(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_IF_METHOD(NEW, oplist)( \
|
||||
M_IF_METHOD2(NEW, INIT_SET, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _insert)(list_t list, it_t it, type x) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_IL1ST_NODE_CONTRACT(it->current); \
|
||||
type *p = M_CALL_NEW(oplist, type); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
M_MEMORY_FULL (sizeof (type)); \
|
||||
@@ -529,14 +526,14 @@ typedef struct ilist_head_s {
|
||||
M_C(name, _push_after)(obj, p); \
|
||||
it->current = p; \
|
||||
(void) list; \
|
||||
ILISTI_CONTRACT(name, 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) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (!M_C(name, _empty_p)(list)); \
|
||||
type *obj = M_C(name, _back)(list); \
|
||||
list->name.prev = list->name.prev->prev; \
|
||||
@@ -547,7 +544,7 @@ typedef struct ilist_head_s {
|
||||
static inline type * \
|
||||
M_C(name, _pop_front)(list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
M_ASSERT (!M_C(name, _empty_p)(list)); \
|
||||
type *obj = M_C(name, _front)(list); \
|
||||
list->name.next = list->name.next->next; \
|
||||
@@ -558,52 +555,52 @@ typedef struct ilist_head_s {
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list1); \
|
||||
ILISTI_CONTRACT(name, list2); \
|
||||
struct ilist_head_s *midle1 = list1->name.prev; \
|
||||
struct ilist_head_s *midle2 = list2->name.next; \
|
||||
M_IL1ST_CONTRACT(name, list1); \
|
||||
M_IL1ST_CONTRACT(name, list2); \
|
||||
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; \
|
||||
list2->name.prev->next = &list1->name; \
|
||||
list2->name.next = &list2->name; \
|
||||
list2->name.prev = &list2->name; \
|
||||
ILISTI_CONTRACT(name, list1); \
|
||||
ILISTI_CONTRACT(name, list2); \
|
||||
M_IL1ST_CONTRACT(name, list1); \
|
||||
M_IL1ST_CONTRACT(name, list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, nv); \
|
||||
ILISTI_CONTRACT(name, ov); \
|
||||
ILISTI_NODE_CONTRACT(it->current); \
|
||||
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); \
|
||||
ILISTI_CONTRACT(name, nv); \
|
||||
ILISTI_CONTRACT(name, ov); \
|
||||
M_IL1ST_CONTRACT(name, nv); \
|
||||
M_IL1ST_CONTRACT(name, ov); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
list_t olist, it_t opos) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, nlist); \
|
||||
ILISTI_CONTRACT(name, olist); \
|
||||
M_IL1ST_CONTRACT(name, nlist); \
|
||||
M_IL1ST_CONTRACT(name, olist); \
|
||||
M_ASSERT (npos != NULL && opos != NULL); \
|
||||
M_ASSERT (!M_C(name, _end_p)(opos)); \
|
||||
/* npos may be end */ \
|
||||
(void) olist, (void) nlist; \
|
||||
type *obj = M_C(name, _ref)(opos); \
|
||||
struct ilist_head_s *ref = npos->current; \
|
||||
struct m_il1st_head_s *ref = npos->current; \
|
||||
/* Remove object */ \
|
||||
M_C(name, _unlink)(obj); \
|
||||
/* Push 'obj' after 'ref' */ \
|
||||
struct 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; \
|
||||
@@ -614,17 +611,19 @@ typedef struct ilist_head_s {
|
||||
npos->previous = ref; \
|
||||
npos->current = &obj->name; \
|
||||
npos->next = next; \
|
||||
ILISTI_CONTRACT(name, nlist); \
|
||||
ILISTI_CONTRACT(name, olist); \
|
||||
M_IL1ST_CONTRACT(name, nlist); \
|
||||
M_IL1ST_CONTRACT(name, olist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t d, list_t e) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, d); \
|
||||
ILISTI_CONTRACT(name, e); \
|
||||
struct ilist_head_s *d_item = d->name.next; \
|
||||
struct ilist_head_s *e_item = e->name.next; \
|
||||
M_IL1ST_CONTRACT(name, d); \
|
||||
M_IL1ST_CONTRACT(name, e); \
|
||||
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; \
|
||||
e->name.next = d_item == &d->name ? &e->name : d_item; \
|
||||
d_item = d->name.prev; \
|
||||
@@ -635,15 +634,15 @@ typedef struct ilist_head_s {
|
||||
d->name.prev->next = &d->name; \
|
||||
e->name.next->prev = &e->name; \
|
||||
e->name.prev->next = &e->name; \
|
||||
ILISTI_CONTRACT(name, d); \
|
||||
ILISTI_CONTRACT(name, e); \
|
||||
M_IL1ST_CONTRACT(name, d); \
|
||||
M_IL1ST_CONTRACT(name, e); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
struct ilist_head_s *next, *it; \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
struct m_il1st_head_s *next, *it; \
|
||||
for(it = list->name.next ; it != &list->name; it = next) { \
|
||||
next = it->next; \
|
||||
it->next = it->prev; \
|
||||
@@ -652,11 +651,18 @@ typedef struct ilist_head_s {
|
||||
next = it->next; \
|
||||
it->next = it->prev; \
|
||||
it->prev = next; \
|
||||
ILISTI_CONTRACT(name, list); \
|
||||
M_IL1ST_CONTRACT(name, list); \
|
||||
} \
|
||||
\
|
||||
/* Used of macro from m-list */ \
|
||||
LISTI_ITBASE_DEF(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)
|
||||
|
||||
|
||||
#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
|
||||
+33
-27
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - INTRUSIVE SHARED PTR Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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(...) \
|
||||
ISHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define M_ISHARED_PTR_OPLIST(...) \
|
||||
M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -42,35 +42,31 @@ 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) \
|
||||
#define M_ISHARED_PTR_INTERFACE(name, type) \
|
||||
atomic_int M_C(name, _cpt)
|
||||
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C99 designated element). */
|
||||
#define ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
|
||||
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C89 designated element). */
|
||||
#define ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
ATOMIC_VAR_INIT(0)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_ISHARED_PTR_DEF(name, ...) \
|
||||
M_ISHARED_PTR_DEF_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static 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 \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -79,23 +75,24 @@ M_BEGIN_PROTECTED_CODE
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// Deferred evaluation
|
||||
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
|
||||
#define M_ISHAR3D_PTR_OPLIST_P1(arg) M_ISHAR3D_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_OPLIST_P3, ISHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_ISHAR3D_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_OPLIST_P3, M_ISHAR3D_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_ISHAR3D_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
// Define the oplist
|
||||
#define ISHAREDI_PTR_OPLIST_P3(name, 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)), \
|
||||
CLEAN(M_C(name, _clean) M_IPTR), \
|
||||
RESET(M_C(name, _reset) M_IPTR), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
@@ -105,17 +102,17 @@ M_BEGIN_PROTECTED_CODE
|
||||
)
|
||||
|
||||
// Deferred evaluatioin
|
||||
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_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 ISHAREDI_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
|
||||
#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_DEF_P3, M_ISHAR3D_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
|
||||
#define M_ISHAR3D_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define ISHAREDI_PTR_DEF_P3(name, type, oplist, shared_t) \
|
||||
#define M_ISHAR3D_PTR_DEF_P3(name, type, oplist, shared_t) \
|
||||
\
|
||||
/* The shared pointer is only a pointer to the type */ \
|
||||
typedef type *shared_t; \
|
||||
@@ -216,7 +213,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t *shared) \
|
||||
M_C(name, _reset)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
@@ -235,4 +232,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#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 - LIST module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,20 +29,16 @@
|
||||
|
||||
/* Define a singly linked list of a given type.
|
||||
USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
LISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_LIST_DEF(name, ...) \
|
||||
M_LIST_DEF_AS(name, M_C(name, _t), M_C(name, _it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a singly linked list of a given type
|
||||
as the provided type name_t with the iterator named it_t
|
||||
USAGE: LIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define LIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_LIST_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
LISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_L1ST_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -50,20 +46,16 @@
|
||||
|
||||
/* Define a singly linked list of a given type allowing both push.
|
||||
USAGE: LIST_DUAL_PUSH_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
LISTI_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name, _it_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_LIST_DUAL_PUSH_DEF(name, ...) \
|
||||
M_LIST_DUAL_PUSH_DEF_AS(name, M_C(name,_t), M_C(name, _it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a singly linked list of a given type allowing both push.
|
||||
as the provided type name_t with the iterator named it_t
|
||||
USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
|
||||
#define M_LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
LISTI_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_L1ST_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -71,36 +63,52 @@
|
||||
|
||||
/* Define the oplist of a list of the given type.
|
||||
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define LIST_OPLIST(...) \
|
||||
LISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
#define M_LIST_OPLIST(...) \
|
||||
M_L1ST_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
/* Define an init value to init global variables of type list.
|
||||
USAGE:
|
||||
list_t global_variable = LIST_INIT_VALUE();
|
||||
*/
|
||||
#define M_LIST_INIT_VALUE() \
|
||||
{ NULL }
|
||||
|
||||
|
||||
/* Define an init value to init global variables of type dual push list.
|
||||
USAGE:
|
||||
list_t global_variable = LIST_DUAL_PUSH_INIT_VALUE();
|
||||
*/
|
||||
#define M_LIST_DUAL_PUSH_INIT_VALUE() \
|
||||
{ { NULL, NULL } }
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Deferred evaluation for the oplist definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_OPLIST_P1(arg) LISTI_OPLIST_P2 arg
|
||||
#define M_L1ST_OPLIST_P1(arg) M_L1ST_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define LISTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(LISTI_OPLIST_P3, LISTI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_L1ST_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_L1ST_OPLIST_P3, M_L1ST_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define LISTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_L1ST_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_LIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* OPLIST definition of a list and list_dual_push */
|
||||
#define LISTI_OPLIST_P3(name, oplist) \
|
||||
#define M_L1ST_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(API_1(M_INIT_VAI)), \
|
||||
INIT_WITH(API_1(M_INIT_WITH_VAI)), \
|
||||
SET(M_C(name, _set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
SWAP(M_C(name, _swap)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
SUBTYPE(M_C(name,_subtype_ct)), \
|
||||
EMPTY_P(M_C(name,_empty_p)), \
|
||||
@@ -116,7 +124,7 @@
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
IT_INSERT(M_C(name, _insert)), \
|
||||
IT_REMOVE(M_C(name,_remove)), \
|
||||
CLEAN(M_C(name,_clean)), \
|
||||
RESET(M_C(name,_reset)), \
|
||||
PUSH(M_C(name,_push_back)), \
|
||||
POP(M_C(name,_pop_back)), \
|
||||
PUSH_MOVE(M_C(name,_push_move)), \
|
||||
@@ -140,35 +148,35 @@
|
||||
|
||||
/* Deferred evaluation for the list definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_DEF_P1(arg) LISTI_DEF_P2 arg
|
||||
#define M_L1ST_DEF_P1(arg) M_ID( M_L1ST_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define LISTI_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(LISTI_DEF_P3, LISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
#define M_L1ST_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_L1ST_DEF_P3, M_L1ST_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define LISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Define allocation functions. If MEMPOOL, we need to define it */
|
||||
#define LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
#define M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
|
||||
M_IF_METHOD(MEMPOOL, oplist)( \
|
||||
\
|
||||
MEMPOOL_DEF(M_C(name, _mempool), struct M_C(name, _s)) \
|
||||
M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \
|
||||
static inline struct M_C(name, _s) *M_C(name, _int_new)(void) { \
|
||||
static inline struct M_C(name, _s) *M_C3(m_l1st_,name,_new)(void) { \
|
||||
return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \
|
||||
static inline void M_C3(m_l1st_,name,_del)(struct M_C(name, _s) *ptr) { \
|
||||
M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
|
||||
} \
|
||||
\
|
||||
, /* No mempool allocation */ \
|
||||
\
|
||||
static inline struct M_C(name, _s) *M_C(name, _int_new)(void) { \
|
||||
static inline struct M_C(name, _s) *M_C3(m_l1st_,name,_new)(void) { \
|
||||
return M_CALL_NEW(oplist, struct M_C(name, _s)); \
|
||||
} \
|
||||
static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \
|
||||
static inline void M_C3(m_l1st_,name,_del)(struct M_C(name, _s) *ptr) { \
|
||||
M_CALL_DEL(oplist, ptr); \
|
||||
} \
|
||||
) \
|
||||
@@ -182,7 +190,7 @@
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
- node_t: alias for M_C(name, _node_t) [ node ]
|
||||
*/
|
||||
#define LISTI_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Define the node of a list, and the list as a pointer to a node */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
@@ -205,14 +213,14 @@
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
LISTI_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of a list
|
||||
(there is nothing worthy to be checked) */
|
||||
#define LISTI_CONTRACT(v) do { \
|
||||
#define M_L1ST_CONTRACT(v) do { \
|
||||
M_ASSERT (v != NULL); \
|
||||
} while (0)
|
||||
|
||||
@@ -224,7 +232,7 @@
|
||||
- list_t: alias for type of the container
|
||||
- it_t: alias for iterator of the container
|
||||
*/
|
||||
#define LISTI_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
@@ -234,40 +242,40 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
M_C(name, _reset)(list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
struct M_C(name, _s) *it = *v; \
|
||||
*v = NULL; \
|
||||
while (it != NULL) { \
|
||||
struct M_C(name, _s) *next = it->next; \
|
||||
M_CALL_CLEAR(oplist, it->data); \
|
||||
M_C(name,_int_del)(it); \
|
||||
M_C3(m_l1st_,name,_del)(it); \
|
||||
it = next; \
|
||||
} \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _clean)(v); \
|
||||
M_C(name, _reset)(v); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _back)(const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT(*v != NULL); \
|
||||
return M_CONST_CAST(type, &((*v)->data)); \
|
||||
return &((*v)->data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next; \
|
||||
next = M_C(name, _int_new)(); \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
@@ -275,7 +283,7 @@
|
||||
type *ret = &next->data; \
|
||||
next->next = *v; \
|
||||
*v = next; \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -303,7 +311,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT(*v != NULL); \
|
||||
if (data != NULL) { \
|
||||
M_DO_MOVE (oplist, *data, (*v)->data); \
|
||||
@@ -312,8 +320,8 @@
|
||||
} \
|
||||
struct M_C(name, _s) *tofree = *v; \
|
||||
*v = (*v)->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -329,38 +337,36 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT(*v != NULL && data != NULL); \
|
||||
M_DO_INIT_MOVE (oplist, *data, (*v)->data); \
|
||||
struct M_C(name, _s) *tofree = *v; \
|
||||
*v = (*v)->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
return *v == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t l, list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(l); \
|
||||
LISTI_CONTRACT(v); \
|
||||
struct M_C(name, _s) *tmp = *l; \
|
||||
*l = *v; \
|
||||
*v = tmp; \
|
||||
LISTI_CONTRACT(l); \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(l); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_SWAP(struct M_C(name, _s) *, *l, *v); \
|
||||
M_L1ST_CONTRACT(l); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->current = *v; \
|
||||
it->previous = NULL; \
|
||||
@@ -377,7 +383,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it1, const list_t v) \
|
||||
{ \
|
||||
LISTI_CONTRACT(v); \
|
||||
M_L1ST_CONTRACT(v); \
|
||||
M_ASSERT (it1 != NULL); \
|
||||
(void)v; /* unused */ \
|
||||
it1->current = NULL; \
|
||||
@@ -430,7 +436,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t list) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
size_t size = 0; \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
@@ -443,7 +449,7 @@
|
||||
static inline bool \
|
||||
M_C(name, _sublist_p)(const list_t list, const it_t itsub) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
M_ASSERT (itsub != NULL); \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
while (it != NULL) { \
|
||||
@@ -457,7 +463,7 @@
|
||||
static inline type * \
|
||||
M_C(name, _get)(const list_t list, size_t i) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
struct M_C(name, _s) *it = *list; \
|
||||
/* FIXME: How to avoid the double iteration over the list? */ \
|
||||
size_t len = M_C(name,_size)(list); \
|
||||
@@ -481,10 +487,10 @@
|
||||
M_C(name, _insert)(list_t list, it_t insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
M_ASSERT (insertion_point != NULL); \
|
||||
M_ASSERT(M_C(name, _sublist_p)(list, insertion_point)); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
@@ -500,13 +506,13 @@
|
||||
} \
|
||||
/* Update insertion_point to this element */ \
|
||||
insertion_point->current = next; \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, it_t removing_point) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
M_ASSERT (removing_point != NULL); \
|
||||
M_ASSERT (removing_point->current != NULL); \
|
||||
M_ASSERT(M_C(name, _sublist_p)(list, removing_point)); \
|
||||
@@ -517,21 +523,21 @@
|
||||
removing_point->previous->next = next; \
|
||||
} \
|
||||
M_CALL_CLEAR(oplist, removing_point->current->data); \
|
||||
M_C(name,_int_del) (removing_point->current); \
|
||||
M_C3(m_l1st_,name,_del) (removing_point->current); \
|
||||
removing_point->current = next; \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
LISTI_CONTRACT(org); \
|
||||
M_L1ST_CONTRACT(org); \
|
||||
struct M_C(name, _s) *next, *it_org; \
|
||||
struct M_C(name, _s) **update_list; \
|
||||
update_list = list; \
|
||||
it_org = *org; \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C(name, _int_new)(); \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
@@ -543,7 +549,7 @@
|
||||
it_org = it_org->next; \
|
||||
} \
|
||||
*update_list = NULL; \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -557,7 +563,7 @@
|
||||
static inline void \
|
||||
M_C(name, _init_move)(list_t list, list_t org) \
|
||||
{ \
|
||||
LISTI_CONTRACT(org); \
|
||||
M_L1ST_CONTRACT(org); \
|
||||
M_ASSERT (list != NULL && list != org); \
|
||||
*list = *org; \
|
||||
*org = NULL; /* safer */ \
|
||||
@@ -574,8 +580,8 @@
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \
|
||||
{ \
|
||||
LISTI_CONTRACT(nv); \
|
||||
LISTI_CONTRACT(ov); \
|
||||
M_L1ST_CONTRACT(nv); \
|
||||
M_L1ST_CONTRACT(ov); \
|
||||
M_ASSERT (it != NULL); \
|
||||
M_ASSERT (it->current != NULL); \
|
||||
M_ASSERT (M_C(name, _sublist_p)(ov, it)); \
|
||||
@@ -599,8 +605,8 @@
|
||||
M_C(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
list_t olist, it_t opos) \
|
||||
{ \
|
||||
LISTI_CONTRACT(nlist); \
|
||||
LISTI_CONTRACT(olist); \
|
||||
M_L1ST_CONTRACT(nlist); \
|
||||
M_L1ST_CONTRACT(olist); \
|
||||
M_ASSERT (npos != NULL); \
|
||||
M_ASSERT (opos != NULL); \
|
||||
M_ASSERT (M_C(name, _sublist_p)(nlist, npos)); \
|
||||
@@ -627,15 +633,15 @@
|
||||
/* Update 'npos' to point to the new current element */ \
|
||||
npos->previous = npos->current; \
|
||||
npos->current = current; \
|
||||
LISTI_CONTRACT(nlist); \
|
||||
LISTI_CONTRACT(olist); \
|
||||
M_L1ST_CONTRACT(nlist); \
|
||||
M_L1ST_CONTRACT(olist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list1); \
|
||||
LISTI_CONTRACT(list2); \
|
||||
M_L1ST_CONTRACT(list1); \
|
||||
M_L1ST_CONTRACT(list2); \
|
||||
M_ASSERT (list1 != list2); \
|
||||
struct M_C(name, _s) **update_list = list1; \
|
||||
struct M_C(name, _s) *it = *list1; \
|
||||
@@ -650,7 +656,7 @@
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
LISTI_CONTRACT(list); \
|
||||
M_L1ST_CONTRACT(list); \
|
||||
struct M_C(name, _s) *previous = NULL, *it = *list, *next; \
|
||||
while (it != NULL) { \
|
||||
next = it->next; \
|
||||
@@ -660,6 +666,8 @@
|
||||
} \
|
||||
*list = previous; \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF)
|
||||
|
||||
|
||||
/* Internal list function definition using only iterator functions
|
||||
@@ -672,15 +680,15 @@
|
||||
- list_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
*/
|
||||
#define LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, const list_t list, \
|
||||
M_C(name, _get_str)(m_string_t str, const list_t list, \
|
||||
bool append) \
|
||||
{ \
|
||||
M_ASSERT (str != NULL && list != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "["); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
it_t it; \
|
||||
for (M_C(name, _it)(it, list) ; \
|
||||
!M_C(name, _end_p)(it); \
|
||||
@@ -688,9 +696,9 @@
|
||||
type const *item = M_C(name, _cref)(it); \
|
||||
M_CALL_GET_STR(oplist, str, *item, true); \
|
||||
if (!M_C(name, _last_p)(it)) \
|
||||
string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
m_string_push_back (str, M_GET_SEPARATOR oplist); \
|
||||
} \
|
||||
string_push_back (str, ']'); \
|
||||
m_string_push_back (str, ']'); \
|
||||
} \
|
||||
, /* no str */ ) \
|
||||
\
|
||||
@@ -718,7 +726,7 @@
|
||||
M_C(name, _parse_str)(list_t list, const char str[], const char **endp) \
|
||||
{ \
|
||||
M_ASSERT (str != NULL && list != NULL); \
|
||||
M_C(name,_clean)(list); \
|
||||
M_C(name,_reset)(list); \
|
||||
bool success = false; \
|
||||
int c = *str++; \
|
||||
if (M_UNLIKELY (c != '[')) goto exit; \
|
||||
@@ -749,7 +757,7 @@
|
||||
M_C(name, _in_str)(list_t list, FILE *file) \
|
||||
{ \
|
||||
M_ASSERT (file != NULL && list != NULL); \
|
||||
M_C(name,_clean)(list); \
|
||||
M_C(name,_reset)(list); \
|
||||
int c = fgetc(file); \
|
||||
if (M_UNLIKELY (c != '[')) return false; \
|
||||
c = fgetc(file); \
|
||||
@@ -804,7 +812,7 @@
|
||||
m_serial_return_code_t ret; \
|
||||
m_serial_local_t local; \
|
||||
size_t estimated_size = 0; \
|
||||
M_C(name,_clean)(list); \
|
||||
M_C(name,_reset)(list); \
|
||||
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
|
||||
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
|
||||
type item; \
|
||||
@@ -864,16 +872,55 @@
|
||||
, /* no hash */ ) \
|
||||
|
||||
|
||||
/* Definition of the emplace_back function for single list */
|
||||
#define M_L1ST_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Definition of the emplace_back function for dual push list */
|
||||
#define M_L1ST_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_back_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Definition of the emplace_front function for dual push list */
|
||||
#define M_L1ST_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
|
||||
static inline void \
|
||||
function_name(name_t v \
|
||||
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
|
||||
{ \
|
||||
M_C(name, _subtype_ct) *data = M_C(name, _push_front_raw)(v); \
|
||||
if (M_UNLIKELY (data == NULL) ) \
|
||||
return; \
|
||||
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
|
||||
}
|
||||
|
||||
|
||||
/* Deferred evaluation for the dual-push list definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define LISTI_DUAL_PUSH_DEF_P1(arg) LISTI_DUAL_PUSH_DEF_P2 arg
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P1(arg) M_ID( M_L1ST_DUAL_PUSH_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define LISTI_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(LISTI_DUAL_PUSH_DEF_P3, LISTI_DUAL_PUSH_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_L1ST_DUAL_PUSH_DEF_P3, M_L1ST_DUAL_PUSH_DEF_FAILURE)(name, type, oplist, list_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define LISTI_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DUAL_PUSH_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Internal dual-push list definition
|
||||
@@ -883,7 +930,7 @@
|
||||
- list_t: alias for M_C(name, _t) [ type of the container ]
|
||||
- it_t: alias for M_C(name, _it_t) [ iterator of the container ]
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Node of a list (it is liked the singly linked list) */ \
|
||||
struct M_C(name, _s) { \
|
||||
@@ -916,13 +963,13 @@
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of an dual-push list */
|
||||
#define LISTI_DUAL_PUSH_CONTRACT(l) do { \
|
||||
#define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \
|
||||
M_ASSERT (l != NULL); \
|
||||
M_ASSERT ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
@@ -935,7 +982,7 @@
|
||||
- list_t: alias for type of the container
|
||||
- it_t: alias for iterator of the container
|
||||
*/
|
||||
#define LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
#define M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(list_t v) \
|
||||
@@ -943,44 +990,44 @@
|
||||
M_ASSERT( v != NULL); \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(list_t v) \
|
||||
M_C(name, _reset)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
struct M_C(name, _s) *next = it->next; \
|
||||
M_CALL_CLEAR(oplist, it->data); \
|
||||
M_C(name,_int_del)(it); \
|
||||
M_C3(m_l1st_,name,_del)(it); \
|
||||
it = next; \
|
||||
} \
|
||||
v->front = NULL; \
|
||||
v->back = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(list_t v) \
|
||||
{ \
|
||||
M_C(name, _clean)(v); \
|
||||
M_C(name, _reset)(v); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _back)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->back != NULL); \
|
||||
return M_CONST_CAST(type, &(v->back->data)); \
|
||||
return &(v->back->data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_back_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
@@ -993,10 +1040,17 @@
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == NULL) ? next : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
/* Internal, for INIT_WITH */ \
|
||||
static inline type * \
|
||||
M_C(name, _push_raw)(list_t d) \
|
||||
{ \
|
||||
return M_C(name, _push_back_raw)(d); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push_back)(list_t v, type const x) \
|
||||
{ \
|
||||
@@ -1037,7 +1091,7 @@
|
||||
static inline void \
|
||||
M_C(name, _pop_back)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->back != NULL); \
|
||||
struct M_C(name, _s) *tofree = v->back; \
|
||||
if (data != NULL) { \
|
||||
@@ -1046,46 +1100,46 @@
|
||||
M_CALL_CLEAR(oplist, tofree->data); \
|
||||
} \
|
||||
v->back = tofree->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
/* Update front too if the list became empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == tofree) ? NULL : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop_move)(type *data, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->back != NULL); \
|
||||
M_ASSERT (data != NULL); \
|
||||
struct M_C(name, _s) *tofree = v->back; \
|
||||
M_DO_INIT_MOVE (oplist, *data, tofree->data); \
|
||||
v->back = tofree->next; \
|
||||
M_C(name,_int_del)(tofree); \
|
||||
M_C3(m_l1st_,name,_del)(tofree); \
|
||||
/* Update front too if the list became empty */ \
|
||||
/* This C code shall generate branchless code */ \
|
||||
struct M_C(name, _s) *front = v->front; \
|
||||
front = (front == tofree) ? NULL : front; \
|
||||
v->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
static inline type * \
|
||||
M_C(name, _front)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (v->front != NULL); \
|
||||
return M_CONST_CAST(type, &(v->front->data)); \
|
||||
return &(v->front->data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _push_front_raw)(list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return NULL; \
|
||||
@@ -1099,7 +1153,7 @@
|
||||
v->back = next; \
|
||||
} \
|
||||
v->front = next; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
@@ -1137,15 +1191,15 @@
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
return v->back == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(list_t l, list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(l); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(l); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->front, v->front); \
|
||||
M_SWAP(struct M_C(name, _s) *, l->back, v->back); \
|
||||
} \
|
||||
@@ -1153,7 +1207,7 @@
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
M_ASSERT (it != NULL); \
|
||||
it->current = v->back; \
|
||||
it->previous = NULL; \
|
||||
@@ -1171,7 +1225,7 @@
|
||||
M_C(name, _it_end)(it_t it1, const list_t v) \
|
||||
{ \
|
||||
M_ASSERT (it1 != NULL); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
(void)v; /* unused */ \
|
||||
it1->current = NULL; \
|
||||
it1->previous = NULL; \
|
||||
@@ -1223,7 +1277,7 @@
|
||||
static inline size_t \
|
||||
M_C(name, _size)(const list_t v) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(v); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(v); \
|
||||
size_t size = 0; \
|
||||
struct M_C(name, _s) *it = v->back; \
|
||||
while (it != NULL) { \
|
||||
@@ -1237,9 +1291,9 @@
|
||||
M_C(name, _insert)(list_t list, it_t insertion_point, \
|
||||
type const x) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_ASSERT (insertion_point != NULL); \
|
||||
struct M_C(name, _s) *next = M_C(name, _int_new)(); \
|
||||
struct M_C(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
return; \
|
||||
@@ -1265,7 +1319,7 @@
|
||||
static inline void \
|
||||
M_C(name, _remove)(list_t list, it_t removing_point) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_ASSERT (removing_point != NULL); \
|
||||
M_ASSERT(removing_point->current != NULL); \
|
||||
struct M_C(name, _s) *next = removing_point->current->next; \
|
||||
@@ -1281,24 +1335,24 @@
|
||||
list->front = front; \
|
||||
/* Remove node */ \
|
||||
M_CALL_CLEAR(oplist, removing_point->current->data); \
|
||||
M_C(name,_int_del) (removing_point->current); \
|
||||
M_C3(m_l1st_,name,_del) (removing_point->current); \
|
||||
removing_point->current = next; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(list_t list, const list_t org) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(org); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(org); \
|
||||
struct M_C(name, _s) *next = NULL; \
|
||||
struct M_C(name, _s) *it_org; \
|
||||
struct M_C(name, _s) **update_list; \
|
||||
if (M_UNLIKELY (list == org)) return; \
|
||||
M_C(name, _clean)(list); \
|
||||
M_C(name, _reset)(list); \
|
||||
update_list = &list->back; \
|
||||
it_org = org->back; \
|
||||
while (it_org != NULL) { \
|
||||
next = M_C(name, _int_new)(); \
|
||||
next = M_C3(m_l1st_,name,_new)(); \
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \
|
||||
@@ -1340,8 +1394,8 @@
|
||||
static inline void \
|
||||
M_C(name, _splice_back)(list_t list1, list_t list2, it_t it) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_ASSERT (it->current != NULL); \
|
||||
/* First remove the item 'it' from the list 'list2' */ \
|
||||
struct M_C(name, _s) *current = it->current; \
|
||||
@@ -1365,16 +1419,16 @@
|
||||
front = list1->front; \
|
||||
front = (front == NULL) ? current : front; \
|
||||
list1->front = front; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice_at)(list_t nlist, it_t npos, \
|
||||
list_t olist, it_t opos) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(nlist); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(olist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(nlist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(olist); \
|
||||
M_ASSERT (npos != NULL && opos != NULL); \
|
||||
/* First remove the item 'opos' from the list 'olist' */ \
|
||||
struct M_C(name, _s) *current = opos->current; \
|
||||
@@ -1411,15 +1465,15 @@
|
||||
/* Update 'npos' to point to 'current'. */ \
|
||||
npos->previous = npos_current; \
|
||||
npos->current = current; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(nlist); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(olist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(nlist); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(olist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _splice)(list_t list1, list_t list2) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_ASSERT (list1 != list2); \
|
||||
if (M_LIKELY (list1->front != NULL)) { \
|
||||
list1->front->next = list2->back; \
|
||||
@@ -1431,14 +1485,14 @@
|
||||
} \
|
||||
list2->back = NULL; \
|
||||
list2->front = NULL; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list1); \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list2); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list1); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _reverse)(list_t list) \
|
||||
{ \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
list->front = list->back; \
|
||||
struct M_C(name, _s) *previous = NULL, *it = list->back, *next; \
|
||||
while (it != NULL) { \
|
||||
@@ -1448,7 +1502,20 @@
|
||||
it = next; \
|
||||
} \
|
||||
list->back = previous; \
|
||||
LISTI_DUAL_PUSH_CONTRACT(list); \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_back), oplist, M_L1ST_EMPLACE_BACK_DEF) \
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_C(name, _emplace_front), oplist, M_L1ST_EMPLACE_FRONT_DEF)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define LIST_DEF M_LIST_DEF
|
||||
#define LIST_DEF_AS M_LIST_DEF_AS
|
||||
#define LIST_DUAL_PUSH_DEF M_LIST_DUAL_PUSH_DEF
|
||||
#define LIST_DUAL_PUSH_DEF_AS M_LIST_DUAL_PUSH_DEF_AS
|
||||
#define LIST_OPLIST M_LIST_OPLIST
|
||||
#define LIST_INIT_VALUE M_LIST_INIT_VALUE
|
||||
#define LIST_DUAL_PUSH_INIT_VALUE M_LIST_DUAL_PUSH_INIT_VALUE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+40
-29
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - MEMPOOL module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,47 +27,52 @@
|
||||
|
||||
#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
|
||||
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 MEMPOOL_DEF(name, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, M_C(name, _t) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_MEMPOOL_DEF(name, type) \
|
||||
M_MEMPOOL_DEF_AS(name, M_C(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 \
|
||||
MEMPOOL_DEF_P2(name, type, name_t ) \
|
||||
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 MEMPOOL_MAX_PER_SEGMENT
|
||||
#define MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
#ifndef M_USE_MEMPOOL_MAX_PER_SEGMENT
|
||||
#define M_USE_MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
|
||||
#endif
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define MEMPOOL_DEF_P2(name, type, name_t) \
|
||||
#define M_M3MPOOL_DEF_P2(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. */ \
|
||||
@@ -81,7 +86,7 @@
|
||||
typedef struct M_C(name,_segment_s) { \
|
||||
unsigned int count; \
|
||||
struct M_C(name,_segment_s) *next; \
|
||||
M_C(name,_union_ct) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
M_C(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_C(name,_segment_ct); \
|
||||
\
|
||||
/* Define a mempool. \
|
||||
@@ -103,13 +108,13 @@
|
||||
} \
|
||||
mem->current_segment->next = NULL; \
|
||||
mem->current_segment->count = 0; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_clear)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
while (segment != NULL) { \
|
||||
M_C(name,_segment_ct) *next = segment->next; \
|
||||
@@ -124,7 +129,7 @@
|
||||
static inline type * \
|
||||
M_C(name,_alloc)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
/* Test if one object is in the free list */ \
|
||||
M_C(name,_union_ct) *ret = mem->free_list; \
|
||||
if (ret != NULL) { \
|
||||
@@ -137,7 +142,7 @@
|
||||
M_ASSERT(segment != NULL); \
|
||||
unsigned int count = segment->count; \
|
||||
/* If segment is full, allocate a new one from the system */ \
|
||||
if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
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))); \
|
||||
@@ -152,14 +157,14 @@
|
||||
/* Return the object as the last element of the current segment */ \
|
||||
ret = &segment->tab[count]; \
|
||||
segment->count = count + 1; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
return &ret->t; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_free)(name_t mem, type *ptr) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
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; \
|
||||
@@ -168,14 +173,20 @@
|
||||
mem->free_list = ret; \
|
||||
/* NOTE: the objects are NOT given back to the system until the mempool \
|
||||
is fully cleared */ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_M3MPOOL_CONTRACT(mem, type); \
|
||||
} \
|
||||
|
||||
/* MEMPOOL contract */
|
||||
#define MEMPOOLI_CONTRACT(mempool, type) do { \
|
||||
/* 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 <= MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
M_ASSERT((mempool)->current_segment->count <= M_USE_MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#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
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -152,14 +152,14 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
return retval == 0;
|
||||
}
|
||||
|
||||
// Internal type, not exported.
|
||||
typedef once_flag m_once_ct[1];
|
||||
// a helper structure for m_once_call
|
||||
typedef once_flag m_once_t[1];
|
||||
|
||||
// Initial value for m_once_ct
|
||||
#define M_ONCEI_INIT_VALUE { ONCE_FLAG_INIT }
|
||||
// Initial value for m_once_t
|
||||
#define M_ONCE_INIT_VALUE { ONCE_FLAG_INIT }
|
||||
|
||||
// Call the function exactly once
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
static inline void m_once_call(m_once_t o, void (*func)(void))
|
||||
{
|
||||
call_once(o,func);
|
||||
}
|
||||
@@ -315,10 +315,9 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
typedef INIT_ONCE m_once_t[1];
|
||||
#define M_ONCE_INIT_VALUE { INIT_ONCE_STATIC_INIT }
|
||||
static inline BOOL CALLBACK m_once_callback( PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
|
||||
{
|
||||
void (*func)(void);
|
||||
(void) InitOnce;
|
||||
@@ -327,9 +326,9 @@ static inline BOOL CALLBACK m_oncei_callback( PINIT_ONCE InitOnce, PVOID Paramet
|
||||
(*func)();
|
||||
return TRUE;
|
||||
}
|
||||
static inline void m_oncei_call(m_once_ct o, void (*func)(void))
|
||||
static inline void m_once_call(m_once_t o, void (*func)(void))
|
||||
{
|
||||
InitOnceExecuteOnce(o, m_oncei_callback, (void*)(intptr_t)func, NULL);
|
||||
InitOnceExecuteOnce(o, m_once_callback, (void*)(intptr_t)func, NULL);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
@@ -474,10 +473,9 @@ static inline bool m_thread_sleep(unsigned long long usec)
|
||||
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))
|
||||
typedef pthread_once_t m_once_t[1];
|
||||
#define M_ONCE_INIT_VALUE { PTHREAD_ONCE_INIT }
|
||||
static inline void m_once_call(m_once_t o, void (*func)(void))
|
||||
{
|
||||
pthread_once(o,func);
|
||||
}
|
||||
@@ -511,9 +509,9 @@ M_END_PROTECTED_CODE
|
||||
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
|
||||
m_once_t M_C(m_once_, name) = M_ONCE_INIT_VALUE
|
||||
# define M_LOCKI_BY_ONCE(name) \
|
||||
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
(m_once_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)
|
||||
|
||||
+94
-35
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - dynamic priority queue module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,20 +32,16 @@
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_PRIOQUEUE_DEF(name, ...) \
|
||||
M_PRIOQUEUE_DEF_AS(name, M_C(name,_t), M_C(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 \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_PR1OQUEUE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -53,9 +49,9 @@
|
||||
|
||||
/* Define the oplist of a prioqueue of type.
|
||||
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define M_PRIOQUEUE_OPLIST(...) \
|
||||
M_PR1OQUEUE_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -64,18 +60,18 @@
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
|
||||
#define M_PR1OQUEUE_OPLIST_P1(arg) M_PR1OQUEUE_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_OPLIST_P3, PRIOQUEUEI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_PR1OQUEUE_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_PR1OQUEUE_OPLIST_P3, M_PR1OQUEUE_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_PR1OQUEUE_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* Define oplist of a priority queue */
|
||||
#define PRIOQUEUEI_OPLIST_P3(name, oplist) \
|
||||
#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
@@ -84,36 +80,43 @@
|
||||
,INIT_MOVE(M_C(name, _init_move)) \
|
||||
,MOVE(M_C(name, _move)) \
|
||||
,SWAP(M_C(name, _swap)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,RESET(M_C(name,_reset)) \
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,EMPTY_P(M_C(name, _empty_p)), \
|
||||
,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)), \
|
||||
,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)) \
|
||||
,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)),) \
|
||||
)
|
||||
|
||||
|
||||
/* Deferred evaluation for the definition,
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
|
||||
#define M_PR1OQUEUE_DEF_P1(arg) M_ID( M_PR1OQUEUE_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_DEF_P3, PRIOQUEUEI_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
|
||||
#define M_PR1OQUEUE_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_PR1OQUEUE_DEF_P3, M_PR1OQUEUE_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
||||
#define M_PR1OQUEUE_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(PRIOQUEUE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Define the priority queue:
|
||||
@@ -123,7 +126,7 @@
|
||||
- prioqueue_t: type of the container,
|
||||
- it_t: iterator of the container
|
||||
*/
|
||||
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
#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) \
|
||||
@@ -189,9 +192,9 @@
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
M_C(name, _reset)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clean)(p->array); \
|
||||
M_C(name, _array_reset)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
@@ -432,8 +435,64 @@
|
||||
} \
|
||||
} \
|
||||
, /* No EQUAL */ ) \
|
||||
\
|
||||
M_IF_METHOD(OUT_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _out_str)(FILE *file, const prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_out_str)(file, p->array); \
|
||||
} \
|
||||
,/* No OUT_STR */) \
|
||||
\
|
||||
M_IF_METHOD(IN_STR, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _in_str)(prioqueue_t p, FILE *file) \
|
||||
{ \
|
||||
return M_C(name, _array_in_str)(p->array, file); \
|
||||
} \
|
||||
,/* No IN_STR */) \
|
||||
\
|
||||
M_IF_METHOD(GET_STR, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _get_str)(string_t str, const prioqueue_t p, bool append) \
|
||||
{ \
|
||||
M_C(name, _array_get_str)(str, p->array, append); \
|
||||
} \
|
||||
,/* No GET_STR */) \
|
||||
\
|
||||
M_IF_METHOD(PARSE_STR, oplist)( \
|
||||
static inline bool \
|
||||
M_C(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \
|
||||
{ \
|
||||
return M_C(name, _array_parse_str)(p->array, str, endp); \
|
||||
} \
|
||||
,/* No PARSE_STR */) \
|
||||
\
|
||||
M_IF_METHOD(OUT_SERIAL, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \
|
||||
{ \
|
||||
return M_C(name, _array_out_serial)(f, p->array); \
|
||||
} \
|
||||
,/* No OUT_SERIAL */) \
|
||||
\
|
||||
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \
|
||||
{ \
|
||||
return M_C(name, _array_in_serial)(p->array, f); \
|
||||
} \
|
||||
,/* No in_SERIAL */) \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_C(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
|
||||
|
||||
|
||||
// TODO: set all & remove all function
|
||||
|
||||
#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
|
||||
+252
-227
File diff suppressed because it is too large.
Load diff
+81
-68
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - Serial BIN
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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_ser1al_bin_write_size(FILE *f, const size_t size)
|
||||
{
|
||||
bool b;
|
||||
if (M_LIKELY(size < 253))
|
||||
@@ -84,7 +89,7 @@ m_serial_bin_write_size(FILE *f, const size_t size)
|
||||
* (and I/O bandwidth)
|
||||
*/
|
||||
static inline bool
|
||||
m_serial_bin_read_size(FILE *f, size_t *size)
|
||||
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;
|
||||
@@ -107,7 +112,7 @@ 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_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);
|
||||
@@ -117,7 +122,7 @@ 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_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;
|
||||
@@ -153,7 +158,7 @@ m_serial_bin_write_integer(m_serial_write_t serial,const long long data, const s
|
||||
/* 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_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
|
||||
{
|
||||
float f1;
|
||||
double f2;
|
||||
@@ -179,13 +184,13 @@ m_serial_bin_write_float(m_serial_write_t serial, const long double data, const
|
||||
/* 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_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);
|
||||
@@ -199,7 +204,7 @@ m_serial_bin_write_string(m_serial_write_t serial, const char data[], size_t len
|
||||
(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_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
|
||||
{
|
||||
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);
|
||||
@@ -210,7 +215,7 @@ m_serial_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial,
|
||||
/* 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_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
|
||||
@@ -226,7 +231,7 @@ m_serial_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_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
|
||||
@@ -242,7 +247,7 @@ m_serial_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
/* 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_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -254,7 +259,7 @@ m_serial_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
|
||||
(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_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -264,7 +269,7 @@ 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_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;
|
||||
@@ -277,7 +282,7 @@ 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_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -290,7 +295,7 @@ m_serial_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
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_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;
|
||||
@@ -303,7 +308,7 @@ 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_ser1al_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -311,28 +316,28 @@ 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -344,15 +349,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) )
|
||||
|
||||
#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_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,7 +374,7 @@ m_serial_bin_read_boolean(m_serial_read_t serial, bool *b){
|
||||
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_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;
|
||||
@@ -397,7 +409,7 @@ m_serial_bin_read_integer(m_serial_read_t serial, long long *i, const size_t siz
|
||||
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_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;
|
||||
@@ -422,15 +434,15 @@ m_serial_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
|
||||
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_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 = stringi_fit2size(s, length + 1);
|
||||
stringi_set_size(s, length);
|
||||
char *p = m_str1ng_fit2size(s, length + 1);
|
||||
m_str1ng_set_size(s, length);
|
||||
// Read the characters excluding the final null one.
|
||||
// NOTE: fread supports length == 0.
|
||||
size_t n = fread(M_ASSIGN_CAST(void*, p), 1, length, f);
|
||||
@@ -447,7 +459,7 @@ m_serial_bin_read_string(m_serial_read_t serial, struct string_s *s){
|
||||
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_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);
|
||||
@@ -471,7 +483,7 @@ m_serial_bin_read_array_start(m_serial_local_t local, m_serial_read_t serial, si
|
||||
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_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) {
|
||||
@@ -493,7 +505,7 @@ m_serial_bin_read_array_next(m_serial_local_t local, m_serial_read_t serial)
|
||||
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_ser1al_bin_read_map_value(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) local; // argument not used
|
||||
(void) serial;
|
||||
@@ -504,7 +516,7 @@ m_serial_bin_read_map_value(m_serial_local_t local, m_serial_read_t 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_ser1al_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
{
|
||||
(void) serial;
|
||||
local->data[1].i = 0;
|
||||
@@ -518,7 +530,7 @@ m_serial_bin_read_tuple_start(m_serial_local_t local, m_serial_read_t serial)
|
||||
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_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,7 +547,7 @@ m_serial_bin_read_tuple_id(m_serial_local_t local, m_serial_read_t serial, const
|
||||
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_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,32 +561,32 @@ m_serial_bin_read_variant_start(m_serial_local_t local, m_serial_read_t 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_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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -586,7 +598,8 @@ static inline void m_serial_bin_read_clear(m_serial_read_t serial)
|
||||
/* Define a synonym of m_serial_read_t to the BIN serializer with its proper OPLIST */
|
||||
typedef m_serial_read_t m_serial_bin_read_t;
|
||||
#define M_OPL_m_serial_bin_read_t() \
|
||||
(INIT_WITH(m_serial_bin_read_init), CLEAR(m_serial_bin_read_clear), TYPE(m_serial_bin_read_t) )
|
||||
(INIT_WITH(m_serial_bin_read_init), CLEAR(m_serial_bin_read_clear), \
|
||||
TYPE(m_serial_bin_read_t), PROPERTIES(( LET_AS_INIT_WITH(1) )) )
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
+697
-81
File diff suppressed because it is too large.
Load diff
+103
-102
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SHARED Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,72 +33,60 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
#define M_SHARED_PTR_OPLIST(...) \
|
||||
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_BASIC_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_SHARED_PTR_DEF(name, ...) \
|
||||
M_SHARED_PTR_DEF_AS(name, M_C(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 \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, name_t ))) \
|
||||
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 ), \
|
||||
(name, __VA_ARGS__ , M_SHAR3D_ATOMIC_OPLIST, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe).
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_SHARED_PTR_RELAXED_DEF_AS(name, M_C(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 \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, name_t ))) \
|
||||
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 ), \
|
||||
(name, __VA_ARGS__, M_SHAR3D_INTEGER_OPLIST, name_t ))) \
|
||||
M_END_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, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name, _t), M_C(name, _it_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_SHARED_RESOURCE_DEF(name, ...) \
|
||||
M_SHARED_RESOURCE_DEF_AS(name, M_C(name,_t), M_C(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 \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
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 ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -108,25 +96,26 @@ M_BEGIN_PROTECTED_CODE
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
|
||||
#define M_SHAR3D_PTR_OPLIST_P1(arg) M_SHAR3D_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given, shared_t oplist */
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_OPLIST_P3, SHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_SHAR3D_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_SHAR3D_PTR_OPLIST_P3, M_SHAR3D_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_SHAR3D_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
#define SHAREDI_PTR_OPLIST_P3(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)), \
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
RESET(M_C(name, _reset)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(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),) \
|
||||
@@ -134,44 +123,44 @@ M_BEGIN_PROTECTED_CODE
|
||||
)
|
||||
|
||||
// OPLIST to handle a counter of atomic type
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
#define M_SHAR3D_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
ADD(atomic_fetch_add), \
|
||||
SUB(atomic_fetch_sub), \
|
||||
IT_CREF(atomic_load))
|
||||
|
||||
// OPLIST to handle a counter of non-atomic type
|
||||
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(sharedi_integer_init_set), \
|
||||
ADD(sharedi_integer_add), \
|
||||
SUB(sharedi_integer_sub), \
|
||||
IT_CREF(sharedi_integer_cref))
|
||||
#define M_SHAR3D_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(m_shar3d_integer_init_set), \
|
||||
ADD(m_shar3d_integer_add), \
|
||||
SUB(m_shar3d_integer_sub), \
|
||||
IT_CREF(m_shar3d_integer_cref))
|
||||
|
||||
/* Atomic like interface for basic integers */
|
||||
static inline void sharedi_integer_init_set(int *p, int val) { *p = val; }
|
||||
static inline int sharedi_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
|
||||
static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
|
||||
static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
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; }
|
||||
|
||||
/* Contract of a shared pointer */
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
#define M_SHAR3D_CONTRACT(shared, cpt_oplist) do { \
|
||||
M_ASSERT(shared != NULL); \
|
||||
M_ASSERT(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
|
||||
} while (0)
|
||||
|
||||
// deferred evaluation
|
||||
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_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 SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
|
||||
#define M_SHAR3D_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(M_SHAR3D_PTR_DEF_P3, M_SHAR3D_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
#define M_SHAR3D_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Code generation */
|
||||
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
|
||||
#define M_SHAR3D_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
@@ -216,9 +205,10 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = false; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _init_new)(shared_t shared) \
|
||||
{ \
|
||||
@@ -236,13 +226,14 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
, /* No INIT */ ) \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -250,20 +241,20 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _init_set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) { \
|
||||
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
|
||||
(void) n; /* unused return value */ \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
|
||||
bool combineAlloc = (*dest)->combineAlloc; \
|
||||
@@ -278,11 +269,11 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t dest) \
|
||||
M_C(name, _reset)(shared_t dest) \
|
||||
{ \
|
||||
/* NOTE: Clear will also set dest to NULL */ \
|
||||
M_C(name, _clear)(dest); \
|
||||
@@ -292,8 +283,8 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
@@ -302,19 +293,19 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _init_move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
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); \
|
||||
@@ -324,27 +315,27 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _swap)(shared_t p1, \
|
||||
shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
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); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const shared_t p1, \
|
||||
const shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
M_ASSERT (data != NULL); \
|
||||
@@ -354,7 +345,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
static inline type * \
|
||||
M_C(name, _ref)(shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
|
||||
M_ASSERT(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
M_ASSERT (data != NULL); \
|
||||
@@ -365,23 +356,23 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
|
||||
/********************************** SHARED RESOURCE ************************************/
|
||||
|
||||
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
|
||||
#define M_SHAR3D_RESOURCE_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->buffer != NULL); \
|
||||
} while (0)
|
||||
|
||||
// deferred
|
||||
#define SHAREDI_RESOURCE_DEF_P1(arg) SHAREDI_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 SHAREDI_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
|
||||
#define M_SHAR3D_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(M_SHAR3D_RESOURCE_DEF_P3, M_SHAR3D_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
|
||||
#define M_SHAR3D_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
|
||||
#define M_SHAR3D_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
@@ -391,7 +382,7 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
} M_C(name, _atype_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
m_genint_t core; \
|
||||
M_C(name, _atype_ct) *buffer; \
|
||||
} shared_t[1]; \
|
||||
\
|
||||
@@ -417,32 +408,32 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_CALL_INIT(oplist, s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, (unsigned int) n); \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
m_genint_init(s->core, (unsigned int) n); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
M_SHAR3D_RESOURCE_CONTRACT(s); \
|
||||
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) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(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); \
|
||||
} \
|
||||
@@ -452,38 +443,38 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(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_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
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_ASSERT (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
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) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(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; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -491,11 +482,11 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
M_C(name, _it_set)(it_t itd, it_t its) \
|
||||
{ \
|
||||
M_ASSERT (itd != NULL && its != NULL); \
|
||||
SHAREDI_RESOURCE_CONTRACT(its->ref); \
|
||||
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); \
|
||||
} \
|
||||
@@ -503,4 +494,14 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#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
|
||||
+202
-203
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - SNAPSHOT Module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,8 +22,8 @@
|
||||
* (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_SNAPSHOT
|
||||
#define MSTARLIB_SNAPSHOT
|
||||
#ifndef MSTARLIB_SNAPSHOT_H
|
||||
#define MSTARLIB_SNAPSHOT_H
|
||||
|
||||
#include "m-atomic.h"
|
||||
#include "m-core.h"
|
||||
@@ -33,20 +33,16 @@ 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, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPSC_DEF_AS(name, M_C(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 \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SNAPSH0T_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -54,20 +50,16 @@ 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, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPMC_DEF_AS(name, M_C(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 \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SNAPSH0T_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -75,20 +67,16 @@ 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, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_MPMC_DEF_AS(name, M_C(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 \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
M_SNAPSH0T_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -96,8 +84,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
|
||||
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
SNAPSHOTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#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__ )))
|
||||
|
||||
@@ -105,22 +93,23 @@ M_BEGIN_PROTECTED_CODE
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
// deferred evaluation of the input
|
||||
#define SNAPSHOTI_OPLIST_P1(arg) SNAPSHOTI_OPLIST_P2 arg
|
||||
#define M_SNAPSH0T_OPLIST_P1(arg) M_SNAPSH0T_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define SNAPSHOTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_OPLIST_P3, SNAPSHOTI_OPLIST_FAILURE)(name, oplist)
|
||||
#define M_SNAPSH0T_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_OPLIST_P3, M_SNAPSH0T_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SNAPSHOTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define M_SNAPSH0T_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_SNAPSHOT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* Define the oplist of a snapshot */
|
||||
#define SNAPSHOTI_OPLIST_P3(name, oplist) \
|
||||
#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)) \
|
||||
,NAME(name) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
@@ -138,47 +127,47 @@ M_BEGIN_PROTECTED_CODE
|
||||
* - b: Boolean indicating that the read buffer shall be updated
|
||||
* all fields packed in an unsigned char type.
|
||||
*/
|
||||
#define SNAPSHOTI_SPSC_FLAG(r, w, f, b) \
|
||||
#define M_SNAPSH0T_SPSC_FLAG(r, w, f, b) \
|
||||
((unsigned char)( ( (r) << 4) | ((w) << 2) | ((f)) | ((b) << 6)))
|
||||
#define SNAPSHOTI_SPSC_R(flags) \
|
||||
#define M_SNAPSH0T_SPSC_R(flags) \
|
||||
(((unsigned int) (flags) >> 4) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_W(flags) \
|
||||
#define M_SNAPSH0T_SPSC_W(flags) \
|
||||
(((unsigned int) (flags) >> 2) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_F(flags) \
|
||||
#define M_SNAPSH0T_SPSC_F(flags) \
|
||||
(((unsigned int) (flags) >> 0) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_B(flags) \
|
||||
#define M_SNAPSH0T_SPSC_B(flags) \
|
||||
(((unsigned int) (flags) >> 6) & 0x01u)
|
||||
|
||||
/* NOTE: Due to atomic_load only accepting non-const pointer,
|
||||
we can't have any const in the interface. */
|
||||
#define SNAPSHOTI_SPSC_FLAGS_CONTRACT(flags) \
|
||||
M_ASSERT(SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_W(flags) \
|
||||
&& SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_F(flags) \
|
||||
&& SNAPSHOTI_SPSC_W(flags) != SNAPSHOTI_SPSC_F(flags))
|
||||
#define M_SNAPSH0T_SPSC_FLAGS_CONTRACT(flags) \
|
||||
M_ASSERT(M_SNAPSH0T_SPSC_R(flags) != M_SNAPSH0T_SPSC_W(flags) \
|
||||
&& M_SNAPSH0T_SPSC_R(flags) != M_SNAPSH0T_SPSC_F(flags) \
|
||||
&& M_SNAPSH0T_SPSC_W(flags) != M_SNAPSH0T_SPSC_F(flags))
|
||||
|
||||
#define SNAPSHOTI_SPSC_CONTRACT(snap) do { \
|
||||
#define M_SNAPSH0T_SPSC_CONTRACT(snap) do { \
|
||||
M_ASSERT((snap) != NULL); \
|
||||
unsigned char f = atomic_load (&(snap)->flags); \
|
||||
SNAPSHOTI_SPSC_FLAGS_CONTRACT(f); \
|
||||
M_SNAPSH0T_SPSC_FLAGS_CONTRACT(f); \
|
||||
} while (0)
|
||||
|
||||
// A snapshot is basically an atomic triple buffer (Lock Free)
|
||||
// between a single producer thread and a single consummer thread.
|
||||
#define SNAPSHOTI_SPSC_MAX_BUFFER 3
|
||||
#define M_SNAPSH0T_SPSC_MAX_BUFFER 3
|
||||
|
||||
// Defered evaluation of the arguments.
|
||||
#define SNAPSHOTI_SPSC_DEF_P1(arg) SNAPSHOTI_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 SNAPSHOTI_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPSC_DEF_P3, SNAPSHOTI_SPSC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
#define M_SNAPSH0T_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_SPSC_DEF_P3, M_SNAPSH0T_SPSC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPSC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPSC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPSC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a SPSC snapshot */
|
||||
#define SNAPSHOTI_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
@@ -187,7 +176,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) data[SNAPSHOTI_SPSC_MAX_BUFFER]; \
|
||||
M_C(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); \
|
||||
@@ -203,18 +192,18 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _init)(snapshot_t snap) \
|
||||
{ \
|
||||
M_ASSERT(snap != NULL); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, SNAPSHOTI_SPSC_FLAG(0, 1, 2, 0)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
atomic_init (&snap->flags, M_SNAPSH0T_SPSC_FLAG(0, 1, 2, 0)); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
} \
|
||||
@@ -223,40 +212,40 @@ M_BEGIN_PROTECTED_CODE
|
||||
static inline void \
|
||||
M_C(name, _init_set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
/* 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) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT_MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _init_move)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
atomic_store (&org->flags, M_SNAPSH0T_SPSC_FLAG(0,0,0,0) ); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (INIT_MOVE) */ \
|
||||
\
|
||||
@@ -265,133 +254,133 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _move)(snapshot_t snap, \
|
||||
snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(org); \
|
||||
M_ASSERT(snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
atomic_store (&org->flags, M_SNAPSH0T_SPSC_FLAG(0,0,0,0) ); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (MOVE) */ \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* Swap F and W buffer, setting exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_R(origFlags), \
|
||||
SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), 1); \
|
||||
nextFlags = M_SNAPSH0T_SPSC_FLAG(M_SNAPSH0T_SPSC_R(origFlags), \
|
||||
M_SNAPSH0T_SPSC_F(origFlags), \
|
||||
M_SNAPSH0T_SPSC_W(origFlags), 1); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return new write buffer for new updating */ \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(nextFlags)].x; \
|
||||
return &snap->data[M_SNAPSH0T_SPSC_W(nextFlags)].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* If no exchange registered, do nothing and keep the same */ \
|
||||
if (!SNAPSHOTI_SPSC_B(origFlags)) { \
|
||||
if (!M_SNAPSH0T_SPSC_B(origFlags)) { \
|
||||
nextFlags = origFlags; \
|
||||
break; \
|
||||
} \
|
||||
/* Swap R and F buffer, clearing exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), \
|
||||
SNAPSHOTI_SPSC_R(origFlags), 0); \
|
||||
nextFlags = M_SNAPSH0T_SPSC_FLAG(M_SNAPSH0T_SPSC_F(origFlags), \
|
||||
M_SNAPSH0T_SPSC_W(origFlags), \
|
||||
M_SNAPSH0T_SPSC_R(origFlags), 0); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return current read buffer */ \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(nextFlags)].x); \
|
||||
return M_CONST_CAST(type, &snap->data[M_SNAPSH0T_SPSC_R(nextFlags)].x); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline bool \
|
||||
M_C(name, _updated_p)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load (&snap->flags); \
|
||||
return SNAPSHOTI_SPSC_B(flags); \
|
||||
return M_SNAPSH0T_SPSC_B(flags); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(flags)].x; \
|
||||
return &snap->data[M_SNAPSH0T_SPSC_W(flags)].x; \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type const * \
|
||||
M_C(name, _get_read_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
M_SNAPSH0T_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(flags)].x); \
|
||||
return M_CONST_CAST(type, &snap->data[M_SNAPSH0T_SPSC_R(flags)].x); \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/******************************** INTERNAL SPMC **********************************/
|
||||
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG_W(f) ((f) >> 1)
|
||||
#define SNAPSHOTI_SPMC_INT_FLAG_N(f) ((f) & 1)
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG(w, n) ( ((w) << 1) | (n) )
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG_W(f) ((f) >> 1)
|
||||
#define M_SNAPSH0T_SPMC_INT_FLAG_N(f) ((f) & 1)
|
||||
|
||||
// 2 more buffer than the number of readers are needed
|
||||
#define SNAPSHOTI_SPMC_EXTRA_BUFFER 2
|
||||
#define M_SNAPSH0T_SPMC_EXTRA_BUFFER 2
|
||||
|
||||
#define SNAPSHOTI_SPMC_MAX_READER (GENINT_MAX_ALLOC-SNAPSHOTI_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 SNAPSHOTI_SPMC_INT_FLAG)
|
||||
- lastNext: last published written index + next flag (format M_SNAPSH0T_SPMC_INT_FLAG)
|
||||
- currentWrite: the index being currently written.
|
||||
- n_reader : number of readers
|
||||
- cptTab: ref counter array to keep track of how many readers use the corresponding buffer.
|
||||
- freeList: a pool of free integers.
|
||||
*/
|
||||
typedef struct snapshot_mrsw_int_s {
|
||||
typedef struct m_snapsh0t_mrsw_s {
|
||||
atomic_uint lastNext;
|
||||
unsigned int currentWrite;
|
||||
size_t n_reader;
|
||||
atomic_uint *cptTab;
|
||||
genint_t freeList;
|
||||
} snapshot_mrsw_int_ct[1];
|
||||
m_genint_t freeList;
|
||||
} m_snapsh0t_mrsw_ct[1];
|
||||
|
||||
// can't check currentWrite due to potential data race on it
|
||||
#define SNAPSHOTI_SPMC_INT_CONTRACT(s) do { \
|
||||
#define M_SNAPSH0T_SPMC_INT_CONTRACT(s) do { \
|
||||
M_ASSERT (s != NULL); \
|
||||
M_ASSERT (s->n_reader > 0 && s->n_reader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
M_ASSERT ((size_t)SNAPSHOTI_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
|
||||
<= s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT (s->n_reader > 0 && s->n_reader <= M_SNAPSH0T_SPMC_MAX_READER); \
|
||||
M_ASSERT ((size_t)M_SNAPSH0T_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
|
||||
<= s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT (s->cptTab != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Initialize snapshot_mrsw_int_ct for n readers (constructor) */
|
||||
/* Initialize m_snapsh0t_mrsw_ct for n readers (constructor) */
|
||||
static inline void
|
||||
snapshot_mrsw_int_init(snapshot_mrsw_int_ct s, size_t n)
|
||||
m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n)
|
||||
{
|
||||
M_ASSERT (s != NULL);
|
||||
M_ASSERT (n >= 1 && n <= SNAPSHOTI_SPMC_MAX_READER);
|
||||
M_ASSERT (n >= 1 && n <= M_SNAPSH0T_SPMC_MAX_READER);
|
||||
s->n_reader = n;
|
||||
n += SNAPSHOTI_SPMC_EXTRA_BUFFER;
|
||||
n += M_SNAPSH0T_SPMC_EXTRA_BUFFER;
|
||||
|
||||
// Initialize the counters to zero (no reader use it)
|
||||
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n);
|
||||
@@ -402,149 +391,149 @@ snapshot_mrsw_int_init(snapshot_mrsw_int_ct s, size_t n)
|
||||
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, SNAPSHOTI_SPMC_INT_FLAG(w, true));
|
||||
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);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Clear snapshot_mrsw_int_ct (destructor) */
|
||||
/* Clear m_snapsh0t_mrsw_ct (destructor) */
|
||||
static inline void
|
||||
snapshot_mrsw_int_clear(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(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
|
||||
snapshot_mrsw_int_get_write_idx(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_get_write_idx(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
}
|
||||
|
||||
/* Return the number of readers */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_size(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_size(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return (unsigned int) s->n_reader;
|
||||
}
|
||||
|
||||
/* Give the current index that is written to the readers,
|
||||
and return new available index for writter */
|
||||
and return new available index for the writer thread */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_write_idx(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_write_idx(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
// Provide the finalized written buffer to the readers.
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
|
||||
newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, true);
|
||||
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
|
||||
|
||||
if (SNAPSHOTI_SPMC_INT_FLAG_N(previous)) {
|
||||
if (M_SNAPSH0T_SPMC_INT_FLAG_N(previous)) {
|
||||
// Reuse previous buffer as it was not used by any reader
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
// Some other read threads may already have try to reserve this index
|
||||
// So atomic_load(&s->cptTab[idx]) can be greater than 1.
|
||||
// However they will fail to ack it in lastNext,
|
||||
// so they will remove their reservation later
|
||||
} else {
|
||||
// Remove the writer thread counter from the count of the previous buffer
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
M_ASSERT (c != 0 && c <= s->n_reader + 1);
|
||||
// Get a new buffer.
|
||||
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.
|
||||
}
|
||||
M_ASSERT (idx < s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
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);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* Perform a swap of the current write buffer and return a new one */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_write(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_write(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
s->currentWrite = snapshot_mrsw_int_write_idx(s, s->currentWrite);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
s->currentWrite = m_snapsh0t_mrsw_write_idx(s, s->currentWrite);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return s->currentWrite;
|
||||
}
|
||||
|
||||
/* Start writing to the write buffer and return its index */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_write_start(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_write_start(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
// Get a new buffer.
|
||||
unsigned int idx = genint_pop(s->freeList);
|
||||
M_ASSERT (idx != GENINT_ERROR);
|
||||
M_ASSERT (idx < s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
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);
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* End writing to the given write buffer */
|
||||
static inline void
|
||||
snapshot_mrsw_int_write_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_write_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
// Provide this write bufer to the readers
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, true);
|
||||
newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, true);
|
||||
} while (!atomic_compare_exchange_weak(&s->lastNext, &previous, newNext));
|
||||
|
||||
// Free the previous write buffer
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
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);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Start reading the latest written buffer and return the index to it */
|
||||
static inline unsigned int
|
||||
snapshot_mrsw_int_read_start(snapshot_mrsw_int_ct s)
|
||||
m_snapsh0t_mrsw_read_start(m_snapsh0t_mrsw_ct s)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
unsigned int idx, previous;
|
||||
reload:
|
||||
// Load the last published index + Next flag
|
||||
previous = atomic_load(&s->lastNext);
|
||||
while (true) {
|
||||
// Get the last published index
|
||||
idx = SNAPSHOTI_SPMC_INT_FLAG_W(previous);
|
||||
idx = M_SNAPSH0T_SPMC_INT_FLAG_W(previous);
|
||||
// Load the number of threads using this index
|
||||
unsigned int c = atomic_load(&s->cptTab[idx]);
|
||||
M_ASSERT (c <= s->n_reader + 1);
|
||||
@@ -553,67 +542,67 @@ snapshot_mrsw_int_read_start(snapshot_mrsw_int_ct s)
|
||||
|| !atomic_compare_exchange_strong(&s->cptTab[idx], &c, c+1)))
|
||||
goto reload;
|
||||
// Try to ack it
|
||||
unsigned int newNext = SNAPSHOTI_SPMC_INT_FLAG(idx, false);
|
||||
unsigned int newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, false);
|
||||
reforce:
|
||||
if (M_LIKELY (atomic_compare_exchange_strong(&s->lastNext, &previous, newNext)))
|
||||
break;
|
||||
// We have been preempted by another thread
|
||||
if (idx == SNAPSHOTI_SPMC_INT_FLAG_W(previous)) {
|
||||
if (idx == M_SNAPSH0T_SPMC_INT_FLAG_W(previous)) {
|
||||
// This is still ok if the index has not changed
|
||||
// We can get previous to true again if the writer has recycled the index,
|
||||
// while we reserved it, and the reader get prempted until its CAS.
|
||||
if (M_UNLIKELY (SNAPSHOTI_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
|
||||
if (M_UNLIKELY (M_SNAPSH0T_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
|
||||
break;
|
||||
}
|
||||
// Free the reserved index as we failed it to ack it
|
||||
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);
|
||||
}
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* End the reading the given buffer */
|
||||
static inline void
|
||||
snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_ASSERT (idx < s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
M_ASSERT (idx < s->n_reader + M_SNAPSH0T_SPMC_EXTRA_BUFFER);
|
||||
// Decrement reference counter of the buffer
|
||||
unsigned int c = atomic_fetch_sub(&s->cptTab[idx], 1U);
|
||||
M_ASSERT (c != 0 && c <= s->n_reader + 1);
|
||||
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);
|
||||
}
|
||||
SNAPSHOTI_SPMC_INT_CONTRACT(s);
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
}
|
||||
|
||||
/* Contract of a SPMC snapshot.
|
||||
Nothing notable as it can be accessed concurrently */
|
||||
#define SNAPSHOTI_SPMC_CONTRACT(snap) do { \
|
||||
#define M_SNAPSH0T_SPMC_CONTRACT(snap) do { \
|
||||
M_ASSERT (snap != NULL); \
|
||||
M_ASSERT (snap->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Defered evaluation
|
||||
#define SNAPSHOTI_SPMC_DEF_P1(arg) SNAPSHOTI_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 SNAPSHOTI_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPMC_DEF_P3, SNAPSHOTI_SPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
#define M_SNAPSH0T_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_SPMC_DEF_P3, M_SNAPSH0T_SPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a SPMC snapshot */
|
||||
#define SNAPSHOTI_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
@@ -623,7 +612,7 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) *data; \
|
||||
snapshot_mrsw_int_ct core; \
|
||||
m_snapsh0t_mrsw_ct core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
@@ -636,68 +625,68 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader) \
|
||||
{ \
|
||||
M_ASSERT (snap != NULL); \
|
||||
M_ASSERT (nReader > 0 && nReader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
M_ASSERT (nReader > 0 && nReader <= M_SNAPSH0T_SPMC_MAX_READER); \
|
||||
snap->data = M_CALL_REALLOC(oplist, M_C(name, _aligned_type_ct), \
|
||||
NULL, nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
NULL, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
|
||||
if (M_UNLIKELY (snap->data == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_ct)) * \
|
||||
(nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER)); \
|
||||
(nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
snapshot_mrsw_int_init(snap->core, nReader); \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
m_snapsh0t_mrsw_init(snap->core, nReader); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
size_t nReader = snapshot_mrsw_int_size(snap->core); \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
size_t nReader = m_snapsh0t_mrsw_size(snap->core); \
|
||||
for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, snap->data); \
|
||||
snapshot_mrsw_int_clear(snap->core); \
|
||||
m_snapsh0t_mrsw_clear(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write(snap->core); \
|
||||
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) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_read_start(snap->core); \
|
||||
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) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
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); \
|
||||
M_ASSERT (oldx >= snap->data); \
|
||||
M_ASSERT (oldx < snap->data + snap->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->n_reader +SNAPSHOTI_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
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); \
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->data); \
|
||||
snapshot_mrsw_int_read_end(snap->core, idx); \
|
||||
m_snapsh0t_mrsw_read_end(snap->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_get_write_idx(snap->core); \
|
||||
M_SNAPSH0T_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = m_snapsh0t_mrsw_get_write_idx(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
@@ -711,20 +700,20 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
// MPMC is built upon SPMC
|
||||
|
||||
// Defered evaluation
|
||||
#define SNAPSHOTI_MPMC_DEF_P1(arg) SNAPSHOTI_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 SNAPSHOTI_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_MPMC_DEF_P3, SNAPSHOTI_MPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
#define M_SNAPSH0T_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(M_SNAPSH0T_MPMC_DEF_P3, M_SNAPSH0T_MPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_MPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_MPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_MPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a MPMC snapshot */
|
||||
#define SNAPSHOTI_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
#define M_SNAPSH0T_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
SNAPSHOTI_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist, M_C(name, _mrsw_pct))) \
|
||||
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; \
|
||||
@@ -741,8 +730,8 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
{ \
|
||||
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
unsigned int idx = snap->core->core->currentWrite; \
|
||||
snap->core->core->currentWrite = GENINT_ERROR; \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
snap->core->core->currentWrite = M_GENINT_ERROR; \
|
||||
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
@@ -754,22 +743,22 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
static inline type * \
|
||||
M_C(name, _write_start)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write_start(snap->core->core); \
|
||||
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) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
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); \
|
||||
M_ASSERT (oldx >= snap->core->data); \
|
||||
M_ASSERT (oldx < snap->core->data + snap->core->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
M_ASSERT(snap->core->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
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); \
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->core->data); \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
@@ -785,8 +774,18 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
} \
|
||||
\
|
||||
|
||||
//TODO: _set_, _init_set
|
||||
//FIXME: Evaluate the needs for the methods _set_, _init_set.
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
#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
|
||||
+1063
-710
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB - TUPLE module
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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,28 +32,26 @@
|
||||
/* Define the tuple type and functions.
|
||||
USAGE:
|
||||
TUPLE_DEF2(name, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, M_C(name, _t) TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
#define M_TUPLE_DEF2(name, ...) \
|
||||
M_TUPLE_DEF2_AS(name, M_C(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the tuple type and functions
|
||||
as the given name.
|
||||
USAGE:
|
||||
TUPLE_DEF2_AS(name, name_t, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2_AS(name, name_t, ...) \
|
||||
#define M_TUPLE_DEF2_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, name_t TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_TUPL3_DEF2_P1( (name, name_t M_TUPL3_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a tuple.
|
||||
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define TUPLE_OPLIST(...) \
|
||||
#define M_TUPLE_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(TUPLEI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
|
||||
TUPLEI_OPLIST_P1((__VA_ARGS__ )))
|
||||
(M_TUPL3_OPLIST_P1((__VA_ARGS__, M_BASIC_OPLIST )), \
|
||||
M_TUPL3_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Return an array suitable for the WIP _cmp_order function.
|
||||
@@ -62,15 +60,15 @@
|
||||
(shall be constexpr, but only supported in C++14).
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
#define TUPLE_ORDER(name, ...) \
|
||||
( (const int[]) {M_MAP2_C(TUPLEI_ORDER_CONVERT, name, __VA_ARGS__), 0})
|
||||
#define M_TUPLE_ORDER(name, ...) \
|
||||
( (const int[]) {M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0})
|
||||
#else
|
||||
#include <initializer_list>
|
||||
namespace m_lib {
|
||||
template <unsigned int N>
|
||||
struct m_int_array {
|
||||
struct m_tupl3_integer_va {
|
||||
int data[N];
|
||||
/*constexpr*/ inline m_int_array(std::initializer_list<int> init){
|
||||
/*constexpr*/ inline m_tupl3_integer_va(std::initializer_list<int> init){
|
||||
int j = 0;
|
||||
for(auto i:init) {
|
||||
data[j++] = i;
|
||||
@@ -78,426 +76,446 @@ namespace m_lib {
|
||||
}
|
||||
};
|
||||
}
|
||||
#define TUPLE_ORDER(name, ...) \
|
||||
(m_lib::m_int_array<M_NARGS(__VA_ARGS__,0)>({M_MAP2_C(TUPLEI_ORDER_CONVERT, name, __VA_ARGS__), 0}).data)
|
||||
#define M_TUPLE_ORDER(name, ...) \
|
||||
(m_lib::m_tupl3_integer_va<M_NARGS(__VA_ARGS__,0)>({M_MAP2_C(M_TUPL3_ORDER_CONVERT, name, __VA_ARGS__), 0}).data)
|
||||
#endif
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Contract of a tuple. Nothing notable */
|
||||
#define TUPLEI_CONTRACT(tup) do { \
|
||||
#define M_TUPL3_CONTRACT(tup) do { \
|
||||
M_ASSERT(tup != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define TUPLEI_INJECT_GLOBAL(...) \
|
||||
M_MAP(TUPLEI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
#define M_TUPL3_INJECT_GLOBAL(...) \
|
||||
M_MAP(M_TUPL3_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 TUPLEI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
TUPLEI_INJECT_OPLIST_B duo_or_trio
|
||||
#define M_TUPL3_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
M_TUPL3_INJECT_OPLIST_B duo_or_trio
|
||||
|
||||
#define TUPLEI_INJECT_OPLIST_B( f, ... ) \
|
||||
#define M_TUPL3_INJECT_OPLIST_B( f, ... ) \
|
||||
M_DEFERRED_COMMA \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Deferred evaluation
|
||||
#define TUPLEI_DEF2_P1(...) TUPLEI_DEF2_P2 __VA_ARGS__
|
||||
#define M_TUPL3_DEF2_P1(...) M_ID( M_TUPL3_DEF2_P2 __VA_ARGS__ )
|
||||
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define TUPLEI_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(TUPLEI_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
#define M_TUPL3_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(M_TUPL3_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
|
||||
// Test if the third argument of (name, type, oplist) is an oplist
|
||||
#define TUPLEI_IS_OPLIST_P(a) \
|
||||
#define M_TUPL3_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define TUPLEI_DEF2_P2(name, name_t, ...) \
|
||||
TUPLEI_IF_ALL_OPLIST(__VA_ARGS__)(TUPLEI_DEF2_P3, TUPLEI_DEF2_FAILURE)(name, name_t, __VA_ARGS__)
|
||||
#define M_TUPL3_DEF2_P2(name, name_t, ...) \
|
||||
M_TUPL3_IF_ALL_OPLIST(__VA_ARGS__)(M_TUPL3_DEF2_P3, M_TUPL3_DEF2_FAILURE)(name, name_t, __VA_ARGS__)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define TUPLEI_DEF2_FAILURE(name, name_t, ...) \
|
||||
#define M_TUPL3_DEF2_FAILURE(name, name_t, ...) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(TUPLE_DEF2): at least one of the given argument is not a valid oplist: " #__VA_ARGS__)
|
||||
|
||||
/* Define the tuple */
|
||||
#define TUPLEI_DEF2_P3(name, name_t, ...) \
|
||||
TUPLEI_DEFINE_TYPE(name, name_t, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_ENUM(name, __VA_ARGS__) \
|
||||
TUPLEI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
TUPLEI_IF_ALL(INIT, __VA_ARGS__)(TUPLEI_DEFINE_INIT(name, __VA_ARGS__),) \
|
||||
TUPLEI_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_INIT_SET2(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_SET(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_SET2(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
TUPLEI_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
TUPLEI_IF_ALL(CMP, __VA_ARGS__)(TUPLEI_DEFINE_CMP(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(CMP, __VA_ARGS__)(TUPLEI_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \
|
||||
TUPLEI_DEFINE_CMP_FIELD(name, __VA_ARGS__) \
|
||||
TUPLEI_IF_ALL(HASH, __VA_ARGS__)(TUPLEI_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(EQUAL, __VA_ARGS__)(TUPLEI_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(GET_STR, __VA_ARGS__)(TUPLEI_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(OUT_STR, __VA_ARGS__)(TUPLEI_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(IN_STR, __VA_ARGS__)(TUPLEI_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(PARSE_STR, __VA_ARGS__)(TUPLEI_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(OUT_SERIAL, __VA_ARGS__)(TUPLEI_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(IN_SERIAL, __VA_ARGS__)(TUPLEI_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(INIT_MOVE, __VA_ARGS__)(TUPLEI_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(MOVE, __VA_ARGS__)(TUPLEI_DEFINE_MOVE(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(SWAP, __VA_ARGS__)(TUPLEI_DEFINE_SWAP(name, __VA_ARGS__),) \
|
||||
TUPLEI_IF_ALL(CLEAN, __VA_ARGS__)(TUPLEI_DEFINE_CLEAN(name, __VA_ARGS__),)
|
||||
#define M_TUPL3_DEF2_P3(name, name_t, ...) \
|
||||
M_TUPL3_DEFINE_TYPE(name, name_t, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_ENUM(name, __VA_ARGS__) \
|
||||
M_TUPL3_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
M_TUPL3_IF_ALL(INIT, __VA_ARGS__)(M_TUPL3_DEFINE_INIT(name, __VA_ARGS__),) \
|
||||
M_TUPL3_DEFINE_INIT_SET(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_INIT_SET2(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_SET(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_SET2(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_CLEAR(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_IF_ONE(CMP, __VA_ARGS__)(M_TUPL3_DEFINE_CMP(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(CMP, __VA_ARGS__)(M_TUPL3_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \
|
||||
M_TUPL3_DEFINE_CMP_FIELD(name, __VA_ARGS__) \
|
||||
M_TUPL3_IF_ONE(HASH, __VA_ARGS__)(M_TUPL3_DEFINE_HASH(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ONE(EQUAL, __VA_ARGS__)(M_TUPL3_DEFINE_EQUAL(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(GET_STR, __VA_ARGS__)(M_TUPL3_DEFINE_GET_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(OUT_STR, __VA_ARGS__)(M_TUPL3_DEFINE_OUT_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(IN_STR, __VA_ARGS__)(M_TUPL3_DEFINE_IN_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(PARSE_STR, __VA_ARGS__)(M_TUPL3_DEFINE_PARSE_STR(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(OUT_SERIAL, __VA_ARGS__)(M_TUPL3_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(IN_SERIAL, __VA_ARGS__)(M_TUPL3_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(INIT_MOVE, __VA_ARGS__)(M_TUPL3_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(MOVE, __VA_ARGS__)(M_TUPL3_DEFINE_MOVE(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(SWAP, __VA_ARGS__)(M_TUPL3_DEFINE_SWAP(name, __VA_ARGS__),) \
|
||||
M_TUPL3_IF_ALL(RESET, __VA_ARGS__)(M_TUPL3_DEFINE_RESET(name, __VA_ARGS__),)
|
||||
|
||||
/* Provide order for _cmp_order */
|
||||
#define TUPLEI_ORDER_CONVERT(name, x) M_C(name, M_C(TUPLEI_ORDER_CONVERT_, x))
|
||||
#define TUPLEI_ORDER_CONVERT_ASC(x) M_C3(_,x,_value)
|
||||
#define TUPLEI_ORDER_CONVERT_DSC(x) M_C3(_,x,_value)*-1
|
||||
#define M_TUPL3_ORDER_CONVERT(name, x) M_C(name, M_C(M_TUPL3_ORDER_CONVERT_, x))
|
||||
#define M_TUPL3_ORDER_CONVERT_ASC(x) M_C3(_,x,_value)
|
||||
#define M_TUPL3_ORDER_CONVERT_DSC(x) M_C3(_,x,_value)*-1
|
||||
|
||||
/* Get the field name, the type, the oplist or the methods
|
||||
based on the tuple (field, type, oplist) */
|
||||
#define TUPLEI_GET_FIELD(f,t,o) f
|
||||
#define TUPLEI_GET_TYPE(f,t,o) t
|
||||
#define TUPLEI_GET_OPLIST(f,t,o) o
|
||||
#define TUPLEI_GET_INIT(f,t,o) M_GET_INIT o
|
||||
#define TUPLEI_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
|
||||
#define TUPLEI_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
|
||||
#define TUPLEI_GET_MOVE(f,t,o) M_GET_MOVE o
|
||||
#define TUPLEI_GET_SET(f,t,o) M_GET_SET o
|
||||
#define TUPLEI_GET_CLEAR(f,t,o) M_GET_CLEAR o
|
||||
#define TUPLEI_GET_CMP(f,t,o) M_GET_CMP o
|
||||
#define TUPLEI_GET_HASH(f,t,o) M_GET_HASH o
|
||||
#define TUPLEI_GET_EQUAL(f,t,o) M_GET_EQUAL o
|
||||
#define TUPLEI_GET_STR(f,t,o) M_GET_GET_STR o
|
||||
#define TUPLEI_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
|
||||
#define TUPLEI_GET_IN_STR(f,t,o) M_GET_IN_STR o
|
||||
#define TUPLEI_GET_OUT_SERIAL(f,t,o) M_GET_OUT_SERIAL o
|
||||
#define TUPLEI_GET_IN_SERIAL(f,t,o) M_GET_IN_SERIAL o
|
||||
#define TUPLEI_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
|
||||
#define TUPLEI_GET_SWAP(f,t,o) M_GET_SWAP o
|
||||
#define TUPLEI_GET_CLEAN(f,t,o) M_GET_CLEAN o
|
||||
#define M_TUPL3_GET_FIELD(f,t,o) f
|
||||
#define M_TUPL3_GET_TYPE(f,t,o) t
|
||||
#define M_TUPL3_GET_OPLIST(f,t,o) o
|
||||
#define M_TUPL3_GET_INIT(f,t,o) M_GET_INIT o
|
||||
#define M_TUPL3_GET_INIT_SET(f,t,o) M_GET_INIT_SET o
|
||||
#define M_TUPL3_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o
|
||||
#define M_TUPL3_GET_MOVE(f,t,o) M_GET_MOVE o
|
||||
#define M_TUPL3_GET_SET(f,t,o) M_GET_SET o
|
||||
#define M_TUPL3_GET_CLEAR(f,t,o) M_GET_CLEAR o
|
||||
#define M_TUPL3_GET_CMP(f,t,o) M_GET_CMP o
|
||||
#define M_TUPL3_GET_HASH(f,t,o) M_GET_HASH o
|
||||
#define M_TUPL3_GET_EQUAL(f,t,o) M_GET_EQUAL o
|
||||
#define M_TUPL3_GET_STR(f,t,o) M_GET_GET_STR o
|
||||
#define M_TUPL3_GET_OUT_STR(f,t,o) M_GET_OUT_STR o
|
||||
#define M_TUPL3_GET_IN_STR(f,t,o) M_GET_IN_STR o
|
||||
#define M_TUPL3_GET_OUT_SERIAL(f,t,o) M_GET_OUT_SERIAL o
|
||||
#define M_TUPL3_GET_IN_SERIAL(f,t,o) M_GET_IN_SERIAL o
|
||||
#define M_TUPL3_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o
|
||||
#define M_TUPL3_GET_SWAP(f,t,o) M_GET_SWAP o
|
||||
#define M_TUPL3_GET_RESET(f,t,o) M_GET_RESET o
|
||||
|
||||
/* Call the method associated to the given operator for the given parameter
|
||||
of the tuple t=(name, type, oplist) */
|
||||
#define TUPLEI_CALL_INIT(t, ...) M_APPLY_API(TUPLEI_GET_INIT t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_INIT_SET(t, ...) M_APPLY_API(TUPLEI_GET_INIT_SET t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_INIT_MOVE(t, ...) M_APPLY_API(TUPLEI_GET_INIT_MOVE t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_MOVE(t, ...) M_APPLY_API(TUPLEI_GET_MOVE t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_SET(t, ...) M_APPLY_API(TUPLEI_GET_SET t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_CLEAR(t, ...) M_APPLY_API(TUPLEI_GET_CLEAR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_CMP(t, ...) M_APPLY_API(TUPLEI_GET_CMP t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_HASH(t, ...) M_APPLY_API(TUPLEI_GET_HASH t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_EQUAL(t, ...) M_APPLY_API(TUPLEI_GET_EQUAL t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_GET_STR(t, ...) M_APPLY_API(TUPLEI_GET_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_OUT_STR(t, ...) M_APPLY_API(TUPLEI_GET_OUT_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_IN_STR(t, ...) M_APPLY_API(TUPLEI_GET_IN_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_PARSE_STR(t, ...) M_APPLY_API(TUPLEI_GET_PARSE_STR t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_OUT_SERIAL(t, ...) M_APPLY_API(TUPLEI_GET_OUT_SERIAL t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_IN_SERIAL(t, ...) M_APPLY_API(TUPLEI_GET_IN_SERIAL t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_SWAP(t, ...) M_APPLY_API(TUPLEI_GET_SWAP t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define TUPLEI_CALL_CLEAN(t, ...) M_APPLY_API(TUPLEI_GET_CLEAN t, TUPLEI_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_INIT(t, ...) M_APPLY_API(M_TUPL3_GET_INIT t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_INIT_SET(t, ...) M_APPLY_API(M_TUPL3_GET_INIT_SET t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_INIT_MOVE(t, ...) M_APPLY_API(M_TUPL3_GET_INIT_MOVE t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_MOVE(t, ...) M_APPLY_API(M_TUPL3_GET_MOVE t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_SET(t, ...) M_APPLY_API(M_TUPL3_GET_SET t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_CLEAR(t, ...) M_APPLY_API(M_TUPL3_GET_CLEAR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_CMP(t, ...) M_APPLY_API(M_TUPL3_GET_CMP t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_HASH(t, ...) M_APPLY_API(M_TUPL3_GET_HASH t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_EQUAL(t, ...) M_APPLY_API(M_TUPL3_GET_EQUAL t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_GET_STR(t, ...) M_APPLY_API(M_TUPL3_GET_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_OUT_STR(t, ...) M_APPLY_API(M_TUPL3_GET_OUT_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_IN_STR(t, ...) M_APPLY_API(M_TUPL3_GET_IN_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_PARSE_STR(t, ...) M_APPLY_API(M_TUPL3_GET_PARSE_STR t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_OUT_SERIAL(t, ...) M_APPLY_API(M_TUPL3_GET_OUT_SERIAL t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_IN_SERIAL(t, ...) M_APPLY_API(M_TUPL3_GET_IN_SERIAL t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_SWAP(t, ...) M_APPLY_API(M_TUPL3_GET_SWAP t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
#define M_TUPL3_CALL_RESET(t, ...) M_APPLY_API(M_TUPL3_GET_RESET t, M_TUPL3_GET_OPLIST t, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define the type of a tuple */
|
||||
#define TUPLEI_DEFINE_TYPE(name, name_t, ...) \
|
||||
#define M_TUPL3_DEFINE_TYPE(name, name_t, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_MAP(TUPLEI_DEFINE_RECUR_TYPE_ELE , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_RECUR_TYPE_ELE , __VA_ARGS__) \
|
||||
} name_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
/* Define internal type for oplist */ \
|
||||
typedef name_t M_C(name, _ct);
|
||||
typedef name_t M_C(name, _ct); \
|
||||
/* Save constant as the number of arguments (internal) */ \
|
||||
typedef enum { \
|
||||
M_C3(m_tupl3_, name, _num_args) = M_NARGS(__VA_ARGS__) \
|
||||
} M_C3(m_tupl3_, name, _num_args_ct); \
|
||||
/* Save alias for the types of arguments */ \
|
||||
M_MAP3(M_TUPL3_DEFINE_TYPE_ELE, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
TUPLEI_GET_TYPE a TUPLEI_GET_FIELD a ;
|
||||
#define M_TUPL3_DEFINE_TYPE_ELE(name, num, a) \
|
||||
typedef M_TUPL3_GET_TYPE a M_C4(name, _type_, num, _ct);
|
||||
|
||||
#define M_TUPL3_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
M_TUPL3_GET_TYPE a M_TUPL3_GET_FIELD a ;
|
||||
|
||||
/* Define the basic enumerate, identifying a parameter */
|
||||
#define TUPLEI_DEFINE_ENUM(name, ...) \
|
||||
#define M_TUPL3_DEFINE_ENUM(name, ...) \
|
||||
typedef enum { \
|
||||
M_C(name, _first_one_val), \
|
||||
M_MAP2_C(TUPLEI_DEFINE_ENUM_ELE , name, __VA_ARGS__) \
|
||||
M_MAP2_C(M_TUPL3_DEFINE_ENUM_ELE , name, __VA_ARGS__) \
|
||||
} M_C(name,_field_e);
|
||||
|
||||
#define TUPLEI_DEFINE_ENUM_ELE(name, a) \
|
||||
M_C4(name, _, TUPLEI_GET_FIELD a, _value)
|
||||
#define M_TUPL3_DEFINE_ENUM_ELE(name, a) \
|
||||
M_C4(name, _, M_TUPL3_GET_FIELD a, _value)
|
||||
|
||||
/* Control that all given oplists of all parameters are really oplists */
|
||||
#define TUPLEI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(TUPLEI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define M_TUPL3_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(M_TUPL3_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, TUPLEI_GET_FIELD a, \
|
||||
TUPLEI_GET_TYPE a, TUPLEI_GET_OPLIST a)
|
||||
#define M_TUPL3_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_TUPL3_GET_FIELD a, \
|
||||
M_TUPL3_GET_TYPE a, M_TUPL3_GET_OPLIST a)
|
||||
|
||||
/* Define the INIT method calling the INIT method for all params */
|
||||
#define TUPLEI_DEFINE_INIT(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT(name, ...) \
|
||||
static inline void M_C(name, _init)(M_C(name,_ct) my) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_FUNC(a) \
|
||||
TUPLEI_CALL_INIT(a, my -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_INIT_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT(a, my -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
/* Define the INIT_SET method calling the INIT_SET method for all params */
|
||||
#define TUPLEI_DEFINE_INIT_SET(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT_SET(name, ...) \
|
||||
static inline void M_C(name, _init_set)(M_C(name,_ct) my , M_C(name,_ct) const org) { \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(org); \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLEI_DEFINE_INIT_SET_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_SET(a, my -> TUPLEI_GET_FIELD a , org -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_INIT_SET_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT_SET(a, my -> M_TUPL3_GET_FIELD a , org -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
/* Define the INIT_WITH method calling the INIT_SET method for all params. */
|
||||
#define TUPLEI_DEFINE_INIT_SET2(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT_SET2(name, ...) \
|
||||
static inline void M_C(name, _init_emplace)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_SET2_PROTO(a) \
|
||||
, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a
|
||||
#define M_TUPL3_DEFINE_INIT_SET2_PROTO(a) \
|
||||
, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_SET2_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_SET(a, my -> TUPLEI_GET_FIELD a , TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_INIT_SET2_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT_SET(a, my -> M_TUPL3_GET_FIELD a , M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the SET method calling the SET method for all params. */
|
||||
#define TUPLEI_DEFINE_SET(name, ...) \
|
||||
#define M_TUPL3_DEFINE_SET(name, ...) \
|
||||
static inline void M_C(name, _set)(M_C(name,_ct) my , \
|
||||
M_C(name,_ct) const org) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_TUPL3_CONTRACT(org); \
|
||||
M_MAP(M_TUPL3_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_SET_FUNC(a) \
|
||||
TUPLEI_CALL_SET(a, my -> TUPLEI_GET_FIELD a , org -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_SET_FUNC(a) \
|
||||
M_TUPL3_CALL_SET(a, my -> M_TUPL3_GET_FIELD a , org -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the SET_WITH method calling the SET method for all params. */
|
||||
#define TUPLEI_DEFINE_SET2(name, ...) \
|
||||
#define M_TUPL3_DEFINE_SET2(name, ...) \
|
||||
static inline void M_C(name, _emplace)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_PROTO, __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_MAP(M_TUPL3_DEFINE_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLEI_DEFINE_SET2_PROTO(a) \
|
||||
, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a
|
||||
#define M_TUPL3_DEFINE_SET2_PROTO(a) \
|
||||
, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a
|
||||
|
||||
#define TUPLEI_DEFINE_SET2_FUNC(a) \
|
||||
TUPLEI_CALL_SET(a, my -> TUPLEI_GET_FIELD a , TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_SET2_FUNC(a) \
|
||||
M_TUPL3_CALL_SET(a, my -> M_TUPL3_GET_FIELD a , M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the CLEAR method calling the CLEAR method for all params. */
|
||||
#define TUPLEI_DEFINE_CLEAR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_CLEAR(name, ...) \
|
||||
static inline void M_C(name, _clear)(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_MAP(M_TUPL3_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CLEAR_FUNC(a) \
|
||||
TUPLEI_CALL_CLEAR(a, my -> TUPLEI_GET_FIELD a );
|
||||
#define M_TUPL3_DEFINE_CLEAR_FUNC(a) \
|
||||
M_TUPL3_CALL_CLEAR(a, my -> M_TUPL3_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the GET_AT_field & CGET_AT methods for all params. */
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_DEFINE_GETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
#define M_TUPL3_DEFINE_GETTER_FIELD(name, ...) \
|
||||
M_MAP3(M_TUPL3_DEFINE_GETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD_PROTO(name, a) \
|
||||
static inline TUPLEI_GET_TYPE a * M_C3(name, _get_at_, TUPLEI_GET_FIELD a) \
|
||||
#define M_TUPL3_DEFINE_GETTER_FIELD_PROTO(name, num, a) \
|
||||
static inline M_TUPL3_GET_TYPE a * M_C3(name, _get_at_, M_TUPL3_GET_FIELD a) \
|
||||
(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
return &(my->M_TUPL3_GET_FIELD a); \
|
||||
} \
|
||||
static inline TUPLEI_GET_TYPE a const * M_C3(name, _cget_at_, TUPLEI_GET_FIELD a) \
|
||||
static inline M_TUPL3_GET_TYPE a const * M_C3(name, _cget_at_, M_TUPL3_GET_FIELD a) \
|
||||
(M_C(name,_ct) const my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
}
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
return &(my->M_TUPL3_GET_FIELD a); \
|
||||
} \
|
||||
/* Same but uses numerical index for accessing the field (internal) */ \
|
||||
static inline M_TUPL3_GET_TYPE a * M_C4(m_tupl3_, name, _get_at_, num) \
|
||||
(M_C(name,_ct) my) { \
|
||||
return &(my->M_TUPL3_GET_FIELD a); \
|
||||
} \
|
||||
|
||||
|
||||
/* Define the SET_field methods for all params. */
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_DEFINE_SETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
#define M_TUPL3_DEFINE_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(M_TUPL3_DEFINE_SETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD_PROTO(name, a) \
|
||||
static inline void M_C3(name, _set_, TUPLEI_GET_FIELD a) \
|
||||
(M_C(name,_ct) my, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CALL_SET(a, my ->TUPLEI_GET_FIELD a, TUPLEI_GET_FIELD a); \
|
||||
#define M_TUPL3_DEFINE_SETTER_FIELD_PROTO(name, a) \
|
||||
static inline void M_C3(name, _set_, M_TUPL3_GET_FIELD a) \
|
||||
(M_C(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \
|
||||
M_TUPL3_CONTRACT(my); \
|
||||
M_TUPL3_CALL_SET(a, my ->M_TUPL3_GET_FIELD a, M_TUPL3_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the CMP method by calling CMP methods for all params. */
|
||||
#define TUPLEI_DEFINE_CMP(name, ...) \
|
||||
#define M_TUPL3_DEFINE_CMP(name, ...) \
|
||||
static inline int M_C(name, _cmp)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
int i; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_CMP_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
M_MAP(M_TUPL3_DEFINE_CMP_FUNC_P0, __VA_ARGS__) \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_FUNC(a) \
|
||||
i = TUPLEI_CALL_CMP(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
#define M_TUPL3_DEFINE_CMP_FUNC_P0(a) \
|
||||
M_IF(M_TUPL3_TEST_METHOD_P(CMP, a))(M_TUPL3_DEFINE_CMP_FUNC_P1, M_EAT)(a)
|
||||
#define M_TUPL3_DEFINE_CMP_FUNC_P1(a) \
|
||||
i = M_TUPL3_CALL_CMP(a, e1 -> M_TUPL3_GET_FIELD a , e2 -> M_TUPL3_GET_FIELD a ); \
|
||||
if (i != 0) return i;
|
||||
|
||||
|
||||
/* Define the CMP_ORDER method by calling CMP methods for all params
|
||||
In the right order
|
||||
FIXME: _cmp_order is not supported by algorithm yet.
|
||||
FIXME: All oplists shall define the CMP operator or at least one?
|
||||
*/
|
||||
#define TUPLEI_DEFINE_CMP_ORDER(name, ...) \
|
||||
#define M_TUPL3_DEFINE_CMP_ORDER(name, ...) \
|
||||
static inline int M_C(name, _cmp_order)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2, \
|
||||
const int order[]) { \
|
||||
int i, r; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
while (true) { \
|
||||
i=*order++; \
|
||||
switch (i) { \
|
||||
case 0: return 0; \
|
||||
M_MAP2(TUPLEI_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_TUPL3_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_ORDER_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
case -M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
r = TUPLEI_CALL_CMP(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
#define M_TUPL3_DEFINE_CMP_ORDER_FUNC(name, a) \
|
||||
case M_C4(name, _, M_TUPL3_GET_FIELD a, _value): \
|
||||
case -M_C4(name, _, M_TUPL3_GET_FIELD a, _value): \
|
||||
r = M_TUPL3_CALL_CMP(a, e1 -> M_TUPL3_GET_FIELD a , e2 -> M_TUPL3_GET_FIELD a ); \
|
||||
if (r != 0) return i < 0 ? -r : r; \
|
||||
break;
|
||||
|
||||
|
||||
/* Define a CMP_field method for all given params that export a CMP method */
|
||||
#define TUPLEI_DEFINE_CMP_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_MAP_CMP_FIELD, name, __VA_ARGS__)
|
||||
#define M_TUPL3_DEFINE_CMP_FIELD(name, ...) \
|
||||
M_MAP2(M_TUPL3_MAP_CMP_FIELD, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_MAP_CMP_FIELD(name, a) \
|
||||
M_IF_METHOD(CMP, TUPLEI_GET_OPLIST a)( \
|
||||
TUPLEI_DEFINE_CMP_FIELD_FUNC(name, TUPLEI_GET_FIELD a, TUPLEI_GET_CMP a), \
|
||||
#define M_TUPL3_MAP_CMP_FIELD(name, a) \
|
||||
M_IF_METHOD(CMP, M_TUPL3_GET_OPLIST a)( \
|
||||
M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, M_TUPL3_GET_FIELD a, M_TUPL3_GET_CMP a, M_TUPL3_GET_OPLIST a), \
|
||||
)
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
|
||||
#define M_TUPL3_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp, oplist) \
|
||||
static inline int M_C3(name, _cmp_, field)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
return func_cmp ( e1 -> field , e2 -> field ); \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
return M_APPLY_API(func_cmp, oplist, e1 -> field , e2 -> field ); \
|
||||
}
|
||||
|
||||
|
||||
/* Define a EQUAL method by calling the EQUAL methods for all params */
|
||||
#define TUPLEI_DEFINE_EQUAL(name, ...) \
|
||||
#define M_TUPL3_DEFINE_EQUAL(name, ...) \
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
bool b; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_EQUAL_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e2); \
|
||||
M_MAP(M_TUPL3_DEFINE_EQUAL_FUNC_P0, __VA_ARGS__) \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_EQUAL_FUNC(a) \
|
||||
b = TUPLEI_CALL_EQUAL(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
#define M_TUPL3_DEFINE_EQUAL_FUNC_P0(a) \
|
||||
M_IF(M_TUPL3_TEST_METHOD_P(EQUAL, a))(M_TUPL3_DEFINE_EQUAL_FUNC_P1, M_EAT)(a)
|
||||
#define M_TUPL3_DEFINE_EQUAL_FUNC_P1(a) \
|
||||
b = M_TUPL3_CALL_EQUAL(a, e1 -> M_TUPL3_GET_FIELD a , e2 -> M_TUPL3_GET_FIELD a ); \
|
||||
if (!b) return false;
|
||||
|
||||
|
||||
/* Define a HASH method by calling the HASH methods for all params */
|
||||
#define TUPLEI_DEFINE_HASH(name, ...) \
|
||||
#define M_TUPL3_DEFINE_HASH(name, ...) \
|
||||
static inline size_t M_C(name, _hash)(M_C(name,_ct) const e1) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
M_TUPL3_CONTRACT(e1); \
|
||||
M_HASH_DECL(hash); \
|
||||
M_MAP(TUPLEI_DEFINE_HASH_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_HASH_FUNC_P0, __VA_ARGS__) \
|
||||
return M_HASH_FINAL (hash); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_HASH_FUNC(a) \
|
||||
M_HASH_UP(hash, TUPLEI_CALL_HASH(a, e1 -> TUPLEI_GET_FIELD a) );
|
||||
#define M_TUPL3_DEFINE_HASH_FUNC_P0(a) \
|
||||
M_IF(M_TUPL3_TEST_METHOD_P(HASH, a))(M_TUPL3_DEFINE_HASH_FUNC_P1, M_EAT)(a)
|
||||
#define M_TUPL3_DEFINE_HASH_FUNC_P1(a) \
|
||||
M_HASH_UP(hash, M_TUPL3_CALL_HASH(a, e1 -> M_TUPL3_GET_FIELD a) );
|
||||
|
||||
|
||||
/* Define a GET_STR method by calling the GET_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
#define M_TUPL3_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(m_string_t str, \
|
||||
M_C(name,_ct) const el, \
|
||||
bool append) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "("); \
|
||||
M_MAP(TUPLEI_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
string_push_back (str, ')'); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "("); \
|
||||
M_MAP(M_TUPL3_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
m_string_push_back (str, ')'); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_GET_STR_FUNC(a) \
|
||||
if (comma) string_push_back (str, ','); \
|
||||
#define M_TUPL3_DEFINE_GET_STR_FUNC(a) \
|
||||
if (comma) m_string_push_back (str, ','); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_GET_STR(a, str, el -> TUPLEI_GET_FIELD a, true); \
|
||||
M_TUPL3_CALL_GET_STR(a, str, el -> M_TUPL3_GET_FIELD a, true); \
|
||||
|
||||
|
||||
/* Define a OUT_STR method by calling the OUT_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_OUT_STR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_OUT_STR(name, ...) \
|
||||
static inline void M_C(name, _out_str)(FILE *f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (f != NULL); \
|
||||
fputc('(', f); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
fputc (')', f); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_OUT_STR_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_OUT_STR_FUNC(a) \
|
||||
if (comma) fputc (',', f); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_OUT_STR(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
M_TUPL3_CALL_OUT_STR(a, f, el -> M_TUPL3_GET_FIELD a); \
|
||||
|
||||
|
||||
/* Define a IN_STR method by calling the IN_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_IN_STR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool M_C(name, _in_str)(M_C(name,_ct) el, FILE *f) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (f != NULL); \
|
||||
int c = fgetc(f); \
|
||||
if (c != '(') return false; \
|
||||
M_MAP(TUPLEI_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
c = fgetc(f); \
|
||||
return (c == ')'); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_IN_STR_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_IN_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = fgetc (f); \
|
||||
if (c != ',' || c == EOF) return false; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLEI_CALL_IN_STR(a, el -> TUPLEI_GET_FIELD a, f) == false) \
|
||||
if (M_TUPL3_CALL_IN_STR(a, el -> M_TUPL3_GET_FIELD a, f) == false) \
|
||||
return false ; \
|
||||
|
||||
|
||||
/* Define a PARSE_STR method by calling the PARSE_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_PARSE_STR(name, ...) \
|
||||
#define M_TUPL3_DEFINE_PARSE_STR(name, ...) \
|
||||
static inline bool M_C(name, _parse_str)(M_C(name,_ct) el, \
|
||||
const char str[], \
|
||||
const char **endptr) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (str != NULL); \
|
||||
bool success = false; \
|
||||
bool comma = false; \
|
||||
int c = *str++; \
|
||||
if (c != '(') goto exit; \
|
||||
M_MAP(TUPLEI_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
|
||||
c = *str++; \
|
||||
success = (c == ')'); \
|
||||
exit: \
|
||||
@@ -505,58 +523,58 @@ namespace m_lib {
|
||||
return success; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_PARSE_STR_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_PARSE_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = *str++; \
|
||||
if (c != ',' || c == 0) goto exit; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLEI_CALL_PARSE_STR(a, el -> TUPLEI_GET_FIELD a, str, &str) == false) \
|
||||
if (M_TUPL3_CALL_PARSE_STR(a, el -> M_TUPL3_GET_FIELD a, str, &str) == false) \
|
||||
goto exit ; \
|
||||
|
||||
|
||||
/* Return the parameter name as a C string */
|
||||
#define TUPLEI_STRINGIFY_NAME(a) \
|
||||
M_APPLY(M_AS_STR, TUPLEI_GET_FIELD a)
|
||||
#define M_TUPL3_STRINGIFY_NAME(a) \
|
||||
M_AS_STR(M_TUPL3_GET_FIELD a)
|
||||
|
||||
|
||||
/* Define a OUT_SERIAL method by calling the OUT_SERIAL methods for all params */
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL(name, ...) \
|
||||
#define M_TUPL3_DEFINE_OUT_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
/* Define a constant static table of all fields names */ \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
{ M_REDUCE(M_TUPL3_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
int index = 0; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->write_tuple_start(local, f); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
|
||||
M_MAP(M_TUPL3_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
|
||||
M_ASSERT( index == field_max); \
|
||||
ret |= f->m_interface->write_tuple_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL_FUNC(a) \
|
||||
#define M_TUPL3_DEFINE_OUT_SERIAL_FUNC(a) \
|
||||
f->m_interface->write_tuple_id(local, f, field_name, field_max, index); \
|
||||
TUPLEI_CALL_OUT_SERIAL(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
M_TUPL3_CALL_OUT_SERIAL(a, f, el -> M_TUPL3_GET_FIELD a); \
|
||||
index++; \
|
||||
|
||||
|
||||
/* Define a IN_SERIAL method by calling the IN_SERIAL methods for all params */
|
||||
#define TUPLEI_DEFINE_IN_SERIAL(name, ...) \
|
||||
#define M_TUPL3_DEFINE_IN_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(M_C(name,_ct) el, m_serial_read_t f) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_ASSERT (f != NULL && f->m_interface != NULL); \
|
||||
int index = -1; \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
{ M_REDUCE(M_TUPL3_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->read_tuple_start(local, f); \
|
||||
@@ -565,7 +583,7 @@ namespace m_lib {
|
||||
if (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
M_ASSERT (index >= 0 && index < field_max); \
|
||||
switch (1+index) { \
|
||||
M_MAP2(TUPLEI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
M_MAP2(M_TUPL3_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
default: M_ASSERT(0); \
|
||||
} \
|
||||
ret = (ret == M_SERIAL_OK_DONE) ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL; \
|
||||
@@ -574,88 +592,139 @@ namespace m_lib {
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
ret = TUPLEI_CALL_IN_SERIAL(a, el -> TUPLEI_GET_FIELD a, f); \
|
||||
#define M_TUPL3_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, M_TUPL3_GET_FIELD a, _value): \
|
||||
ret = M_TUPL3_CALL_IN_SERIAL(a, el -> M_TUPL3_GET_FIELD a, f); \
|
||||
break; \
|
||||
|
||||
|
||||
/* Define a INIT_MOVE method by calling the INIT_MOVE methods for all params */
|
||||
#define TUPLEI_DEFINE_INIT_MOVE(name, ...) \
|
||||
#define M_TUPL3_DEFINE_INIT_MOVE(name, ...) \
|
||||
static inline void M_C(name, _init_move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_MAP(M_TUPL3_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_MOVE(a, el -> TUPLEI_GET_FIELD a, org -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
M_TUPL3_CALL_INIT_MOVE(a, el -> M_TUPL3_GET_FIELD a, org -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a MOVE method by calling the MOVE methods for all params */
|
||||
#define TUPLEI_DEFINE_MOVE(name, ...) \
|
||||
#define M_TUPL3_DEFINE_MOVE(name, ...) \
|
||||
static inline void M_C(name, _move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(el); \
|
||||
M_MAP(M_TUPL3_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_MOVE_FUNC(a) \
|
||||
TUPLEI_CALL_MOVE(a, el -> TUPLEI_GET_FIELD a, org -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_MOVE_FUNC(a) \
|
||||
M_TUPL3_CALL_MOVE(a, el -> M_TUPL3_GET_FIELD a, org -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a SWAP method by calling the SWAP methods for all params */
|
||||
#define TUPLEI_DEFINE_SWAP(name, ...) \
|
||||
#define M_TUPL3_DEFINE_SWAP(name, ...) \
|
||||
static inline void M_C(name, _swap)(M_C(name,_ct) el1, M_C(name,_ct) el2) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
TUPLEI_CONTRACT(el2); \
|
||||
M_MAP(TUPLEI_DEFINE_SWAP_FUNC , __VA_ARGS__) \
|
||||
M_TUPL3_CONTRACT(el1); \
|
||||
M_TUPL3_CONTRACT(el2); \
|
||||
M_MAP(M_TUPL3_DEFINE_SWAP_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_SWAP_FUNC(a) \
|
||||
TUPLEI_CALL_SWAP(a, el1 -> TUPLEI_GET_FIELD a, el2 -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_SWAP_FUNC(a) \
|
||||
M_TUPL3_CALL_SWAP(a, el1 -> M_TUPL3_GET_FIELD a, el2 -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a CLEAN method by calling the CLEAN methods for all params */
|
||||
#define TUPLEI_DEFINE_CLEAN(name, ...) \
|
||||
static inline void M_C(name, _clean)(M_C(name,_ct) el1) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAN_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
/* Define a RESET method by calling the RESET methods for all params */
|
||||
#define M_TUPL3_DEFINE_RESET(name, ...) \
|
||||
static inline void M_C(name, _reset)(M_C(name,_ct) el1) { \
|
||||
M_TUPL3_CONTRACT(el1); \
|
||||
M_MAP(M_TUPL3_DEFINE_RESET_FUNC , __VA_ARGS__) \
|
||||
} \
|
||||
|
||||
#define TUPLEI_DEFINE_CLEAN_FUNC(a) \
|
||||
TUPLEI_CALL_CLEAN(a, el1 -> TUPLEI_GET_FIELD a);
|
||||
#define M_TUPL3_DEFINE_RESET_FUNC(a) \
|
||||
M_TUPL3_CALL_RESET(a, el1 -> M_TUPL3_GET_FIELD a);
|
||||
|
||||
|
||||
/* INIT_WITH macro enabling recursive INIT_WITH initialization
|
||||
tuple = { int, m_string_t, array<m_string_t> }
|
||||
USAGE:
|
||||
M_LET( (x, 2, ("John"), ( ("Bear"), ("Rabbit") )), tuple_t)
|
||||
|
||||
"If you think it's simple, you're deluding yourself."
|
||||
|
||||
Several pass are done:
|
||||
1) If the number of arguments doesn't match the number of oplists of the
|
||||
tuple oplist, it is assumed something is wrong. It uses the _init_emplace
|
||||
function to provide proper warning in such case.
|
||||
2) Otherwise, it checks that the number of arguments matches the number
|
||||
of arguments of the tuple definition.
|
||||
3) Mix all arguments with their associated oplists to have pair (arg, oplist),
|
||||
4) Map the following macro for each computed pair :
|
||||
4.a) If INIT_WITH macro is not defined for this pair, it uses INIT_SET
|
||||
4.b) If the argument is encapsulated with parenthesis, it uses INIT_WITH
|
||||
4.c) If the oplist property LET_AS_INIT_WITH is defined, it uses INIT_WITH
|
||||
4.d) Otherwise it uses INIT_SET.
|
||||
*/
|
||||
#define M_TUPL3_INIT_WITH(oplist, dest, ...) \
|
||||
M_TUPL3_INIT_WITH_P1(M_GET_NAME oplist, M_GET_OPLIST oplist, dest, __VA_ARGS__)
|
||||
#define M_TUPL3_INIT_WITH_P1(name, oplist_arglist, dest, ...) \
|
||||
M_IF(M_NOTEQUAL( M_NARGS oplist_arglist, M_NARGS (__VA_ARGS__))) \
|
||||
(M_TUPL3_INIT_WITH_P1_FUNC, M_TUPL3_INIT_WITH_P1_MACRO)(name, oplist_arglist, dest, __VA_ARGS__)
|
||||
#define M_TUPL3_INIT_WITH_P1_FUNC(name, oplist_arglist, dest, ...) \
|
||||
M_C(name, _init_emplace)(dest, __VA_ARGS__)
|
||||
#define M_TUPL3_INIT_WITH_P1_MACRO(name, oplist_arglist, dest, ...) \
|
||||
( M_STATIC_ASSERT( M_NARGS oplist_arglist == M_C3(m_tupl3_, name, _num_args), M_LIB_DIMENSION_ERROR, "The number of oplists given to TUPLE_OPLIST don't match the number of oplists used to create the tuple." ), \
|
||||
M_STATIC_ASSERT( M_NARGS(__VA_ARGS__) == M_C3(m_tupl3_, name, _num_args), M_LIB_DIMENSION_ERROR, "Missing / Too many arguments for tuple"), \
|
||||
M_MAP3(M_TUPL3_INIT_WITH_P2, (name, dest), M_OPFLAT M_MERGE_ARGLIST( oplist_arglist, (__VA_ARGS__) ) ) \
|
||||
(void) 0)
|
||||
#define M_TUPL3_INIT_WITH_P2(name_dest, num, pair) \
|
||||
M_TUPL3_INIT_WITH_P3( M_PAIR_1 name_dest, M_PAIR_2 name_dest, num, M_PAIR_1 pair, M_PAIR_2 pair )
|
||||
#define M_TUPL3_INIT_WITH_P3(name, dest, num, oplist, param) \
|
||||
M_IF(M_TEST_METHOD_P(INIT_WITH, oplist))(M_TUPL3_INIT_WITH_P4, M_TUPL3_INIT_WITH_SET)(name, dest, num, oplist, param)
|
||||
#define M_TUPL3_INIT_WITH_SET(name, dest, num, oplist, param) \
|
||||
M_CALL_INIT_SET (oplist, *M_C4(m_tupl3_, name, _get_at_, num)(dest), param) ,
|
||||
#define M_TUPL3_INIT_WITH_P4(name, dest, num, oplist, param) \
|
||||
M_IF(M_PARENTHESIS_P( param))(M_TUPL3_INIT_WITH_P5, M_TUPL3_INIT_WITH_P6)(name, dest, num, oplist, param)
|
||||
#define M_TUPL3_INIT_WITH_P5(name, dest, num, oplist, param) \
|
||||
M_CALL_INIT_WITH(oplist, *M_C4(m_tupl3_, name, _get_at_, num)(dest), M_REMOVE_PARENTHESIS (param) ) ,
|
||||
#define M_TUPL3_INIT_WITH_P6(name, dest, num, oplist, param) \
|
||||
M_IF(M_GET_PROPERTY(oplist, LET_AS_INIT_WITH))(M_TUPL3_INIT_WITH_P5, M_TUPL3_INIT_WITH_SET)(name, dest, num, oplist, param)
|
||||
|
||||
/* Macros for testing for the presence of a method in the parameter (name, type, oplist) */
|
||||
#define TUPLEI_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(TUPLEI_TEST_METHOD2_P, method, M_OPFLAT trio)
|
||||
#define M_TUPL3_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(M_TUPL3_TEST_METHOD2_P, method, M_OPFLAT trio)
|
||||
|
||||
#define TUPLEI_TEST_METHOD2_P(method, f, t, op) \
|
||||
#define M_TUPL3_TEST_METHOD2_P(method, f, t, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
|
||||
|
||||
/* Macros for testing for the presence of a method in all the params */
|
||||
#define TUPLEI_IF_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(TUPLEI_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
#define M_TUPL3_IF_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(M_TUPL3_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
/* Macros for testing for the presence of a method in at least one params */
|
||||
#define M_TUPL3_IF_ONE(method, ...) \
|
||||
M_IF(M_REDUCE2(M_TUPL3_TEST_METHOD_P, M_OR, method, __VA_ARGS__))
|
||||
|
||||
// deferred evaluation
|
||||
#define TUPLEI_OPLIST_P1(arg) TUPLEI_OPLIST_P2 arg
|
||||
#define M_TUPL3_OPLIST_P1(arg) M_TUPL3_OPLIST_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define TUPLEI_OPLIST_P2(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(TUPLEI_OPLIST_P3, TUPLEI_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
#define M_TUPL3_OPLIST_P2(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(M_TUPL3_OPLIST_P3, M_TUPL3_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define TUPLEI_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_TUPLEI_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
#define M_TUPL3_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_M_TUPL3_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define the TUPLE oplist */
|
||||
#define TUPLEI_OPLIST_P3(name, ...) \
|
||||
#define M_TUPL3_OPLIST_P3(name, ...) \
|
||||
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(M_C(name, _init_emplace)), \
|
||||
INIT_WITH(API_1(M_TUPL3_INIT_WITH)), \
|
||||
SET(M_C(name,_set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
OPLIST( (__VA_ARGS__) ), \
|
||||
M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(M_C(name, _cmp)),), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_C(name, _hash)),), \
|
||||
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_C(name, _equal_p)),), \
|
||||
@@ -668,11 +737,22 @@ namespace m_lib {
|
||||
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_C(name, _init_move)),), \
|
||||
M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \
|
||||
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_C(name, _swap)),), \
|
||||
M_IF_METHOD_ALL(CLEAN, __VA_ARGS__)(CLEAN(M_C(name, _clean)),), \
|
||||
M_IF_METHOD_ALL(RESET, __VA_ARGS__)(RESET(M_C(name, _reset)),), \
|
||||
M_IF_METHOD(NEW, M_RET_ARG1(__VA_ARGS__,))(NEW(M_DELAY2(M_GET_NEW) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
M_IF_METHOD(REALLOC, M_RET_ARG1(__VA_ARGS__,))(REALLOC(M_DELAY2(M_GET_REALLOC) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
M_IF_METHOD(DEL, M_RET_ARG1(__VA_ARGS__,))(DEL(M_DELAY2(M_GET_DEL) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
EMPLACE_TYPE( ( M_REDUCE2(M_TUPL3_OPLIST_SUBTYPE, M_ID, name, M_SEQ(1, M_NARGS(__VA_ARGS__))) ) ) \
|
||||
)
|
||||
|
||||
/* Support for EMPLACE_TYPE in OPLIST. It refers the created internal type alias */
|
||||
#define M_TUPL3_OPLIST_SUBTYPE(name, num) \
|
||||
M_C4(name, _type_, num, _ct)
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define TUPLE_DEF2 M_TUPLE_DEF2
|
||||
#define TUPLE_DEF2_AS M_TUPLE_DEF2_AS
|
||||
#define TUPLE_OPLIST M_TUPLE_OPLIST
|
||||
#define TUPLE_ORDER M_TUPLE_ORDER
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+336
-298
File diff suppressed because it is too large.
Load diff
+172
-154
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* M*LIB / WORKER - Extra worker interface
|
||||
*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "m-buffer.h"
|
||||
#include "m-mutex.h"
|
||||
|
||||
/* Include needed system header for detection of how many core on the system */
|
||||
/* Include needed system header for detection of how many cores are available in the system */
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
@@ -96,8 +96,8 @@
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Definition of a work order */
|
||||
typedef struct work_order_s {
|
||||
struct worker_sync_s *block; // Reference to the shared Synchronization block
|
||||
typedef struct m_work3r_order_s {
|
||||
struct m_worker_sync_s *block; // Reference to the shared Synchronization block
|
||||
void * data; // The work order data
|
||||
void (*func) (void *data); // The work order function (for GCC)
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
@@ -106,52 +106,52 @@ typedef struct work_order_s {
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
std::function<void(void*)> function; // The work order function (for C++)
|
||||
#endif
|
||||
} worker_order_ct;
|
||||
} m_work3r_order_ct;
|
||||
|
||||
/* Define the macros needed to initialize an order.
|
||||
* * MACRO to be used to send an empty order to stop the thread
|
||||
* * MACRO to complete the not-used fields
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK || M_USE_WORKER_CPP_FUNCTION
|
||||
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL, NULL }
|
||||
# define WORKERI_EXTRA_ORDER , NULL
|
||||
# define M_WORK3R_EMPTY_ORDER { NULL, NULL, NULL, NULL }
|
||||
# define M_WORK3R_EXTRA_ORDER , NULL
|
||||
#else
|
||||
# define WORKERI_EMPTY_ORDER { NULL, NULL, NULL }
|
||||
# define WORKERI_EXTRA_ORDER
|
||||
# define M_WORK3R_EMPTY_ORDER { NULL, NULL, NULL }
|
||||
# define M_WORK3R_EXTRA_ORDER
|
||||
#endif
|
||||
|
||||
/* As in C++, it uses std::function, M_POD_OPLIST
|
||||
/* As it is C++, it uses std::function, M_POD_OPLIST
|
||||
is not sufficient for initialization of the structure.
|
||||
So let's use C++ constructor, destructor and copy constructor */
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
# define WORKERI_CPP_INIT(x) (new (&(x)) worker_order_ct())
|
||||
# define WORKERI_CPP_INIT_SET(x, y) (new (&(x)) worker_order_ct(y))
|
||||
# define WORKERI_CPP_SET(x, y) ((x) = (y))
|
||||
# define WORKERI_CPP_CLEAR(x) ((&(x))->~worker_order_ct())
|
||||
# define WORKERI_CPP_INIT_MOVE(x,y) (new (&(x)) worker_order_ct(y), ((&(y))->~worker_order_ct()))
|
||||
# define WORKER_OPLIST \
|
||||
(INIT(WORKERI_CPP_INIT), INIT_SET(WORKERI_CPP_INIT_SET), \
|
||||
SET(WORKERI_CPP_SET), CLEAR(WORKERI_CPP_CLEAR), INIT_MOVE(WORKERI_CPP_INIT_MOVE) )
|
||||
# define M_WORK3R_CPP_INIT(x) (new (&(x)) m_work3r_order_ct())
|
||||
# define M_WORK3R_CPP_INIT_SET(x, y) (new (&(x)) m_work3r_order_ct(y))
|
||||
# define M_WORK3R_CPP_SET(x, y) ((x) = (y))
|
||||
# define M_WORK3R_CPP_CLEAR(x) ((&(x))->~m_work3r_order_ct())
|
||||
# define M_WORK3R_CPP_INIT_MOVE(x,y) (new (&(x)) m_work3r_order_ct(y), ((&(y))->~m_work3r_order_ct()))
|
||||
# define M_WORK3R_OPLIST \
|
||||
(INIT(M_WORK3R_CPP_INIT), INIT_SET(M_WORK3R_CPP_INIT_SET), \
|
||||
SET(M_WORK3R_CPP_SET), CLEAR(M_WORK3R_CPP_CLEAR), INIT_MOVE(M_WORK3R_CPP_INIT_MOVE) )
|
||||
#else
|
||||
# define WORKER_OPLIST M_POD_OPLIST
|
||||
# define M_WORK3R_OPLIST M_POD_OPLIST
|
||||
#endif
|
||||
|
||||
/* Definition of a worker (implemented by a thread) */
|
||||
typedef struct worker_thread_s {
|
||||
/* Definition of the identity of a worker thread */
|
||||
typedef struct m_work3r_thread_s {
|
||||
m_thread_t id;
|
||||
} worker_thread_ct;
|
||||
} m_work3r_thread_ct;
|
||||
|
||||
/* Definition of the queue that will record the work orders */
|
||||
BUFFER_DEF_AS(worker_queue, m_worker_queue_ct, worker_order_ct, 0,
|
||||
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, WORKER_OPLIST)
|
||||
BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0,
|
||||
BUFFER_QUEUE|BUFFER_UNBLOCKING_PUSH|BUFFER_BLOCKING_POP|BUFFER_THREAD_SAFE|BUFFER_DEFERRED_POP, M_WORK3R_OPLIST)
|
||||
|
||||
/* Definition the global pool of workers */
|
||||
typedef struct worker_s {
|
||||
typedef struct m_worker_s {
|
||||
/* The work order queue */
|
||||
m_worker_queue_ct queue_g;
|
||||
m_work3r_queue_t queue_g;
|
||||
|
||||
/* The table of available workers */
|
||||
worker_thread_ct *worker;
|
||||
m_work3r_thread_ct *worker;
|
||||
|
||||
/* Number of workers in the table */
|
||||
unsigned int numWorker_g;
|
||||
@@ -165,18 +165,18 @@ typedef struct worker_s {
|
||||
m_mutex_t lock;
|
||||
m_cond_t a_thread_ends; // EVENT: A worker has ended
|
||||
|
||||
} worker_t[1];
|
||||
} m_worker_t[1];
|
||||
|
||||
/* Definition of the synchronization point for workers */
|
||||
typedef struct worker_sync_s {
|
||||
typedef struct m_worker_sync_s {
|
||||
atomic_int num_spawn; // Number of spawned workers accord this synchronization point
|
||||
atomic_int num_terminated_spawn; // Number of terminated spawned workers
|
||||
struct worker_s *worker; // Reference to the pool of workers
|
||||
} worker_sync_t[1];
|
||||
struct m_worker_s *worker; // Reference to the pool of workers
|
||||
} m_worker_sync_t[1];
|
||||
|
||||
/* Return the number of CPU of the system */
|
||||
/* Return the number of cores available in the system */
|
||||
static inline int
|
||||
workeri_get_cpu_count(void)
|
||||
m_work3r_get_cpu_count(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
SYSTEM_INFO sysinfo;
|
||||
@@ -200,25 +200,25 @@ workeri_get_cpu_count(void)
|
||||
|
||||
// (INTERNAL) Debug support for workers
|
||||
#if 1
|
||||
#define WORKERI_DEBUG(...) (void) 0
|
||||
#define M_WORK3R_DEBUG(...) (void) 0
|
||||
#else
|
||||
#define WORKERI_DEBUG(...) printf(__VA_ARGS__)
|
||||
#define M_WORK3R_DEBUG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Execute the registered work order **synchronously** */
|
||||
static inline void
|
||||
workeri_exec(worker_order_ct *w)
|
||||
m_work3r_exec(m_work3r_order_ct *w)
|
||||
{
|
||||
M_ASSERT (w!= NULL && w->block != NULL);
|
||||
WORKERI_DEBUG ("Starting thread with data %p\n", w->data);
|
||||
M_WORK3R_DEBUG ("Starting thread with data %p\n", w->data);
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
|
||||
M_WORK3R_DEBUG ("Running %s f=%p b=%p\n", (w->func == NULL) ? "Blocks" : "Function", w->func, w->blockFunc);
|
||||
if (w->func == NULL)
|
||||
w->blockFunc(w->data);
|
||||
else
|
||||
#endif
|
||||
#if M_USE_WORKER_CPP_FUNCTION
|
||||
WORKERI_DEBUG ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
|
||||
M_WORK3R_DEBUG ("Running %s f=%p b=%p\n", (w->function == NULL) ? "Lambda" : "Function", w->func, w->blockFunc);
|
||||
if (w->function)
|
||||
w->function(w->data);
|
||||
else
|
||||
@@ -231,28 +231,28 @@ workeri_exec(worker_order_ct *w)
|
||||
|
||||
/* The worker thread main loop*/
|
||||
static inline void
|
||||
workeri_thread(void *arg)
|
||||
m_work3r_thread(void *arg)
|
||||
{
|
||||
// Get back the given argument
|
||||
struct worker_s *g = M_ASSIGN_CAST(struct worker_s *, arg);
|
||||
struct m_worker_s *g = M_ASSIGN_CAST(struct m_worker_s *, arg);
|
||||
while (true) {
|
||||
worker_order_ct w;
|
||||
m_work3r_order_ct w;
|
||||
// If needed, reset the global state of the worker
|
||||
if (g->resetFunc_g != NULL) {
|
||||
g->resetFunc_g();
|
||||
}
|
||||
// Waiting for data
|
||||
WORKERI_DEBUG ("Waiting for data (queue: %lu / %lu)\n", worker_queue_size(g->queue_g), worker_queue_capacity(g->queue_g));
|
||||
worker_queue_pop(&w, g->queue_g);
|
||||
M_WORK3R_DEBUG ("Waiting for data (queue: %lu / %lu)\n", m_work3r_queue_size(g->queue_g), m_work3r_queue_capacity(g->queue_g));
|
||||
m_work3r_queue_pop(&w, g->queue_g);
|
||||
// We received a work order
|
||||
// Note: that the work order is still present in the queue
|
||||
// preventing further work order to be pushed in the queue until it finishes doing the work
|
||||
// If a stop request is received, terminate the thread
|
||||
if (w.block == NULL) break;
|
||||
// Execute the work order
|
||||
workeri_exec(&w);
|
||||
m_work3r_exec(&w);
|
||||
// Consumme fully the work order in the queue
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
m_work3r_queue_pop_release(g->queue_g);
|
||||
// Signal that a worker has finished.
|
||||
m_mutex_lock(g->lock);
|
||||
m_cond_broadcast(g->a_thread_ends);
|
||||
@@ -272,23 +272,23 @@ workeri_thread(void *arg)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (or NULL if none)
|
||||
*/
|
||||
static inline void
|
||||
worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
{
|
||||
M_ASSERT (numWorker >= -1);
|
||||
// Auto compute number of workers if the argument is 0
|
||||
if (numWorker <= 0)
|
||||
numWorker = (1 + (numWorker == -1))*workeri_get_cpu_count()-1;
|
||||
WORKERI_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
|
||||
numWorker = (1 + (numWorker == -1))*m_work3r_get_cpu_count()-1;
|
||||
M_WORK3R_DEBUG ("Starting queue with: %d\n", numWorker + extraQueue);
|
||||
// Initialization
|
||||
// numWorker can still be 0 if it is a single core cpu (no worker available)
|
||||
M_ASSERT(numWorker >= 0);
|
||||
size_t numWorker_st = (size_t) numWorker;
|
||||
g->worker = M_MEMORY_REALLOC(worker_thread_ct, NULL, numWorker_st);
|
||||
g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, numWorker_st);
|
||||
if (g->worker == NULL) {
|
||||
M_MEMORY_FULL(sizeof (worker_thread_ct) * numWorker_st);
|
||||
M_MEMORY_FULL(sizeof (m_work3r_thread_ct) * numWorker_st);
|
||||
return;
|
||||
}
|
||||
worker_queue_init(g->queue_g, numWorker_st + extraQueue);
|
||||
m_work3r_queue_init(g->queue_g, numWorker_st + extraQueue);
|
||||
g->numWorker_g = (unsigned int) numWorker_st;
|
||||
g->resetFunc_g = resetFunc;
|
||||
g->clearFunc_g = clearFunc;
|
||||
@@ -297,30 +297,31 @@ worker_init(worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc
|
||||
|
||||
// Create & start the workers
|
||||
for(size_t i = 0; i < numWorker_st; i++) {
|
||||
m_thread_create(g->worker[i].id, workeri_thread, M_ASSIGN_CAST(void*, g));
|
||||
m_thread_create(g->worker[i].id, m_work3r_thread, M_ASSIGN_CAST(void*, g));
|
||||
}
|
||||
}
|
||||
/* Initialization of the worker module (constructor)
|
||||
Provide default values for the arguments.
|
||||
Input:
|
||||
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
|
||||
@extraQueue: number of extra work order we can get if all workers are full
|
||||
@resetFunc: function to reset the state of a worker between work orders (optional)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (optional)
|
||||
*/
|
||||
#define worker_init(...) worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
#define m_worker_init(...) m_worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
|
||||
/* Clear of the worker module (destructor) */
|
||||
static inline void
|
||||
worker_clear(worker_t g)
|
||||
m_worker_clear(m_worker_t g)
|
||||
{
|
||||
M_ASSERT (worker_queue_empty_p (g->queue_g));
|
||||
M_ASSERT (m_work3r_queue_empty_p (g->queue_g));
|
||||
// Push the terminate order on the queue
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
worker_order_ct w = WORKERI_EMPTY_ORDER;
|
||||
m_work3r_order_ct w = M_WORK3R_EMPTY_ORDER;
|
||||
// Normaly all worker threads shall be waiting at this
|
||||
// stage, so all push won't block as the queue is empty.
|
||||
// But for robustness, let's wait.
|
||||
worker_queue_push_blocking (g->queue_g, w, true);
|
||||
m_work3r_queue_push_blocking (g->queue_g, w, true);
|
||||
}
|
||||
// Wait for thread terminanison
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
@@ -330,13 +331,13 @@ worker_clear(worker_t g)
|
||||
M_MEMORY_FREE(g->worker);
|
||||
m_mutex_clear(g->lock);
|
||||
m_cond_clear(g->a_thread_ends);
|
||||
worker_queue_clear(g->queue_g);
|
||||
m_work3r_queue_clear(g->queue_g);
|
||||
}
|
||||
|
||||
/* Start a new collaboration between workers of pool 'g'
|
||||
by defining the synchronization point 'block' */
|
||||
static inline void
|
||||
worker_start(worker_sync_t block, worker_t g)
|
||||
m_worker_start(m_worker_sync_t block, m_worker_t g)
|
||||
{
|
||||
atomic_init (&block->num_spawn, 0);
|
||||
atomic_init (&block->num_terminated_spawn, 0);
|
||||
@@ -349,16 +350,16 @@ worker_start(worker_sync_t block, worker_t g)
|
||||
The work order if composed of the function 'func' and its 'data'
|
||||
*/
|
||||
static inline void
|
||||
worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
m_worker_spawn(m_worker_sync_t block, void (*func)(void *data), void *data)
|
||||
{
|
||||
const worker_order_ct w = { block, data, func WORKERI_EXTRA_ORDER };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
WORKERI_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
const m_work3r_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER };
|
||||
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
|
||||
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
|
||||
M_WORK3R_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
atomic_fetch_add (&block->num_spawn, 1);
|
||||
return;
|
||||
}
|
||||
WORKERI_DEBUG ("Running data ourself: %p\n", data);
|
||||
M_WORK3R_DEBUG ("Running data ourself: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
(*func) (data);
|
||||
}
|
||||
@@ -367,16 +368,16 @@ worker_spawn(worker_sync_t block, void (*func)(void *data), void *data)
|
||||
/* Spawn or not the given work order to workers,
|
||||
or do it ourself if no worker is available */
|
||||
static inline void
|
||||
worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
m_work3r_spawn_block(m_worker_sync_t block, void (^func)(void *data), void *data)
|
||||
{
|
||||
const worker_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
const m_work3r_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
|
||||
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
|
||||
M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
atomic_fetch_add (&block->num_spawn, 1);
|
||||
return;
|
||||
}
|
||||
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
M_WORK3R_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
func (data);
|
||||
}
|
||||
@@ -386,16 +387,16 @@ worker_spawn_block(worker_sync_t block, void (^func)(void *data), void *data)
|
||||
/* Spawn or not the given work order to workers,
|
||||
or do it ourself if no worker is available */
|
||||
static inline void
|
||||
worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func, void *data)
|
||||
m_work3r_spawn_function(m_worker_sync_t block, std::function<void(void *data)> func, void *data)
|
||||
{
|
||||
const worker_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!worker_queue_full_p(block->worker->queue_g))
|
||||
&& worker_queue_push (block->worker->queue_g, w) == true) {
|
||||
WORKERI_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
const m_work3r_order_ct w = { block, data, NULL, func };
|
||||
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
|
||||
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
|
||||
M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
|
||||
atomic_fetch_add (&block->num_spawn, 1);
|
||||
return;
|
||||
}
|
||||
WORKERI_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
M_WORK3R_DEBUG ("Running data ourself as block: %p\n", data);
|
||||
/* No worker available. Call the function ourself */
|
||||
func (data);
|
||||
}
|
||||
@@ -403,7 +404,7 @@ worker_spawn_function(worker_sync_t block, std::function<void(void *data)> func,
|
||||
|
||||
/* Test if all work orders of the given synchronization point are finished */
|
||||
static inline bool
|
||||
worker_sync_p(worker_sync_t block)
|
||||
m_worker_sync_p(m_worker_sync_t block)
|
||||
{
|
||||
/* If the number of spawns is greated than the number
|
||||
of terminated spawns, some spawns are still working.
|
||||
@@ -413,14 +414,14 @@ worker_sync_p(worker_sync_t block)
|
||||
|
||||
/* Wait for all work orders of the given synchronization point to be finished */
|
||||
static inline void
|
||||
worker_sync(worker_sync_t block)
|
||||
m_worker_sync(m_worker_sync_t block)
|
||||
{
|
||||
WORKERI_DEBUG ("Waiting for thread terminasion.\n");
|
||||
M_WORK3R_DEBUG ("Waiting for thread terminasion.\n");
|
||||
// Fast case: all workers have finished
|
||||
if (worker_sync_p(block)) return;
|
||||
if (m_worker_sync_p(block)) return;
|
||||
// Slow case: perform a locked wait to put this thread to waiting state
|
||||
m_mutex_lock(block->worker->lock);
|
||||
while (!worker_sync_p(block)) {
|
||||
while (!m_worker_sync_p(block)) {
|
||||
m_cond_wait(block->worker->a_thread_ends, block->worker->lock);
|
||||
}
|
||||
m_mutex_unlock(block->worker->lock);
|
||||
@@ -428,19 +429,19 @@ worker_sync(worker_sync_t block)
|
||||
|
||||
/* Flush any work order in the queue ourself if some remains.*/
|
||||
static inline void
|
||||
worker_flush(worker_t g)
|
||||
m_worker_flush(m_worker_t g)
|
||||
{
|
||||
worker_order_ct w;
|
||||
while (worker_queue_pop_blocking (&w, g->queue_g, false) == true) {
|
||||
workeri_exec(&w);
|
||||
worker_queue_pop_release(g->queue_g);
|
||||
m_work3r_order_ct w;
|
||||
while (m_work3r_queue_pop_blocking (&w, g->queue_g, false) == true) {
|
||||
m_work3r_exec(&w);
|
||||
m_work3r_queue_pop_release(g->queue_g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return the number of workers */
|
||||
static inline size_t
|
||||
worker_count(worker_t g)
|
||||
m_worker_count(m_worker_t g)
|
||||
{
|
||||
return g->numWorker_g + 1;
|
||||
}
|
||||
@@ -454,78 +455,78 @@ worker_count(worker_t g)
|
||||
TODO: Support oplist for input & outputs parameters
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
worker_spawn_block ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
M_WORK3R_DEF_DATA(_input, _output) \
|
||||
M_WORK3R_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
m_work3r_spawn_block ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
|
||||
#elif M_USE_WORKER_CPP_FUNCTION
|
||||
// TODO: Explicit pass all arguments by reference.
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
worker_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
|
||||
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
m_work3r_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
|
||||
#else
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
worker_spawn ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
#define M_WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
M_WORK3R_DEF_DATA(_input, _output) \
|
||||
M_WORK3R_DEF_SUBFUNC(_input, _output, _core) \
|
||||
m_worker_spawn ((_block), M_WORK3R_SPAWN_SUBFUNC_NAME, &M_WORK3R_SPAWN_DATA_NAME)
|
||||
#endif
|
||||
|
||||
#define WORKER_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
|
||||
#define WORKER_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
|
||||
#define WORKER_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
|
||||
#define WORKER_DEF_DATA(_input, _output) \
|
||||
struct WORKER_SPAWN_STRUCT_NAME { \
|
||||
WORKER_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
|
||||
} WORKER_SPAWN_DATA_NAME = { \
|
||||
WORKER_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
|
||||
#define M_WORK3R_SPAWN_STRUCT_NAME M_C(m_work3r_data_s_, __LINE__)
|
||||
#define M_WORK3R_SPAWN_DATA_NAME M_C(m_work3r_data_, __LINE__)
|
||||
#define M_WORK3R_SPAWN_SUBFUNC_NAME M_C(m_work3r_subfunc_, __LINE__)
|
||||
#define M_WORK3R_DEF_DATA(_input, _output) \
|
||||
struct M_WORK3R_SPAWN_STRUCT_NAME { \
|
||||
M_WORK3R_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_DEF_DATA_OUTPUT _output) \
|
||||
} M_WORK3R_SPAWN_DATA_NAME = { \
|
||||
M_WORK3R_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, M_WORK3R_INIT_DATA_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SINGLE_INPUT(var) __typeof__(var) var;
|
||||
#define WORKER_DEF_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SINGLE_OUTPUT(var) \
|
||||
#define M_WORK3R_DEF_SINGLE_INPUT(var) __typeof__(var) var;
|
||||
#define M_WORK3R_DEF_DATA_INPUT(...) \
|
||||
M_MAP(M_WORK3R_DEF_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_DEF_SINGLE_OUTPUT(var) \
|
||||
__typeof__(var) *M_C(var, _ptr);
|
||||
#define WORKER_DEF_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_INPUT(var) \
|
||||
#define M_WORK3R_DEF_DATA_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_DEF_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_INIT_SINGLE_INPUT(var) \
|
||||
.var = var,
|
||||
#define WORKER_INIT_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_OUTPUT(var) \
|
||||
#define M_WORK3R_INIT_DATA_INPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_INIT_SINGLE_OUTPUT(var) \
|
||||
.M_C(var, _ptr) = &var,
|
||||
#define WORKER_INIT_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
#define M_WORK3R_INIT_DATA_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void M_WORK3R_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void M_WORK3R_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
struct M_WORK3R_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
M_WORK3R_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
#define M_WORK3R_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^M_WORK3R_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
struct M_WORK3R_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
M_WORK3R_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
M_IF_EMPTY _output ( , M_WORK3R_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
#define M_WORK3R_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
__typeof__(var) var = _s_data->var;
|
||||
#define WORKER_INIT_LOCAL_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
#define M_WORK3R_INIT_LOCAL_INPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_LOCAL_INPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
__typeof__(var) var;
|
||||
#define WORKER_INIT_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
#define M_WORK3R_INIT_LOCAL_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
*(_s_data->M_C(var, _ptr)) = var;
|
||||
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define M_WORK3R_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
M_MAP(M_WORK3R_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
@@ -533,22 +534,39 @@ M_END_PROTECTED_CODE
|
||||
|
||||
/* Define empty types and empty functions to not use any worker */
|
||||
|
||||
typedef struct worker_block_s {
|
||||
typedef struct m_worker_block_s {
|
||||
int x;
|
||||
} worker_sync_t[1];
|
||||
} m_worker_sync_t[1];
|
||||
|
||||
typedef struct worker_s {
|
||||
typedef struct m_worker_s {
|
||||
int x;
|
||||
} worker_t[1];
|
||||
} m_worker_t[1];
|
||||
|
||||
#define worker_init(g, numWorker, extraQueue, resetFunc) do { (void) g; } while (0)
|
||||
#define worker_clear(g) do { (void) g; } while (0)
|
||||
#define worker_start(b, w) do { (void) b; } while (0)
|
||||
#define worker_spawn(b, f, d) do { f(d); } while (0)
|
||||
#define worker_sync(b) do { (void) b; } while (0)
|
||||
#define worker_count(w) 1
|
||||
#define WORKER_SPAWN(b, i, c, o) do { c } while (0)
|
||||
#define m_worker_init(g, numWorker, extraQueue, resetFunc) do { (void) g; } while (0)
|
||||
#define m_worker_clear(g) do { (void) g; } while (0)
|
||||
#define m_worker_start(b, w) do { (void) b; } while (0)
|
||||
#define m_worker_spawn(b, f, d) do { f(d); } while (0)
|
||||
#define m_worker_sync_p(b) true
|
||||
#define m_worker_sync(b) do { (void) b; } while (0)
|
||||
#define m_worker_count(w) 1
|
||||
#define m_worker_flush(w) do { (void) w; } while (0)
|
||||
#define M_WORKER_SPAWN(b, i, c, o) do { c } while (0)
|
||||
|
||||
#endif /* M_USE_WORKER */
|
||||
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define worker_t m_worker_t
|
||||
#define worker_sync_t m_worker_sync_t
|
||||
#define worker_init m_worker_init
|
||||
#define worker_clear m_worker_clear
|
||||
#define worker_start m_worker_start
|
||||
#define worker_spawn m_worker_spawn
|
||||
#define worker_sync_p m_worker_sync_p
|
||||
#define worker_sync m_worker_sync
|
||||
#define worker_count m_worker_count
|
||||
#define worker_flush m_worker_flush
|
||||
#define WORKER_SPAWN M_WORKER_SPAWN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
REM Copyright (c) 2017-2021, Patrick Pelissier
|
||||
REM Copyright (c) 2017-2022, Patrick Pelissier
|
||||
REM All rights reserved.
|
||||
REM
|
||||
REM Redistribution and use in source and binary forms, with or without
|
||||
@@ -22,7 +22,7 @@ REM SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
REM Execute the test suite for Microsoft Visual Studio
|
||||
REM
|
||||
REM Load Micosoft Visual Studio environement file.
|
||||
REM Load Micosoft Visual Studio environement file (2019 or 2022)
|
||||
IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
@@ -30,6 +30,13 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxi
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
|
||||
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
)
|
||||
|
||||
REM Add clang-cl in the PATH. It is the default install of clang for MSVC:
|
||||
REM %VCINSTALLDIR%\Tools\Llvm\bin;%VCINSTALLDIR%\Tools\Llvm\x64\bin
|
||||
REM Adding x64 version
|
||||
|
||||
+62
-13
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017-2021, Patrick Pelissier
|
||||
# Copyright (c) 2017-2022, Patrick Pelissier
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -21,6 +21,7 @@
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
CC=cc -std=c99
|
||||
CXX=c++ -std=c++11
|
||||
WCFLAGS_GCC=-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 -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -Wdate-time -Wconversion -Wformat=2 -Winit-self -Wjump-misses-init -Wstack-protector -Wtrampolines -Wwrite-strings -Wformat-security -Wno-float-conversion -O
|
||||
WCFLAGS_CLANG=-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 -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -O
|
||||
WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wunused-function -ftrapv -Wsign-conversion
|
||||
@@ -44,14 +45,20 @@ all:
|
||||
.POSIX:
|
||||
.PHONY: scan-build sanitize check clean *.log coverage synthesis
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .exe .log .depend .gcov
|
||||
.SUFFIXES: .c .exe .log .depend .gcov .analyzer .cpp .fuzz
|
||||
.SECONDARY:
|
||||
|
||||
.c.exe:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -g $(LDFLAGS) $< -o $@
|
||||
|
||||
.cpp.exe:
|
||||
$(CXX) $(WCFLAGS_CPP) -Wno-sign-conversion -Wno-inline $(XCFLAGS) $(CPPFLAGS) -g $(LDFLAGS) $< -o $@
|
||||
|
||||
.c.depend:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -MM -MT `echo $< |$(SED) 's/\.c/\.exe/g'` $< > $@
|
||||
$(CC) $(CPPFLAGS) -MM -MT `echo $< |$(SED) 's/\.c/\.exe/g'` $< > $@
|
||||
|
||||
.cpp.depend:
|
||||
$(CXX) $(CPPFLAGS) -MM -MT `echo $< |$(SED) 's/\.cpp/\.exe/g'` $< > $@
|
||||
|
||||
.exe.log:
|
||||
$(LOG_COMPILER) ./$<
|
||||
@@ -61,27 +68,35 @@ all:
|
||||
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
|
||||
$(CC) $(CPPFLAGS) -E -DNDEBUG -DWITHIN_COVERAGE $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -p -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
|
||||
cat $<.first.c $<.middle.c $<.end.c > $<.c
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -g $<.c -o $<.exe
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) -ftest-coverage -fprofile-arcs -O -g $<.c -o $<.exe
|
||||
$(LOG_COMPILER) ./$<.exe
|
||||
LANG=C gcov $<.gcno > `basename $< .c`.synt
|
||||
cat `basename $< .c`.synt
|
||||
mv $<.c.gcov `basename $< .c`.gcov
|
||||
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
|
||||
|
||||
.cpp.fuzz:
|
||||
afl-g++ $(WCFLAGS_CPP) $(CPPFLAGS) -Wno-sign-conversion -Wno-inline -Wno-conversion -O2 -fsanitize=address,undefined,leak -m32 $< -o $@.exe
|
||||
mkdir -p fuzzer-testsuite
|
||||
for i in $$(seq 1 1000) ; do printf "%d " $$RANDOM ; done > fuzzer-testsuite/t1
|
||||
afl-fuzz -i fuzzer-testsuite/ -o fuzzer-findings -m 800 ./$@.exe -1
|
||||
|
||||
-include depend
|
||||
|
||||
depend:
|
||||
$(RM) depend
|
||||
echo "" > depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.depend/g'`
|
||||
$(CXX) --version 2> /dev/null && $(MAKE) `ls check-*.cpp|$(SED) 's/\.cpp/\.depend/g'` || echo "Skip C++ tests"
|
||||
cat *.depend > depend
|
||||
$(RM) *.depend
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Clean
|
||||
# Main target
|
||||
#####################################################################################################
|
||||
|
||||
# This target generates all executable to be tested by CodeQL
|
||||
exe: depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.exe/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
|
||||
@echo All executable generated
|
||||
@@ -90,10 +105,15 @@ check: depend
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'` CC="$(CC)" CFLAGS="$(CFLAGS)"
|
||||
@echo All tests passed
|
||||
|
||||
check-stl: depend
|
||||
$(MAKE) `ls check-*.cpp|$(SED) 's/\.cpp/\.log/g'` CXX="$(CXX)" XCFLAGS="-O2 -fsanitize=address,undefined,leak"
|
||||
@echo All comparison against C++ STL passed
|
||||
|
||||
clean:
|
||||
$(RM) *.exe *.s *~ *.o *.log a*.dat
|
||||
$(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c
|
||||
$(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c *.analyzer
|
||||
$(RMDIR) coverage coverage-dir mlib-report
|
||||
$(RMDIR) fuzzer-testsuite fuzzer-findings
|
||||
|
||||
distclean: clean
|
||||
$(RM) *.depend depend
|
||||
@@ -144,13 +164,17 @@ gene-queue:
|
||||
gene-string:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S tgen-mstring.c && less tgen-mstring.s
|
||||
|
||||
gene-serial:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -O3 -march=native -DNDEBUG -S -std=c11 tgen-mserial.c && less tgen-mserial.s
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Coverage
|
||||
#####################################################################################################
|
||||
|
||||
coverage:
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.gcov/g'`
|
||||
$(MAKE) synthesis
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.gcov/g'` CC="cc -std=c11"
|
||||
$(MAKE) synthesis.synt check-synthesis
|
||||
|
||||
SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
|
||||
M-ARRAY test-marray.c.c test-marray.synt \
|
||||
@@ -175,11 +199,12 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
|
||||
M-SHARED test-mshared.c.c test-mshared.synt \
|
||||
M-SNAPSHOT test-msnapshot.c.c test-msnapshot.synt \
|
||||
M-STRING ../m-string.h test-mstring.synt \
|
||||
M-TREE test-mtree.c.c test-mtree.synt \
|
||||
M-TUPLE test-mtuple.c.c test-mtuple.synt \
|
||||
M-VARIANT test-mvariant.c.c test-mvariant.synt \
|
||||
M-WORKER ../m-worker.h test-mworker.synt
|
||||
|
||||
synthesis:
|
||||
synthesis.synt:
|
||||
@printf "+-------------------------------+-------------------------------+\n"
|
||||
@for i in $(SYNTHESIS_DATA) ; do \
|
||||
if test "$$j" = "" ; then j=$$i ; continue ; fi; \
|
||||
@@ -187,25 +212,49 @@ synthesis:
|
||||
printf "|\t%16.16s\t|\t%16.16s\t|\n" "$$j" "`grep -v Creating $$i|grep $$k -F -A1 |tail -1|cut -f2 -d':'`"; \
|
||||
j=""; \
|
||||
k=""; \
|
||||
done
|
||||
done > synthesis.synt
|
||||
@cat synthesis.synt
|
||||
@printf "+-------------------------------+-------------------------------+\n"
|
||||
|
||||
# Compare the computed coverage against the reference coverage (synthesis.ref), allowing only increase of coverage
|
||||
check-synthesis: synthesis.synt
|
||||
@paste synthesis.ref synthesis.synt |awk '($$2 != $$9) {err=1} { n1=$$4*$$6/100 ; n2=$$11*$$13/100; if (n1 > n2) { printf "ERROR for %s: new coverage (%d) is lower than reference (%d)\n",$$2,n2,n1 ; err=2 } } END {exit err}'
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Code analyzer tools
|
||||
#####################################################################################################
|
||||
|
||||
# Static analysis of the code using clang scan-build
|
||||
scan-build: clean
|
||||
$(RM) -rf ./mlib-report
|
||||
scan-build -o ./mlib-report $(MAKE) exe XCFLAGS="-std=c99"
|
||||
|
||||
# Relaunch the test suite with the sanitizer.
|
||||
sanitize:
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=address,undefined,leak"
|
||||
$(MAKE) clean check XCFLAGS="-fsanitize=thread -pie -fPIE"
|
||||
$(MAKE) clean
|
||||
$(MAKE) check XCFLAGS="-fsanitize=address,undefined,leak"
|
||||
$(MAKE) clean
|
||||
$(MAKE) check XCFLAGS="-fsanitize=thread -pie -fPIE"
|
||||
|
||||
|
||||
# Static analysis of the code using GCC "-fanalyzer" option
|
||||
# Need GCC >= 10
|
||||
# Preprocess the file before given it to the analyser (just like coverage) to have better report.
|
||||
.c.analyzer:
|
||||
awk '/START_COVERAGE/ { printit=1} (printit == 0) { print }' $< > $<.first.c
|
||||
awk ' printit { print } /END_COVERAGE/ { printit=1}' $< > $<.end.c
|
||||
$(CC) $(CPPFLAGS) -E -DNDEBUG -DWITHIN_COVERAGE $< |grep -v '^#' |awk ' /END_COVERAGE/ { printit=0} printit { print } /START_COVERAGE/ { printit=1 }' |perl -p -e "s/;(?![\"'])/;\n/g ; s/}(?![\"'])/}\n/g ; s/{(?![\"'])/{\n/g" > $<.middle.c
|
||||
cat $<.first.c $<.middle.c $<.end.c > $<.c
|
||||
$(CC) $(CPPFLAGS) $(LDFLAGS) -fanalyzer -Wall -W -O2 -g $<.c -o $<.exe 2> `basename $< .c`.analyzer
|
||||
$(RM) $<.first.c $<.end.c $<.middle.c $<.c $<.exe
|
||||
|
||||
analyze:
|
||||
$(MAKE) `ls test-*.c|$(SED) 's/\.c/\.analyzer/g'`
|
||||
|
||||
|
||||
#####################################################################################################
|
||||
# Test All
|
||||
# Test with the maximum representative number of compiler and flags.
|
||||
#####################################################################################################
|
||||
|
||||
checkall:
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <vector>
|
||||
#include "m-array.h"
|
||||
|
||||
ARRAY_DEF(array_int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL ARRAY_OPLIST(array_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::vector<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(array_int_t a, std::vector<int> b)
|
||||
{
|
||||
size_t s = array_int_size(a);
|
||||
assert (s == b.size());
|
||||
for(size_t i = 0; i < s; i++) {
|
||||
int *b0 = array_int_get(a, i);
|
||||
int &b1 = b.at(i);
|
||||
assert(*b0 == b1);
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
#define HAVE_RESERVE
|
||||
#define HAVE_RESIZE
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <map>
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(tree_int, 5, int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL BPTREE_OPLIST2(tree_int, M_OPL_int(), M_OPL_int() )
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::map<int,int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
#define CLASS_IT_TO_INT(it) (it)->second
|
||||
#define TYPE_IT_TO_INT(it) (it)->value
|
||||
|
||||
void cmp_cont(const tree_int_t a, const std::map<int,int> &b)
|
||||
{
|
||||
tree_int_it_t ita;
|
||||
tree_int_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!tree_int_end_p(ita));
|
||||
const int *k0 = tree_int_cref(ita)->key_ptr;
|
||||
const int &k1 = itb->first;
|
||||
assert(*k0 == k1);
|
||||
const int *v0 = tree_int_cref(ita)->value_ptr;
|
||||
const int &v1 = itb->second;
|
||||
assert(*v0 == v1);
|
||||
itb++;
|
||||
tree_int_next(ita);
|
||||
}
|
||||
assert(tree_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
#define HAVE_GET_KEY_THROUGH_FIND
|
||||
#define HAVE_SET_KEY
|
||||
#define HAVE_KEY_PTR
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <set>
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF(tree_int, 5, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL BPTREE_OPLIST(tree_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::set<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(const tree_int_t a, const std::set<int> &b)
|
||||
{
|
||||
tree_int_it_t ita;
|
||||
tree_int_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!tree_int_end_p(ita));
|
||||
const int *b0 = tree_int_cref(ita);
|
||||
const int &b1 = *itb;
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
tree_int_next(ita);
|
||||
}
|
||||
assert(tree_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <deque>
|
||||
#include "m-deque.h"
|
||||
|
||||
DEQUE_DEF(deque_float, float)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL DEQUE_OPLIST(deque_float, M_OPL_float())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS float
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::deque<float>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(deque_float_t a, std::deque<float> b)
|
||||
{
|
||||
deque_float_it_t ita;
|
||||
deque_float_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!deque_float_end_p(ita));
|
||||
const float *b0 = deque_float_cref(ita);
|
||||
float &b1 = *itb;
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
deque_float_next(ita);
|
||||
}
|
||||
assert(deque_float_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
#define HAVE_PUSH_FRONT
|
||||
#define HAVE_POP_FRONT
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <list>
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DUAL_PUSH_DEF(list_int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::list<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(const list_int_t a, const std::list<int> &b)
|
||||
{
|
||||
list_int_it_t ita;
|
||||
list_int_it(ita, a);
|
||||
auto itb = b.rbegin();
|
||||
while (itb != b.rend()) {
|
||||
assert(!list_int_end_p(ita));
|
||||
const int *b0 = list_int_cref(ita);
|
||||
const int &b1 = *itb;
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
list_int_next(ita);
|
||||
}
|
||||
assert(list_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 100000
|
||||
|
||||
#define HAVE_PUSH_FRONT
|
||||
#define HAVE_REVERSE_IT
|
||||
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,626 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
/* This test will perform random generic operations on the
|
||||
M*LIB container and compares it to the same operation on the
|
||||
C++ equivalent container.
|
||||
If there are some differences, it reports an error.
|
||||
It is therefore quite generic and based on the properties of the container
|
||||
*/
|
||||
|
||||
/* Get the types from the container oplist if needed */
|
||||
#ifndef CONT_TYPE
|
||||
# define CONT_TYPE_(CONT_OPL) M_GET_TYPE CONT_OPL
|
||||
# define CONT_TYPE CONT_TYPE_(CONT_OPL)
|
||||
#endif
|
||||
|
||||
// Type used for M*LIB container. Default is the same as C++
|
||||
#ifndef BASE_TYPE
|
||||
# define BASE_TYPE BASE_CLASS
|
||||
#endif
|
||||
|
||||
// Compare the M*LIB base object to the C++ base object
|
||||
#ifndef CMP_BASE
|
||||
# define CMP_BASE(a, b) assert( (a) == (b) )
|
||||
#endif
|
||||
|
||||
/* Get the affectation if needed to transform an integer into C++ class (resp. M*LIB type) */
|
||||
#ifndef CLASS_SET_INT
|
||||
# define CLASS_SET_INT(a, i) (a) = (i)
|
||||
#endif
|
||||
#ifndef TYPE_SET_INT
|
||||
# define TYPE_SET_INT(a, i) (a) = (i)
|
||||
#endif
|
||||
|
||||
/* Get the affectation if needed to transform a C++ iterator (resp. M*LIB) to an int */
|
||||
#ifndef CLASS_IT_TO_INT
|
||||
# define CLASS_IT_TO_INT(it) *(it)
|
||||
#endif
|
||||
#ifndef TYPE_IT_TO_INT
|
||||
# define TYPE_IT_TO_INT(it) *(it)
|
||||
#endif
|
||||
|
||||
/* Global properties of the container */
|
||||
// Use find to perform GET_KEY for C++
|
||||
//#define HAVE_GET_KEY_THROUGH_FIND
|
||||
// Container are nor ordered
|
||||
//#define DONT_HAVE_SEQUENCE_IT
|
||||
// associative array container
|
||||
//#define HAVE_SET_KEY
|
||||
// Container is in reverse
|
||||
//#define HAVE_REVERSE_IT
|
||||
// Have PUSH_FRONT operator
|
||||
//#define HAVE_PUSH_FRONT
|
||||
// Have POP_FRONT operator
|
||||
//#define HAVE_POP_FRONT
|
||||
|
||||
/*********************************************************************************/
|
||||
|
||||
// Define the container name, extracting it from its oplist
|
||||
#define CONT_NAME_(CONT_OPL) M_GET_NAME CONT_OPL
|
||||
#define CONT_NAME CONT_NAME_(CONT_OPL)
|
||||
|
||||
// Define the maximum number of tests
|
||||
#define MAX_TEST 28
|
||||
|
||||
#ifdef HAVE_REVERSE_IT
|
||||
// Scan the C++ sequence in reverse
|
||||
# define begin rbegin
|
||||
# define end rend
|
||||
# define IT(x) std::prev(x.base(), 1)
|
||||
#else
|
||||
# define IT(x) x
|
||||
#endif
|
||||
|
||||
volatile int test_case;
|
||||
|
||||
void test(int select_test, int index,
|
||||
BASE_TYPE &b0, BASE_CLASS &b1, CONT_TYPE &c0, CONT_CLASS &c1)
|
||||
{
|
||||
bool p0 = false, p1 = false;
|
||||
size_t s0 = 0, s1 = 0;
|
||||
CONT_TYPE tmp;
|
||||
#if M_TEST_METHOD_P(IT_TYPE, CONT_OPL)
|
||||
M_ID(M_GET_IT_TYPE CONT_OPL) it0;
|
||||
auto it1 = c1.begin();
|
||||
#endif
|
||||
|
||||
// Save in a volatile variable the last test for debug purpose
|
||||
test_case = select_test % MAX_TEST;
|
||||
#ifdef DEBUG
|
||||
printf("Case=%d\n", test_case);
|
||||
#endif
|
||||
switch (test_case) {
|
||||
#if M_TEST_METHOD_P(PUSH, CONT_OPL)
|
||||
case 0:
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
M_CALL_PUSH(CONT_OPL, c0, b0);
|
||||
c1.push_back(b1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
index = index % 1000;
|
||||
for(int i = 0; i < index; i++) {
|
||||
TYPE_SET_INT(b0, i);
|
||||
CLASS_SET_INT(b1, i);
|
||||
M_CALL_PUSH(CONT_OPL, c0, b0);
|
||||
c1.push_back(b1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(POP, CONT_OPL)
|
||||
case 2:
|
||||
if (!c1.empty()) {
|
||||
M_CALL_POP(CONT_OPL, &b0, c0);
|
||||
b1 = c1.back();
|
||||
c1.pop_back();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(EMPTY_P, CONT_OPL)
|
||||
case 3:
|
||||
p0 = M_CALL_EMPTY_P(CONT_OPL, c0);
|
||||
p1 = c1.empty();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SIZE, CONT_OPL)
|
||||
case 4:
|
||||
s0 = M_CALL_SIZE(CONT_OPL, c0);
|
||||
s1 = c1.size();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(RESET, CONT_OPL)
|
||||
case 5:
|
||||
M_CALL_RESET(CONT_OPL, c0);
|
||||
c1.clear();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(GET_KEY, CONT_OPL)
|
||||
case 6:
|
||||
if (!c1.empty()) {
|
||||
#ifndef HAVE_GET_KEY_THROUGH_FIND
|
||||
// GET_KEY takes an index which shall be within the range of the container
|
||||
index = index % c1.size();
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_GET_KEY(CONT_OPL, c0, index));
|
||||
b1 = c1[index];
|
||||
#else
|
||||
// GET_KEY takes a key
|
||||
index = index % (DEFAULT_NUMBER/4);
|
||||
BASE_TYPE *p = M_CALL_GET_KEY(CONT_OPL, c0, index);
|
||||
if (p!= NULL) {
|
||||
// Key found
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *p);
|
||||
auto i = c1.find(index);
|
||||
assert(i != c1.end());
|
||||
b1 = CLASS_IT_TO_INT(i);
|
||||
} else {
|
||||
// Key not found
|
||||
auto i = c1.find(index);
|
||||
assert(i == c1.end());
|
||||
TYPE_SET_INT(b0, 0);
|
||||
CLASS_SET_INT(b1, 0);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
assert( M_CALL_EMPTY_P(CONT_OPL, c0) == true);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SET_KEY, CONT_OPL)
|
||||
case 7:
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
#ifndef HAVE_SET_KEY
|
||||
if (!c1.empty())
|
||||
{
|
||||
index = index % c1.size();
|
||||
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
|
||||
c1[index] = b1;
|
||||
}
|
||||
#else
|
||||
index = index % (DEFAULT_NUMBER/4);
|
||||
M_CALL_SET_KEY(CONT_OPL, c0, index, b0);
|
||||
c1[index] = b1;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 21:
|
||||
{
|
||||
unsigned n = index % 1000;
|
||||
unsigned offset = (index / 1027) % 1000;
|
||||
#ifndef HAVE_SET_KEY
|
||||
// If it is a sequence container, check it it fits, otherwise resize
|
||||
// without resize which may not be available, but push is assumed to be.
|
||||
if ((size_t) n+offset > c1.size() ) {
|
||||
TYPE_SET_INT(b0, 0);
|
||||
CLASS_SET_INT(b1, 0);
|
||||
for(unsigned i = c1.size() ; i < (size_t) n+offset; i++) {
|
||||
M_CALL_PUSH(CONT_OPL, c0, b0);
|
||||
c1.push_back(b1);
|
||||
}
|
||||
assert(c1.size() == (size_t) n+offset);
|
||||
}
|
||||
#endif
|
||||
for(unsigned i = 0; i < n; i++) {
|
||||
TYPE_SET_INT(b0, 3*i);
|
||||
CLASS_SET_INT(b1, 3*i);
|
||||
M_CALL_SET_KEY(CONT_OPL, c0, offset + i, b0);
|
||||
c1[offset + i] = b1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(ERASE_KEY, CONT_OPL)
|
||||
case 8:
|
||||
if (!c1.empty()) {
|
||||
index = index % c1.size();
|
||||
p0 = M_CALL_ERASE_KEY(CONT_OPL, c0, index);
|
||||
#ifndef HAVE_GET_KEY_THROUGH_FIND
|
||||
c1.erase(c1.begin() + index);
|
||||
p1 = true;
|
||||
#else
|
||||
auto i = c1.find(index);
|
||||
if (i != c1.end()) {
|
||||
c1.erase(i);
|
||||
p1 = true;
|
||||
} else {
|
||||
p1 = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SET, CONT_OPL) && M_TEST_METHOD_P(INIT_SET, CONT_OPL)
|
||||
case 9:
|
||||
M_CALL_INIT_SET(CONT_OPL, tmp, c0);
|
||||
#if M_TEST_METHOD_P(EQUAL_P, CONT_OPL)
|
||||
assert( M_CALL_EQUAL_P(CONT_OPL, tmp, c0) );
|
||||
#endif
|
||||
M_CALL_SET(CONT_OPL, c0, tmp);
|
||||
M_CALL_CLEAR(CONT_OPL, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(INIT_MOVE, CONT_OPL)
|
||||
case 10:
|
||||
M_CALL_INIT_MOVE(CONT_OPL, tmp, c0);
|
||||
M_CALL_INIT_MOVE(CONT_OPL, c0, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(MOVE, CONT_OPL) && M_TEST_METHOD_P(INIT_MOVE, CONT_OPL)
|
||||
case 11:
|
||||
M_CALL_INIT_SET(CONT_OPL, tmp, c0);
|
||||
M_CALL_MOVE(CONT_OPL, tmp, c0);
|
||||
M_CALL_INIT_MOVE(CONT_OPL, c0, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SWAP, CONT_OPL) && M_TEST_METHOD_P(GET_SIZE, CONT_OPL)
|
||||
case 12:
|
||||
s0 = M_CALL_GET_SIZE(CONT_OPL, c0);
|
||||
M_CALL_INIT(CONT_OPL, tmp);
|
||||
M_CALL_SWAP(CONT_OPL, tmp, c0);
|
||||
s1 = M_CALL_GET_SIZE(CONT_OPL, tmp);
|
||||
M_CALL_SWAP(CONT_OPL, tmp, c0);
|
||||
M_CALL_CLEAR(CONT_OPL, tmp);
|
||||
break;
|
||||
case 13:
|
||||
M_CALL_INIT_SET(CONT_OPL, tmp, c0);
|
||||
M_CALL_SWAP(CONT_OPL, tmp, c0);
|
||||
M_CALL_CLEAR(CONT_OPL, tmp);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(SAFE_GET_KEY, CONT_OPL)
|
||||
case 14:
|
||||
index = (1 + (c1.size() < 1000000)) * (index % ( c1.size() + 1) );
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_SAFE_GET_KEY(CONT_OPL, c0, index));
|
||||
#ifndef HAVE_GET_KEY_THROUGH_FIND
|
||||
if ((size_t) index >= c1.size() ) {
|
||||
c1.resize(index+1);
|
||||
}
|
||||
b1 = c1[index];
|
||||
#else
|
||||
{
|
||||
auto i = c1.find(index);
|
||||
if (i == c1.end()) {
|
||||
#ifdef HAVE_SET_KEY
|
||||
c1[index] = 0;
|
||||
#else
|
||||
c1.insert(index);
|
||||
#endif
|
||||
i = c1.find(index);
|
||||
assert(i != c1.end());
|
||||
}
|
||||
b1 = CLASS_IT_TO_INT(i);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_CREF, CONT_OPL)
|
||||
case 15:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
while (!M_CALL_IT_END_P(CONT_OPL, it0)) {
|
||||
#ifdef HAVE_KEY_PTR
|
||||
// Containers are key / value (through ptr)
|
||||
index = *M_CALL_IT_CREF(CONT_OPL, it0)->key_ptr;
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0)->value_ptr);
|
||||
#elif defined(HAVE_SET_KEY)
|
||||
// Containers are key / value
|
||||
index = M_CALL_IT_CREF(CONT_OPL, it0)->key;
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, M_CALL_IT_CREF(CONT_OPL, it0)->value);
|
||||
#else
|
||||
// Containers are single key
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0));
|
||||
index = b0;
|
||||
#endif
|
||||
#ifndef DONT_HAVE_SEQUENCE_IT
|
||||
// Container are ordered
|
||||
assert(it1 != c1.end());
|
||||
b1 = CLASS_IT_TO_INT(it1);
|
||||
it1++;
|
||||
#else
|
||||
// Containers are not ordered.
|
||||
it1 = c1.find(index);
|
||||
assert(it1 != c1.end());
|
||||
b1 = CLASS_IT_TO_INT(it1);
|
||||
#endif
|
||||
CMP_BASE(b0, b1);
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
}
|
||||
#ifndef DONT_HAVE_SEQUENCE_IT
|
||||
assert(it1 == c1.end());
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_REF, CONT_OPL)
|
||||
case 16:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
while (it1 != c1.end()) {
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, TYPE_IT_TO_INT(M_CALL_IT_REF(CONT_OPL, it0)), b0);
|
||||
*it1 = b1;
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
index = 1457857U * index + 458741U;
|
||||
}
|
||||
assert(M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_LAST, CONT_OPL)
|
||||
case 17:
|
||||
{
|
||||
M_CALL_IT_LAST(CONT_OPL, it0, c0);
|
||||
auto it1b = c1.rbegin();
|
||||
while (it1b != c1.rend()) {
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, TYPE_IT_TO_INT(M_CALL_IT_CREF(CONT_OPL, it0)));
|
||||
b1 = CLASS_IT_TO_INT(it1b);
|
||||
CMP_BASE(b0, b1);
|
||||
M_CALL_IT_PREVIOUS(CONT_OPL, it0);
|
||||
it1b++;
|
||||
}
|
||||
assert(M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_INSERT, CONT_OPL)
|
||||
case 18:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
#ifdef HAVE_INSERT_AFTER
|
||||
while (it1 != c1.end() ) {
|
||||
if (rand() > index)
|
||||
break;
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
}
|
||||
if (it1 != c1.end() ) {
|
||||
M_CALL_IT_INSERT(CONT_OPL, c0, it0, b0);
|
||||
c1.insert_after(it1, b1);
|
||||
}
|
||||
#else
|
||||
if (!c1.empty() ){
|
||||
index = index % c1.size();
|
||||
if (index == 0) {
|
||||
M_CALL_IT_END(CONT_OPL, it0, c0);
|
||||
} else {
|
||||
for(int i = 0; i < index; i++) {
|
||||
assert( it1 != c1.end());
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
}
|
||||
it1++;
|
||||
}
|
||||
}
|
||||
M_CALL_IT_INSERT(CONT_OPL, c0, it0, b0);
|
||||
#ifdef HAVE_REVERSE_IT
|
||||
// in cases of reverse iterator, fix iterator.
|
||||
it1 = std::prev(it1, 1);
|
||||
#endif
|
||||
c1.insert(IT(it1), b1);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(IT_REMOVE, CONT_OPL)
|
||||
case 19:
|
||||
M_CALL_IT_FIRST(CONT_OPL, it0, c0);
|
||||
it1 = c1.begin();
|
||||
#ifdef HAVE_ERASE_AFTER
|
||||
while (it1 != c1.end() ) {
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
if (rand() > index)
|
||||
break;
|
||||
it1++;
|
||||
}
|
||||
if (it1 != c1.end() && !M_CALL_IT_END_P(CONT_OPL, it0) ) {
|
||||
M_CALL_IT_REMOVE(CONT_OPL, c0, it0);
|
||||
c1.erase_after(it1);
|
||||
}
|
||||
#else
|
||||
if (!c1.empty() ){
|
||||
index = index % c1.size();
|
||||
for(int i = 0; i < index; i++) {
|
||||
assert( it1 != c1.end());
|
||||
assert( !M_CALL_IT_END_P(CONT_OPL, it0));
|
||||
M_CALL_IT_NEXT(CONT_OPL, it0);
|
||||
it1++;
|
||||
}
|
||||
M_CALL_IT_REMOVE(CONT_OPL, c0, it0);
|
||||
c1.erase(IT(it1));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if M_TEST_METHOD_P(REVERSE, CONT_OPL)
|
||||
case 20:
|
||||
M_CALL_REVERSE(CONT_OPL, c0);
|
||||
c1.reverse();
|
||||
break;
|
||||
// 21 is above
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PUSH_FRONT
|
||||
case 22:
|
||||
TYPE_SET_INT(b0, index);
|
||||
CLASS_SET_INT(b1, index);
|
||||
M_C(CONT_NAME, _push_front)(c0, b0);
|
||||
c1.push_front(b1);
|
||||
break;
|
||||
|
||||
case 23:
|
||||
index = index % 1000;
|
||||
for(int i = 0; i < index; i++) {
|
||||
TYPE_SET_INT(b0, i);
|
||||
CLASS_SET_INT(b1, i);
|
||||
M_C(CONT_NAME, _push_front)(c0, b0);
|
||||
c1.push_front(b1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POP_FRONT
|
||||
case 24:
|
||||
if (!c1.empty()) {
|
||||
M_C(CONT_NAME, _pop_front)(&b0, c0);
|
||||
b1 = c1.front();
|
||||
c1.pop_front();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RESIZE
|
||||
case 25:
|
||||
index = (1 + (c1.size() < 1000000)) * (index % ( c1.size() + 1) );
|
||||
M_C(CONT_NAME, _resize)(c0, index);
|
||||
c1.resize(index);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RESERVE
|
||||
case 26:
|
||||
index = c1.size() + ( index % (c1.size() + 1) );
|
||||
M_C(CONT_NAME, _reserve)(c0, index);
|
||||
c1.reserve(index);
|
||||
break;
|
||||
|
||||
case 27:
|
||||
M_C(CONT_NAME, _reserve)(c0, 0);
|
||||
c1.shrink_to_fit();
|
||||
break;
|
||||
#endif
|
||||
|
||||
// SPLICE_BACK
|
||||
// SPLICE_AT
|
||||
// Needs SPLICE ?
|
||||
|
||||
default:
|
||||
M_STATIC_ASSERT( 28 == MAX_TEST, MLIB_INTERNAL_ERROR, "Constant MAX_TEST is no coherent with the effective number of tests");
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
CMP_BASE(b0, b1);
|
||||
CMP_CONT(c0, c1);
|
||||
assert(p0 == p1);
|
||||
assert(s0 == s1);
|
||||
}
|
||||
|
||||
static void init_rand(void)
|
||||
{
|
||||
const char *seed = getenv("CHECK_RANDOMIZE");
|
||||
if (seed == NULL) {
|
||||
// No check randomize requested.
|
||||
// Initialize with a common value
|
||||
srand(0x45856525U);
|
||||
} else {
|
||||
unsigned int seed_value = strtoul (seed, NULL, 10);
|
||||
if (seed_value > 1) {
|
||||
// Seed has been set by the user. Use it.
|
||||
printf("Using seed = %u\n", seed_value);
|
||||
} else {
|
||||
time_t tv;
|
||||
time (&tv);
|
||||
seed_value = tv;
|
||||
printf("Generating seed = %u\n", seed_value);
|
||||
}
|
||||
srand(seed_value);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_int(FILE *f)
|
||||
{
|
||||
int c = 0;
|
||||
while (true) {
|
||||
int n = fscanf(f, " %d", &c);
|
||||
if (n == 1) {
|
||||
return c;
|
||||
}
|
||||
if (feof(f)) {
|
||||
return 0;
|
||||
}
|
||||
// Skip next character
|
||||
c = fgetc(f);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int loop = argc >= 2 ? atoi(argv[1]) : DEFAULT_NUMBER;
|
||||
|
||||
BASE_TYPE b0;
|
||||
BASE_CLASS b1;
|
||||
CONT_TYPE c0;
|
||||
CONT_CLASS c1;
|
||||
|
||||
init_rand();
|
||||
M_CALL_INIT(CONT_OPL, c0);
|
||||
M_CALL_INIT(M_GET_OPLIST CONT_OPL, b0);
|
||||
TYPE_SET_INT(b0, 0);
|
||||
CLASS_SET_INT(b1, 0);
|
||||
|
||||
if (loop < 0) {
|
||||
/* test input is provided from stdin */
|
||||
while (!feof(stdin)) {
|
||||
int t = read_int(stdin);
|
||||
int s = read_int(stdin);
|
||||
test(t, s, b0, b1, c0, c1);
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < loop; i++) {
|
||||
int t = rand();
|
||||
int s = rand();
|
||||
test(t, s, b0, b1, c0, c1);
|
||||
}
|
||||
}
|
||||
|
||||
M_CALL_CLEAR(M_GET_OPLIST CONT_OPL, b0);
|
||||
M_CALL_CLEAR(CONT_OPL, c0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <forward_list>
|
||||
#include "m-list.h"
|
||||
|
||||
LIST_DEF(list_int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::forward_list<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(list_int_t a, std::forward_list<int> b)
|
||||
{
|
||||
list_int_it_t ita;
|
||||
list_int_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!list_int_end_p(ita));
|
||||
const int *b0 = list_int_cref(ita);
|
||||
int &b1 = *itb;
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
list_int_next(ita);
|
||||
}
|
||||
assert(list_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define HAVE_INSERT_AFTER
|
||||
#define HAVE_ERASE_AFTER
|
||||
#define DEFAULT_NUMBER 100000
|
||||
|
||||
// C++ forward_list pushs in front instead of in back
|
||||
#define push_back push_front
|
||||
#define pop_back pop_front
|
||||
#define back front
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <queue>
|
||||
#include "m-prioqueue.h"
|
||||
|
||||
// Invert the order of priority for the integers to match the C++ one
|
||||
#define CMP_REVERT(a,b) ((a) > (b) ? -1 : (a) < (b))
|
||||
PRIOQUEUE_DEF(prio_int, int, M_OPEXTEND(M_BASIC_OPLIST, CMP(CMP_REVERT) ))
|
||||
|
||||
// Container OPLIST (disable iterators & reset)
|
||||
#define CONT_OPL \
|
||||
M_OPEXTEND( PRIOQUEUE_OPLIST(prio_int, M_OPL_int()), \
|
||||
RESET(0), \
|
||||
IT_TYPE(0), \
|
||||
IT_FIRST(0), \
|
||||
IT_END(0), \
|
||||
IT_SET(0), \
|
||||
IT_END_P(0), \
|
||||
IT_EQUAL_P(0), \
|
||||
IT_LAST_P(0), \
|
||||
IT_NEXT(0), \
|
||||
IT_CREF(0) )
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::priority_queue<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(const prio_int_t a, const std::priority_queue<int> &b)
|
||||
{
|
||||
std::priority_queue<int> cb = b;
|
||||
prio_int_t ca;
|
||||
prio_int_init_set(ca, a);
|
||||
while (!cb.empty()) {
|
||||
int n;
|
||||
prio_int_pop(&n, ca);
|
||||
assert(n == cb.top());
|
||||
cb.pop();
|
||||
}
|
||||
assert(prio_int_empty_p(ca));
|
||||
prio_int_clear(ca);
|
||||
}
|
||||
|
||||
// There is no reset, so the prioqueue keeps increasing ==> Limit the number of operation.
|
||||
#define DEFAULT_NUMBER 1500
|
||||
|
||||
#define push_back push
|
||||
#define pop_back pop
|
||||
#define back top
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <set>
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(tree_int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL RBTREE_OPLIST(tree_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::set<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(const tree_int_t a, const std::set<int> &b)
|
||||
{
|
||||
tree_int_it_t ita;
|
||||
tree_int_it(ita, a);
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
assert(!tree_int_end_p(ita));
|
||||
const int *b0 = tree_int_cref(ita);
|
||||
const int &b1 = *itb;
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
tree_int_next(ita);
|
||||
}
|
||||
assert(tree_int_end_p(ita));
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <unordered_map>
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict_int, int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL DICT_OPLIST(dict_int, M_OPL_int(), M_OPL_int() )
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::unordered_map<int,int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
// Get the value from the iterator
|
||||
#define CLASS_IT_TO_INT(it) (it)->second
|
||||
#define TYPE_IT_TO_INT(it) (it)->value
|
||||
|
||||
void cmp_cont(const dict_int_t a, const std::unordered_map<int,int> &b)
|
||||
{
|
||||
size_t n = 0;
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
const int *b0 = dict_int_get(a, itb->first);
|
||||
assert(b0 != nullptr);
|
||||
assert(*b0 == itb->second);
|
||||
itb++;
|
||||
n++;
|
||||
}
|
||||
assert(dict_int_size(a) == n);
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
// Use find to perform GET_KEY for C++
|
||||
#define HAVE_GET_KEY_THROUGH_FIND
|
||||
// Container are nor ordered
|
||||
#define DONT_HAVE_SEQUENCE_IT
|
||||
// associative array container
|
||||
#define HAVE_SET_KEY
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, Patrick Pelissier
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* + Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* + Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <unordered_set>
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_SET_DEF(dict_int, int)
|
||||
|
||||
// Container OPLIST
|
||||
#define CONT_OPL DICT_SET_OPLIST(dict_int, M_OPL_int())
|
||||
|
||||
// C++ Base class of the item in the container
|
||||
#define BASE_CLASS int
|
||||
|
||||
// C++ Container class
|
||||
#define CONT_CLASS std::unordered_set<int>
|
||||
|
||||
// Compare the M*LIB container a to the C++ container b
|
||||
#define CMP_CONT(a, b) cmp_cont(a, b)
|
||||
|
||||
void cmp_cont(const dict_int_t a, const std::unordered_set<int> &b)
|
||||
{
|
||||
size_t n = 0;
|
||||
auto itb = b.begin();
|
||||
while (itb != b.end()) {
|
||||
const int &b1 = *itb;
|
||||
const int *b0 = dict_int_get(a, b1);
|
||||
assert(b0 != nullptr);
|
||||
assert(*b0 == b1);
|
||||
itb++;
|
||||
n++;
|
||||
}
|
||||
assert(dict_int_size(a) == n);
|
||||
}
|
||||
|
||||
#define DEFAULT_NUMBER 1000000
|
||||
|
||||
#define HAVE_GET_KEY_THROUGH_FIND
|
||||
#define DONT_HAVE_SEQUENCE_IT
|
||||
|
||||
#define push_back insert
|
||||
#include "check-generic.hpp"
|
||||
+50
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -44,35 +44,66 @@
|
||||
/* For coverage build, do not expand the
|
||||
typical macros assert, NULL, etc. */
|
||||
#undef assert
|
||||
#undef M_ASSERT
|
||||
#undef M_ASSERT_SLOW
|
||||
#undef M_ASSERT_INIT
|
||||
#undef M_ASSERT_INDEX
|
||||
#undef M_STATIC_FAILURE
|
||||
#undef M_STATIC_ASSERT
|
||||
#undef M_ASSUME
|
||||
#undef NULL
|
||||
#undef M_LIKELY
|
||||
#undef M_UNLIKELY
|
||||
#undef M_MEMORY_FULL
|
||||
#undef M_SWAP
|
||||
#undef STRINGI_CONTRACT
|
||||
#undef ARRAYI_CONTRACT
|
||||
#undef LIST_CONTRACT
|
||||
#undef DICTI_CONTRACT
|
||||
#undef DICTI_OA_CONTRACT
|
||||
#undef SHAREDI_CONTRACT
|
||||
#undef SHAREDI_RESSOURCE_CONTRACT
|
||||
#undef BUFFERI_CONTRACT
|
||||
#undef BUFFERI_PROTECTED_CONTRACT
|
||||
#undef ILISTI_CONTRACT
|
||||
#undef DEQUEI_CONTRACT
|
||||
#undef QUEUEI_MPMC_CONTRACT
|
||||
#undef RBTREEI_CONTRACT_NODE
|
||||
#undef RBTREEI_CONTRACT
|
||||
#undef BPTREEI_NODE_CONTRACT
|
||||
#undef BPTREEI_CONTRACT
|
||||
#undef LISTI_CONTRACT
|
||||
#undef LISTI_DUAL_PUSH_CONTRACT
|
||||
#undef M_ARRA4_CONTRACT
|
||||
#undef M_B1TSET_CONTRACT
|
||||
#undef M_BPTR33_NODE_CONTRACT
|
||||
#undef M_BPTR33_NODE_CONTRACT
|
||||
#undef M_BPTR33_CONTRACT
|
||||
#undef M_BUFF3R_CONTRACT
|
||||
#undef M_BUFF3R_PROTECTED_CONTRACT
|
||||
#undef M_QU3UE_MPMC_CONTRACT
|
||||
#undef M_QU3UE_MPMC_CONTRACT
|
||||
#undef M_QU3UE_SPSC_CONTRACT
|
||||
#undef M_QU3UE_SPSC_CONTRACT
|
||||
#undef M_C0NCURRENT_CONTRACT
|
||||
#undef M_D3QU3_CONTRACT
|
||||
#undef M_D1CT_CONTRACT
|
||||
#undef M_D1CT_OA_CONTRACT
|
||||
#undef M_GEN1NT_CONTRACT
|
||||
#undef M_IL1ST_CONTRACT
|
||||
#undef M_IL1ST_NODE_CONTRACT
|
||||
#undef M_L1ST_CONTRACT
|
||||
#undef M_L1ST_DUAL_PUSH_CONTRACT
|
||||
#undef M_M3MPOOL_CONTRACT
|
||||
#undef M_RBTR33_CONTRACT
|
||||
#undef M_RBTR33_CONTRACT_NODE
|
||||
#undef M_SHAR3D_CONTRACT
|
||||
#undef M_SHAR3D_RESOURCE_CONTRACT
|
||||
#undef M_SNAPSH0T_SPSC_FLAGS_CONTRACT
|
||||
#undef M_SNAPSH0T_SPSC_CONTRACT
|
||||
#undef M_SNAPSH0T_SPMC_INT_CONTRACT
|
||||
#undef M_SNAPSH0T_SPMC_CONTRACT
|
||||
#undef M_STR1NG_CONTRACT
|
||||
#undef M_BOUNDED_STR1NG_CONTRACT
|
||||
#undef M_TUPL3_CONTRACT
|
||||
#undef M_VAR1ANT_CONTRACT
|
||||
#undef NDEBUG
|
||||
#undef atomic_init
|
||||
#undef atomic_load
|
||||
#undef atomic_store
|
||||
#undef atomic_compare_exchange_weak
|
||||
#undef atomic_compare_exchange_strong
|
||||
#undef atomic_fetch_add
|
||||
#undef atomic_fetch_sub
|
||||
#undef M_CONST_CAST
|
||||
#undef M_ASSIGN_CAST
|
||||
#undef M_CHECK_DEFAULT_TYPE
|
||||
#undef M_CHECK_SAME
|
||||
#undef M_TR33_NODE_CONTRACT
|
||||
#undef M_TR33_CONTRACT
|
||||
#undef M_TR33_IT_CONTRACT
|
||||
#else
|
||||
/* For normal builds, empty macros which does nothing */
|
||||
#define START_COVERAGE
|
||||
|
||||
+18
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -64,14 +64,14 @@ BPTREE_DEF(bptree2, 5, bptree_t, BPTREE_OPLIST(bptree, DEFAULT_OPLIST))
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 6
|
||||
|
||||
#include "m-bptree.h"
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_DEFAULT_OPLIST, DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_BASIC_OPLIST, DEFAULT_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 7
|
||||
|
||||
@@ -86,7 +86,7 @@ BUFFER_DEF(buffer2, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer, DEFAULT_OPL
|
||||
#include "m-concurrent.h"
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_DEFAULT_OPLIST))
|
||||
CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_BASIC_OPLIST))
|
||||
ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 9
|
||||
@@ -94,14 +94,14 @@ ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAUL
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
DICT_DEF2(dict2, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 10
|
||||
|
||||
#include "m-dict.h"
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, M_DEFAULT_OPLIST, DEFAULT_OPLIST) )
|
||||
DICT_DEF2(dict2, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict, M_BASIC_OPLIST, DEFAULT_OPLIST) )
|
||||
|
||||
#elif TEST == 11
|
||||
|
||||
@@ -140,64 +140,64 @@ CONCURRENT_DEF(array, tmpstr_t, ISHARED_PTR_OPLIST(tmpstr, X()))
|
||||
#include "m-prioqueue.h"
|
||||
|
||||
PRIOQUEUE_DEF(prioqueue, int)
|
||||
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_DEFAULT_OPLIST()))
|
||||
PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_BASIC_OPLIST()))
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
#include "m-rbtree.h"
|
||||
|
||||
RBTREE_DEF(rbtree, int)
|
||||
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_DEFAULT_OPLIST2))
|
||||
RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_BASIC_OPLIST2))
|
||||
|
||||
#elif TEST == 16
|
||||
|
||||
#include "m-shared.h"
|
||||
|
||||
SHARED_PTR_DEF(shared, int)
|
||||
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_DEFAULT_OPLISTop))
|
||||
SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_BASIC_OPLISTop))
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
#include "m-snapshot.h"
|
||||
|
||||
SNAPSHOT_SPSC_DEF(shared, int)
|
||||
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_DEFAULT_OPLIST x))
|
||||
SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_BASIC_OPLIST x))
|
||||
|
||||
#elif TEST == 18
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, DEFAULT_OPLIST, M_BASIC_OPLIST)))
|
||||
|
||||
#elif TEST == 19
|
||||
|
||||
#include "m-tuple.h"
|
||||
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST() )))
|
||||
TUPLE_DEF2(struct2, (a, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST() )))
|
||||
|
||||
#elif TEST == 20
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_DEFAULT_OPLIST)))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, DEFAULT_OPLIST, M_BASIC_OPLIST)))
|
||||
|
||||
#elif TEST == 21
|
||||
|
||||
#include "m-variant.h"
|
||||
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, DEFAULT_OPLIST)))
|
||||
VARIANT_DEF2(struct2, (a, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, DEFAULT_OPLIST)))
|
||||
|
||||
#elif TEST == 22
|
||||
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_DEFAULT_OPLIST, DEFAULT_OPLIST)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_BASIC_OPLIST), (b, int, M_BASIC_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, M_BASIC_OPLIST, DEFAULT_OPLIST)
|
||||
|
||||
int f(void) {
|
||||
int r;
|
||||
@@ -211,8 +211,8 @@ int f(void) {
|
||||
#include "m-funcobj.h"
|
||||
|
||||
FUNC_OBJ_ITF_DEF(itf, int, int)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_DEFAULT_OPLIST), (b, int, M_DEFAULT_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_DEFAULT_OPLIST)
|
||||
FUNC_OBJ_INS_DEF(ins, itf, (x), { return x * self->a + self->b; }, (a, int, M_BASIC_OPLIST), (b, int, M_BASIC_OPLIST))
|
||||
#define M_OPL_ins_t() FUNC_OBJ_INS_OPLIST(ins, DEFAULT_OPLIST, M_BASIC_OPLIST)
|
||||
|
||||
int f(void) {
|
||||
int r;
|
||||
|
||||
+26
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2021, Patrick Pelissier
|
||||
* Copyright (c) 2017-2022, 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:
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 2
|
||||
|
||||
@@ -48,7 +48,7 @@ ARRAY_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
|
||||
LIST_DEF(list, int)
|
||||
LIST_DEF(list2, int)
|
||||
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
|
||||
LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 3
|
||||
|
||||
@@ -56,7 +56,7 @@ LIST_DEF(list3, list_t, LIST_OPLIST(list2, M_DEFAULT_OPLIST))
|
||||
|
||||
DEQUE_DEF(deque, int)
|
||||
DEQUE_DEF(deque2, int)
|
||||
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
|
||||
DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 4
|
||||
|
||||
@@ -64,7 +64,7 @@ DEQUE_DEF(deque3, deque_t, DEQUE_OPLIST(deque2, M_DEFAULT_OPLIST))
|
||||
|
||||
BPTREE_DEF(bptree, 4, int)
|
||||
BPTREE_DEF(bptree2, 4, int)
|
||||
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
|
||||
BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 5
|
||||
|
||||
@@ -72,7 +72,7 @@ BPTREE_DEF(bptree3, 5, bptree_t, BPTREE_OPLIST(bptree2, M_DEFAULT_OPLIST))
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 4, int, int)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_BASIC_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 6
|
||||
|
||||
@@ -80,7 +80,7 @@ BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DE
|
||||
|
||||
BPTREE_DEF2(bptree, 4, int, int)
|
||||
BPTREE_DEF2(bptree2, 4, int, int)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST)
|
||||
BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_BASIC_OPLIST, M_BASIC_OPLIST), int, M_BASIC_OPLIST)
|
||||
|
||||
#elif TEST == 7
|
||||
|
||||
@@ -88,7 +88,7 @@ BPTREE_DEF2(bptree3, 5, bptree_t, BPTREE_OPLIST2(bptree2, M_DEFAULT_OPLIST, M_DE
|
||||
|
||||
BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE)
|
||||
BUFFER_DEF(buffer2, int, 4, BUFFER_THREAD_UNSAFE)
|
||||
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_OPLIST))
|
||||
BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 8
|
||||
|
||||
@@ -97,7 +97,7 @@ BUFFER_DEF(buffer3, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer2, M_DEFAULT_
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 9
|
||||
|
||||
@@ -105,7 +105,7 @@ CONCURRENT_DEF(array3, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST))
|
||||
|
||||
DICT_DEF2(dict, int, int)
|
||||
DICT_DEF2(dict2, int, int)
|
||||
DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
DICT_DEF2(dict3, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict2, M_BASIC_OPLIST, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 10
|
||||
|
||||
@@ -113,7 +113,7 @@ DICT_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPL
|
||||
|
||||
DICT_STOREHASH_DEF2(dict, int, int)
|
||||
DICT_STOREHASH_DEF2(dict2, int, int)
|
||||
DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) )
|
||||
DICT_STOREHASH_DEF2(dict3, int, M_BASIC_OPLIST, dict_t, DICT_OPLIST(dict2, M_BASIC_OPLIST, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 11
|
||||
|
||||
@@ -122,7 +122,7 @@ DICT_STOREHASH_DEF2(dict3, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict2, M_D
|
||||
|
||||
ARRAY_DEF(array, int)
|
||||
ARRAY_DEF(array2, int)
|
||||
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_DEFAULT_OPLIST) )
|
||||
DICT_SET_DEF(dict, array_t, ARRAY_OPLIST(array2, M_BASIC_OPLIST) )
|
||||
|
||||
#elif TEST == 12
|
||||
|
||||
@@ -152,7 +152,7 @@ ISHARED_PTR_DEF(tmpstr, tmp_str_t, (TYPE(struct toto), CLEAR(M_NOTHING_DEFAULT))
|
||||
|
||||
PRIOQUEUE_DEF(prioqueue, int)
|
||||
PRIOQUEUE_DEF(prioqueue2, int)
|
||||
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OPLIST ))
|
||||
PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_BASIC_OPLIST ))
|
||||
|
||||
#elif TEST == 15
|
||||
|
||||
@@ -160,7 +160,7 @@ PRIOQUEUE_DEF(prioqueue3, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue2, M_DEFAULT_OP
|
||||
|
||||
RBTREE_DEF(rbtree, int)
|
||||
RBTREE_DEF(rbtree2, int)
|
||||
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
|
||||
RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 16
|
||||
|
||||
@@ -168,7 +168,7 @@ RBTREE_DEF(rbtree3, rbtree_t, RBTREE_OPLIST(rbtree2, M_DEFAULT_OPLIST))
|
||||
|
||||
SHARED_PTR_DEF(shared, int)
|
||||
SHARED_PTR_DEF(shared2, int)
|
||||
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 17
|
||||
|
||||
@@ -176,7 +176,7 @@ SHARED_PTR_DEF(shared3, shared_t, SHARED_PTR_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
SNAPSHOT_SPSC_DEF(shared, int)
|
||||
SNAPSHOT_SPSC_DEF(shared2, int)
|
||||
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 18
|
||||
|
||||
@@ -184,7 +184,7 @@ SNAPSHOT_SPSC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
SNAPSHOT_SPMC_DEF(shared, int)
|
||||
SNAPSHOT_SPMC_DEF(shared2, int)
|
||||
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 19
|
||||
|
||||
@@ -192,7 +192,7 @@ SNAPSHOT_SPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
|
||||
SNAPSHOT_MPMC_DEF(shared, int)
|
||||
SNAPSHOT_MPMC_DEF(shared2, int)
|
||||
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_BASIC_OPLIST))
|
||||
|
||||
#elif TEST == 20
|
||||
|
||||
@@ -201,8 +201,8 @@ SNAPSHOT_MPMC_DEF(shared3, shared_t, SNAPSHOT_OPLIST(shared2, M_DEFAULT_OPLIST))
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(aggregate2, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2,
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 21
|
||||
@@ -212,8 +212,8 @@ TUPLE_DEF2(struct2,
|
||||
TUPLE_DEF2(aggregate, (x, int), (z, float))
|
||||
TUPLE_DEF2(aggregate2, (x, int), (z, float))
|
||||
TUPLE_DEF2(struct2,
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, TUPLE_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, TUPLE_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 22
|
||||
@@ -223,8 +223,8 @@ TUPLE_DEF2(struct2,
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(aggregate2, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2,
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 23
|
||||
@@ -234,8 +234,8 @@ VARIANT_DEF2(struct2,
|
||||
VARIANT_DEF2(aggregate, (x, int), (z, float))
|
||||
VARIANT_DEF2(aggregate2, (x, int), (z, float))
|
||||
VARIANT_DEF2(struct2,
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST))
|
||||
(a, aggregate_t, VARIANT_OPLIST(aggregate2, M_BASIC_OPLIST, M_BASIC_OPLIST)),
|
||||
(b, aggregate_t, VARIANT_OPLIST(aggregate, M_BASIC_OPLIST, M_BASIC_OPLIST))
|
||||
)
|
||||
|
||||
#elif TEST == 24
|
||||
|
||||
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user